友情提示,下面一大段都是廢話,可以直接跳到后面的部分...
工作以來(lái),一直從事的是基于Windows的C/C++開發(fā)工作枫疆。當(dāng)然,使用最多的當(dāng)數(shù)號(hào)稱宇宙第一IDE的Visual Studio集成開發(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è)本版熔任,幾乎所有的常見Linux發(fā)行版褒链,甚至還安裝過(guò)蘋果的X OS系統(tǒng)(解決過(guò)經(jīng)典的“五國(guó)語(yǔ)言”錯(cuò)誤,后來(lái)折騰到勉強(qiáng)能開機(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ì)于程序開發(fā)人員可以將更多的精力放在程序的邏輯和需求上去∈崧耄可是隐圾,我們雖然很好的完成了任務(wù),但卻會(huì)對(duì)IDE形成很大的依賴掰茶,而且這種依賴會(huì)越來(lái)越大暇藏。一旦有一天離開這些IDE,你會(huì)發(fā)現(xiàn)工作起來(lái)會(huì)及其的痛苦濒蒋。那么在Linux這樣甚至沒有圖形界面的平臺(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è)命令開頭:cmake_minimum_required(VERSION 2.8)
辽剧,正如你看到的VERSION
這個(gè)單詞只能大寫 :-( 送淆,該命令指定了運(yùn)行本配置文件所需的CMake最低版本(我們?cè)趺床拍苤雷畹桶姹臼嵌嗌倌兀课姨孛匆膊恢琅陆危汶S便寫一個(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 ...)
- 很好理解子姜,沒有可說(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
沒有指定具體鏈接到哪一個(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)該是類似于我們編程開發(fā)當(dāng)中的引用的概念吧。具體還沒有使用過(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
開頭嗓蘑。 - 事實(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)指正毫目,我將不勝感激。