初衷
CMake能用來編寫跨平臺(cross-platform)的構建規則,通過這些規則來調用各個平臺的編譯器、鏈接器,生成各個目標(靜態庫,靜態庫,或者可執行)。
我第一個接觸的大型C++項目是OpenCV,它是基于CMake構建的。后來接觸的另一個大型C++項目是Caffe,既提供Makefile也提供CMakeLists.txt。在使用CMake的過程中對CMake的常用語法越發熟悉,甚至日常工作中的項目代碼也被我用CMake進行構建。但是仍然覺得對CMake不夠了解,CMake的不少用法在官方文檔中的描述也感覺有些晦澀、不清晰。
好在CMake是開源項目,覺得CMake文檔寫的爛那就直接翻源碼。而由于越來越多的C/C++開源項目使用CMake進行構建,學習和深入理解CMake對于一個C/C++(尤其是跨平臺)程序員來說還是有相當的好處和必要的。(當然你也可以用gradle/bazel/buck/please/scons/xmake/emake等來構建)
此外,我也仔細看過CMake官方文檔的部分章節,寫過幾篇蹩腳的CMake筆記文檔,了解到通常越新版本的CMake特性越多。這系列blog分析的CMake源碼是CMake-3.14.3版。(不得不吐槽一下:CMake官網打開速度太慢,國內各大開源鏡像站點也都不收錄CMake源碼,CMake官方文檔打開也超慢,而且寫的也不夠系統,中文博客講CMake的也往往很初級)。如果你是第一次接觸CMake,我覺得你最好先用用CMake,稍微熟悉一點基本用法和一些概念后再來看本篇不遲。
CMake入口:命令行參數
CMake是什么?或許我們應該從"cmake.exe是什么?"(windows),或file `which cmake`
(Linux或Mac)來分析。當我們安裝好CMake,它提供了一個可執行文件cmake或cmake.exe,有時候還提供一個GUI版本,比如ccmake或cmake-gui,不過GUI版本可以認為是外科,里子還是cmake命令。
那么cmake命令是什么?其實就是一個C/C++項目編譯出來的可執行文件。它或許提供了一大堆支持的函數、類,但是對外的接口可以說只有一個,那就是main()
函數。當我敲下cmake ..
或者cmake .. -DCMAKE_BUILD_TYPE=Debug
,再或者cmake --build .
,cmake到底會怎么執行,其實就是看它的commandline argument parser是怎么處理的了:它能接受的(合法的)命令行參數有哪些?每一種分別是什么含義?
從$CMAKE_ROOT/Source/cmakemain.cxx
可以看出,它肯定支持的三個參數是:
--build
--open
-
-E
繼續看,發現do_cmake()
函數中處理了其他參數的情況,而且數量非常多:
image.png
而我們看看官方文檔對cmake命令行支持的參數是怎么寫的,先看cmake3.13版本的文檔,可以說是稀巴爛:
再看cmake3.14版本的命令行參數文檔:
看起來有所改善,把支持的命令行參數分成了幾個類別,思路上清晰了不少;不過仍然需要改進,比如說
cmake -N
這一條沒有被列出,但是其實后文又有提到。
根據3.14版的文檔可以看出,執行cmake命令,支持7大類參數:
- 指定
CMakeLists.txt
所在路徑,用來生成目標平臺的構建文件如Makefile、.sln、.xcodeproject等(cmake的主要特色) - 執行構建,相當于用通用的寫法,對生成的目標平臺構建描述文件進行調用,替代具體的"make"、"nmake"等寫法。(個人經常用,還可以指定
--target TargetName
和--config BUILD_TYPE
) - 用VS、XCode等打開工程(我沒用過,我也覺得沒必要)
- 執行cmake腳本
- 執行命令行工具
- 執行
find-package
工具(其實很廢柴,和CMakeLists.txt中的find_package()
根本不是一會事兒,試了好幾個包都找不到) - 在命令行里查看幫助(已經是9012年了,多少年前就有
git help xxx --web
在網頁中看幫助文檔了,cmake什么時候支持一下?)