CMake 入門/Out-of-source Build

CMake 如何決定目錄 編輯

CMake 的參數格式如下

cmake [選項] <source tree 根目錄>
cmake [選項] <binary tree 根目錄>

在 CMake 命令列最後一項所指定的路徑將被視為 source tree 根目錄,當其他選項缺省時此目錄為必要參數。若命令列沒有給定路徑 CMake 才會將目前工作資料夾當成 source tree 根目錄。 source tree 根目錄必須含有 CMakeLists.txt ,否則會發生錯誤。

另外,當命令列指定的路徑下含有 CMakeCache.txt 時(通常是前次建置時遺留下的),該路徑也會被當成 binary tree 根目錄,否則 CMake 一律會把目前工作資料夾當成 binary tree 根目錄。

取得路徑資訊 編輯

CMake 提供了幾個變數讓使用者在撰寫 CMakeLists 時取得路徑資訊,這裡先介紹其中幾個:

CMAKE_SOURCE_DIR
內容為 source tree 根目錄的完整路徑,也就是 CMake 開始建置過程的進入點。
CMAKE_BINARY_DIR
內容為 binary tree 根目錄的完整路徑,在 in-source build 的時候值與 CMAKE_SOURCE_DIR 相同。
PROJECT_SOURCE_DIR
目前所屬專案的原始碼根目錄,即內含 project() 指令的 CMakeLists 所在資料夾。前面的例子沒有階層之分,所以 PROJECT_SOURCE_DIR 和 CMAKE_SOURCE_DIR 相同;更複雜的專案會包含數個子專案,子專案下面還可能會有多個資料夾,PROJECT_SOURCE_DIR 內容為目前正在處理中的專案最上層目錄。
PROJECT_BINARY_DIR
目前所屬專案的建置根目錄,專案意義同上。在 in-source build 時和 PROJECT_SOURCE_DIR 相同。
CMAKE_CURRENT_SOURCE_DIR
目前正在處理的 CMakeLists.txt 所在位置。
CMAKE_CURRENT_BINARY_DIR
目前正在處理的 CMakeLists.txt 對應的建置資料夾位置。當然,在 in-source build 時和 CMAKE_CURRENT_SOURCE_DIR 相同。

這裡要注意的是,CMake 中都使用絕對路徑來表示檔案位置。

為了瞭解 CMake 目前的 source tree 和 binary tree 為何,我們可以在 CMakeLists 當中加上:

message("CMAKE_SOURCE_DIR= ${CMAKE_SOURCE_DIR}")
message("CMAKE_BINARY_DIR= ${CMAKE_BINARY_DIR}")

在源碼之外建置 編輯

本章採用和之前相同的範例,目錄樹的架構如下,各原始碼的內容請參考前一節--建置基本的執行檔

  • ex2/
    • src/
      • CMakeLists.txt
      • calc.c
      • calc.h
      • main.c


Note
若是沿用前一個例子的檔案,請先清除源碼根目錄所有CMake 中間檔,否則源碼根目錄含有前次留下的 CMakeCache.txt,仍會被 CMake 優先視為建置根目錄,於是執行 In-source build


設目前工作目錄為 ex2/,執行下列指令:

$ mkdir -p build
$ cd build
$ cmake ../src
$ make

如果你的編譯器並非系統預設,別忘了依照需求指定 Generator:

$ cmake -G "Unix Makefiles" ../src
$ cmake -G "MSYS Makefiles" ../src
> cmake -G "Visual Studio 9 2008" ../src


執行結束後,ex2/build 下會出現各項中間檔、makefile 以及最終的 ex2 執行檔,但 ex2/src 原封不動,只有三個 C 源碼和一個 CMakeLists.txt。之後若出現什麼疑難雜症,可以輕鬆將 ex2/build 砍掉重練。

注意事項 編輯

在執行 Out-of-source build 之前必須先確定所指定的源碼根目錄是否乾淨,若是該目錄下含有前次留下的 CMakeCache.txt 仍會執行 In-source build。

由於 CMake 生成的 makefile 當中並不會包含 make distclean 的 rule,因此強烈建議採用 out-of-source build,發佈的時候只需將乾淨的 source tree 打包即可。