友情提示,下面一大段都是廢話,可以直接跳到后面的部分...
工作以來(lái),一直從事的是基于Windows的C/C++開(kāi)發(fā)工作。當(dāng)然,使用最多的當(dāng)數(shù)號(hào)稱宇宙第一IDE的Visual Studio集成開(kāi)發(fā)環(huán)境,依稀還記得大學(xué)時(shí)候用的那個(gè)Visual C++ 6.0,對(duì)于一個(gè)剛剛上了兩節(jié)C++課的懵懂少年來(lái)說(shuō),難以想象居然還有如此強(qiáng)大的軟件,點(diǎn)兩下鼠標(biāo)就能運(yùn)行一個(gè)Hello World程序,簡(jiǎn)直牛逼!后來(lái)逐漸接觸了VS05、08等,最近兩年主要使用的版本是2015,也自認(rèn)為還是有一定了解的。
也是在大學(xué)的時(shí)候,曾經(jīng)有半年的時(shí)間瘋狂的迷上了折騰各種各樣的操作系統(tǒng),Windows從2000到8.1的各個(gè)本版,幾乎所有的常見(jiàn)Linux發(fā)行版,甚至還安裝過(guò)蘋果的X OS系統(tǒng)(解決過(guò)經(jīng)典的“五國(guó)語(yǔ)言”錯(cuò)誤,后來(lái)折騰到勉強(qiáng)能開(kāi)機(jī),但是后來(lái)還是因?yàn)楦鞣N硬件驅(qū)動(dòng)問(wèn)題,最終放棄),以上的各種折騰都是在實(shí)體機(jī)上面做的,因?yàn)楫?dāng)時(shí)的筆記本性能低下(什么酷睿2雙核處理器,內(nèi)存2G,硬盤256GB),虛擬機(jī)運(yùn)行的體驗(yàn)極差。經(jīng)歷了各種艱難的抉擇之后,最終選定了CentOS作為筆記本上唯一的一個(gè)操作系統(tǒng)日常使用了將近兩個(gè)月的時(shí)間(后面由于坑爹的舍友強(qiáng)烈要求玩DOTA又安裝回了Windows XP)。
扯遠(yuǎn)了,回過(guò)頭來(lái)介紹CMake。我們知道在Windows平臺(tái)下構(gòu)建一個(gè)稍微復(fù)雜一些的C/C++項(xiàng)目,我們可以利用Visual Studia直接創(chuàng)建一個(gè)工程,在幾乎完全的圖形化界面下對(duì)我們的項(xiàng)目進(jìn)行配置管理,然后進(jìn)行構(gòu)建之后就可以生成我們的可執(zhí)行文件了。這樣看起來(lái)非常方便,對(duì)于程序開(kāi)發(fā)人員可以將更多的精力放在程序的邏輯和需求上去??墒牵覀冸m然很好的完成了任務(wù),但卻會(huì)對(duì)IDE形成很大的依賴,而且這種依賴會(huì)越來(lái)越大。一旦有一天離開(kāi)這些IDE,你會(huì)發(fā)現(xiàn)工作起來(lái)會(huì)及其的痛苦。那么在Linux這樣甚至沒(méi)有圖形界面的平臺(tái)上我們?nèi)绾蝿?chuàng)建一個(gè)復(fù)雜的工程呢,答案就是使用CMake工具(當(dāng)然還有一些其他的方法,比如直接編寫makefile)。
下面將列出我自己在編寫CMakeLists.txt文件的時(shí)候遇到的各種問(wèn)題并給出解答,希望能夠幫到你。
-
一些基本的東西
- CMake工具的配置文件名稱為
CMakeLists.txt,錯(cuò)一個(gè)字符都不行,哪怕只是大小寫不符; - 腳本語(yǔ)言預(yù)留了一些長(zhǎng)得像函數(shù)一樣的關(guān)鍵字稱為命令,比如
cmake_minimum_required(),奇怪的是命令卻是大小寫不敏感的你可以寫成CMakE_MinimUM_ReqUirED()(如果你高興的話),個(gè)人習(xí)慣能小寫的盡量小寫; - 使用
#進(jìn)行注釋,就像C++中的//一樣; - 一般命令可以接收不確定個(gè)數(shù)的參數(shù),就像這樣
add_executable(ABC A.cpp B.cpp C.cpp),不幸的是多個(gè)參數(shù)之間并不是像我們習(xí)以為常的一樣使用逗號(hào)進(jìn)行分割,而是空格。一般的參數(shù)你可以使用引號(hào)引起來(lái),當(dāng)然也可以不加引號(hào),除非你的參數(shù)中本身就包含空格; - 一個(gè)
CMakeLists.txt總是以這樣一個(gè)命令開(kāi)頭:cmake_minimum_required(VERSION 2.8),正如你看到的VERSION這個(gè)單詞只能大寫 :-( ,該命令指定了運(yùn)行本配置文件所需的CMake最低版本(我們?cè)趺床拍苤雷畹桶姹臼嵌嗌倌兀课姨孛匆膊恢?,你隨便寫一個(gè)吧!╮( ̄▽  ̄)╭); - 還有一行的最后是不需要分號(hào)的。
- CMake工具的配置文件名稱為
-
設(shè)置項(xiàng)目名稱
project ("your project name")- 給你的項(xiàng)目取一個(gè)優(yōu)雅或者霸氣的名字;
-
打印信息
message("your messages")- 在執(zhí)行
cmake命令是會(huì)在終端打印指定的信息。如果你遇到了問(wèn)題,希望看一下某個(gè)環(huán)境變量或自定義變量的值,那么你可以使用該命令,例如:message(${CMAKE_CXX_FLAGS})
-
設(shè)置變量
set(KCBP_PATH e:/SVN/kbsskcbp)- 可以定義自定義變量,也可以用來(lái)修改CMake的預(yù)定義變量,例如設(shè)置編譯是
Debug還是Release版本set(CMAKE_BUILD_TYPE Release),使用變量的方式是${YOUR_VARIABLE}
-
指定頭文件目錄
include_directories([AFTER|BEFORE] [SYSTEM] dir1 [dir2 ...])target_include_directories(<target> [SYSTEM] [BEFORE] <INTERFACE|PUBLIC|PRIVATE> [items1...] [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])- 以上兩個(gè)命令都可以用于添加包含目錄,第一個(gè)命令設(shè)置的包含目錄作用域是當(dāng)前
CMakeLists.txt文件,而第二個(gè)命令可以指定為生成的某個(gè)可執(zhí)行文件或庫(kù)文件單獨(dú)設(shè)置包含目錄。 - 幾個(gè)參數(shù):
-
[BEFORE]:官方的解釋“If BEFORE is specified, the content will be prepended to the property instead of being appended”,翻譯一下“如果[BEFORE]參數(shù)被指定,包含目錄將被預(yù)先設(shè)置為屬性而非追加”; -
[SYSTEM]:指定該參數(shù),編譯器將被告知該包含目錄為系統(tǒng)的包含目錄; -
<INTERFACE|PUBLIC|PRIVATE>:指定包含目錄的作用范圍,不同的組合會(huì)修改不同的項(xiàng)目屬性字段。
-
-
指定鏈接庫(kù)目錄
link_directories(directory1 directory2 ...)- 很好理解,沒(méi)有可說(shuō)的,但是官方文檔有一句話 “Note that this command is rarely necessary”。
-
鏈接庫(kù)文件
link_libraries([item1 [item2 [...]]] [[debug|optimized|general] <item>] ...)target_link_libraries(<target> ... <item>... ...)- 以上兩個(gè)命令都可以實(shí)現(xiàn)鏈接指定的庫(kù)文件,
link_libraries沒(méi)有指定具體鏈接到哪一個(gè)目標(biāo),因此它適用于鏈接那些基礎(chǔ)公共的,在項(xiàng)目中每個(gè)生成項(xiàng)目中都會(huì)被使用到的庫(kù);target_link_libraries可以指定具體將庫(kù)鏈接給哪一個(gè)目標(biāo),因此它適用于僅在某個(gè)生成項(xiàng)目中使用到的庫(kù),另外還應(yīng)該注意官方文檔中有這樣一句話“The target_link_libraries() command should be preferred whenever possible. Library dependencies are chained automatically, so directory-wide specification of link libraries is rarely needed.”,因此更加推薦使用target_link_libraries。 - 參數(shù)
[debug|optimized|general]指定在那些配置下該鏈接項(xiàng)目生效。另外,該命令也支持PRIVATE|PUBLIC|INTERFACE參數(shù)。
-
生成可執(zhí)行文件
add_executable(<name> [WIN32] [MACOSX_BUNDLE] [EXCLUDE_FROM_ALL] [source1] [source2 ...])- 命令比較簡(jiǎn)單,添加一個(gè)名稱為
<name>的,由一個(gè)或多個(gè)源文件編譯鏈接而成的可執(zhí)行文件。中間的三個(gè)可選參數(shù)可以理解為在生成時(shí)設(shè)置了相應(yīng)的屬性。 -
add_executable(<name> IMPORTED [GLOBAL])該命令導(dǎo)入一個(gè)當(dāng)前項(xiàng)目以外的目標(biāo),以使其在邏輯上屬于當(dāng)前項(xiàng)目,因此也就實(shí)現(xiàn)了引用當(dāng)前項(xiàng)目以外資源的功能。需要注意的是,該命令僅僅是引入一個(gè)外部目標(biāo),并不會(huì)構(gòu)建一個(gè)新的目標(biāo)。舉例:add_executable(generator IMPORTED) set_property(TARGET generator PROPERTY IMPORTED_LOCATION "/path/to/some_generator") set(GENERATED_SRC ${CMAKE_CURRENT_BINARY_DIR}/generated.c) add_custom_command(OUTPUT ${GENERATED_SRC} COMMAND generator ${GENERATED_SRC}) add_executable(myexe src1.c src2.c ${GENERATED_SRC}) -
add_executable(<name> ALIAS <target>)該命令用于為指定目標(biāo)創(chuàng)建一個(gè)別名。按照個(gè)人的理解應(yīng)該是類似于我們編程開(kāi)發(fā)當(dāng)中的引用的概念吧。具體還沒(méi)有使用過(guò),如果理解有誤,萬(wàn)望指正。
-
生成庫(kù)文件
add_library(<name> [STATIC | SHARED | MODULE] [EXCLUDE_FROM_ALL] [source1] [source2 ...])- 可選參數(shù)
STATIC生成靜態(tài)庫(kù)、SHARED生成動(dòng)態(tài)庫(kù)、MODULE庫(kù)是不會(huì)被鏈接到其他庫(kù),但可以在運(yùn)行時(shí)通過(guò)dlopen-like函數(shù)動(dòng)態(tài)加載的插件;EXCLUDE_FROM_ALL參數(shù)指定在構(gòu)建是會(huì)添加相應(yīng)的屬性。
-
指定生成Debug還是Release版本
-
CMAKE_BUILD_TYPE該變量可被設(shè)置為Debug Release RelWithDebInfo MinSizeRel之一。當(dāng)這個(gè)變量值為Debug時(shí)CMake會(huì)使用變量CMAKE_CXX_FLAGS_DEBUG和CMAKE_C_FLAGS_DEBUG中的字符串作為編譯選項(xiàng),當(dāng)這個(gè)變量值為Release時(shí),工程會(huì)使用變量CMAKE_CXX_FLAGS_RELEASE和CMAKE_C_FLAGS_RELEASE作為編譯選項(xiàng)。
-
-
指定編譯選項(xiàng)
- 設(shè)置變量
CMAKE_<LANG>_FLAGS_<CONFIG>的值,可以指定語(yǔ)言以及配置。
- 設(shè)置變量
-
增加預(yù)處理定義
-
add_definitions(-DFOO -DBAR ...)注意預(yù)處理定義需要以-D開(kāi)頭。 - 事實(shí)上
add_definitions可以用來(lái)添加任何標(biāo)志,比如包含目錄和編譯選項(xiàng),功能應(yīng)該類似于Visual Studio項(xiàng)目配置中的命令行功能,但通常習(xí)慣上只用它來(lái)增加預(yù)處理定義。 - CMake文檔中建議使用另外三個(gè)命令來(lái)替代
add_definitions:- Use
add_compile_definitions()to add preprocessor definitions - Use
include_directories()to add include directories - Use
add_compile_options()to add other options
- Use
-
-
添加子目錄
add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])- 可選參數(shù)
binary_dir指定子目錄生成的目標(biāo)的存放位置,指定EXCLUDE_FROM_ALL參數(shù)意味著子目錄的生成目標(biāo)將默認(rèn)不被包含在父目錄所生成的目標(biāo)當(dāng)中,并且從IDE工程文件中排除。 - 當(dāng)然并非僅僅使用
add_subdirectory命令就可以添加子目錄了,你還必須為子目錄編寫一個(gè)CMakeLists.txt腳本文件并放置在子目錄中才可以。
-
獲取文件列表
-
aux_source_directory(<dir> <variable>)獲取dir目錄當(dāng)中的所有源文件名稱并保存在自定義變量variable當(dāng)中,該命令的主要作用是避免手動(dòng)寫出一堆的文件名稱。例如我們需要使用100個(gè)源文件構(gòu)建成一個(gè)庫(kù)文件或可執(zhí)行文件,我們只需要將所有源文件放在一個(gè)目錄中并使用該命令獲取到文件列表,然后將該列表傳遞給add_library或add_executable即可。
-
-
流程控制
- 流程控制內(nèi)容非常多,基本的包括邏輯判斷、循環(huán)等,等后面有時(shí)間會(huì)慢慢進(jìn)行補(bǔ)充,需要的同學(xué)可以先參考:https://cmake.org/cmake/help/v3.12/manual/cmake-commands.7.html
CMake是一個(gè)龐大的項(xiàng)目,包含非常多的內(nèi)容,本文僅僅是介紹了自己在項(xiàng)目當(dāng)中使用到的一部分,對(duì)于CMake個(gè)人也是處于不斷學(xué)習(xí)和自我糾正的過(guò)程中,如果文檔有錯(cuò)誤或不妥之處,還希望大家能給予批評(píng)指正,我將不勝感激。