作者:billy
版權聲明:著作權歸作者所有,商業轉載請聯系作者獲得授權,非商業轉載請注明出處
CMake簡介
CMake是一個跨平台的、開源的建構工具。cmake是makefile的上層工具,它們的目的正是為了産生可移植的makefile,并簡化自己動手寫makefile時的巨大工作量。目前很多開源的項目都可以通過CMake工具來輕松建構工程,例如部落格之前分享的openHMD、hidapi、OSVR-Core等等,代碼的分享者提供源代碼和相應的Cmake配置檔案,使用者就可以非常友善的在自己的電腦上建構相應的工程,進行開發和調試。
Qmake VS Cmake
- qmake 是為 Qt 量身打造的,使用起來非常友善
- cmake 使用上不如qmake簡單直接,但複雜換來的是強大的功能
- 内置的 out-of source 建構(目前QtCreator為qmake也預設啟用了該功能,詳情請搜尋“Qt影子建構”)
- 為各種平台和場景提供條件編譯
- 可處理多個可執行檔案情況,和很好配合 QtTest 工作
如何選擇建構方式?
Using CMake to Build Qt Projects 此書中提到:
對簡單的Qt工程,采用 qmake
對複雜度超過 qmake 處理能力的,采用 cmake(例如程式中調用了很多第三方庫)
接下來我們就一起來學習下CMake的文法和常用指令。
基本文法規則
- 變量使用 ${} 方式取值,但是在 IF 控制語句 中是直接使用變量名
- 指令(參數 1 參數 2…),參數使用括弧括起,參數之間使用空格或分号分開
- 指令是大小寫無關的,參數和變量是大小寫相關的,推薦全部使用大寫指令
CMake常用指令
-
CMAKE_MINIMUM_REQUIRED (VERSION2.6 FATAL_ERROR)
功能:規定cmake程式的最低版本
這行指令是可選的,我們可以不寫這句話,但在有些情況下,如果CMakeLists.txt檔案中使用了一些高版本cmake特有的一些指令的時候,就需要加上這樣一行,提醒使用者更新到該版本之後再執行cmake
-
PROJECT(<Name>)
功能:用于指定項目的名稱
這條指令會自動建立兩個變量:
<projectnam>_SOURCE_DIR(源代碼路徑) 和 <projectname>_BINARY_DIR(二進制檔案儲存路徑)
cmake系統也幫助我們預定義了 PROJECT_SOURCE_DIR 和 PROJECT_BINARY_DIR 其值與上述對應相等
PROJECT_SOURCE_DIR 指向的目錄同内部建構相同,仍然是項目目錄
而 PROJECT_BINARY_DIR 則有所不同,指向<項目目錄>/build目錄
-
INCLUDE_DIRECTORIES ([AFTER|BEFORE] [SYSTEM] dir1 dir2 …)
功能:設定頭檔案位置
向工程添加多個特定的頭檔案搜尋路徑,路徑之間用空格分隔,如果路徑包含空格,可以使用雙引号将它括起來,預設的行為是追加到目前頭檔案搜尋路徑的後面
-
ADD_LIBRARY(libname [SHARED|STATIC|MODULE] [EXCLUDE_FROM_ALL] source1 source2 … sourceN)
功能:添加動态靜态庫
- 添加一個名為<libname>的庫檔案
- 指定STATIC, SHARED, MODULE參數來指定要建立的庫的類型, STATIC對應的靜态庫(.a),SHARED對應共享動态庫(.so)
- [EXCLUDE_FROM_ALL], 如果指定了這一屬性,對應的一些屬性會在目标被建立時被設定(指明此目錄和子目錄中所有的目标,是否應當從預設建構中排除, 子目錄的IDE工程檔案/Makefile将從頂級IDE工程檔案/Makefile中排除)
- source1 source2 … sourceN用來指定源檔案
-
ADD_SUBDIRECTORY(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
功能:去子目錄中檢視可用的CMakeLists.txt檔案
如果目前目錄下還有子目錄時可以使用add_subdirectory,子目錄中也需要包含有CMakeLists.txt
EXCLUDE_FROM_ALL含義:将這個目錄從編譯過程中排除
-
ADD_EXECUTABLE( [WIN32] [MACOSX_BUNDLE] [EXCLUDE_FROM_ALL] [source1] [source2 …])
功能:添加可執行檔案
例:ADD_EXECUTABLE(hello ${SRC_LIST})
定義了這個工程會生成一個檔案名為 hello 的可執行檔案,相關的源檔案是 SRC_LIST 中定義的源檔案清單
這裡的 hello 和之前的項目名稱沒有任何關系,可以任意定義
-
ADD_DEPENDENCIES(target-name depend-target1 depend-target2 …)
功能:用于添加編譯器指令行标志(選項),通常的情況下我們使用其來添加預處理器定義
讓一個頂層目标依賴于其他的頂層目标,保證某個目标在其他的目标之前被建構
-
TARGET_LINK_LIBRARIES(<name> lib1 lib2 lib3)
功能:将若幹庫連結到目标庫檔案
例如:TARGET_LINK_LIBRARIES(hello log4cpp thrift)
這句話指定在連結目标檔案的時候需要連結的外部庫,其效果類似gcc的編譯參數“-l”,可以解決外部庫的依賴問題
-
SET_PROPERTY
功能:在給定的作用域内設定一個命名的屬性,PROPERTY參數是必須的
set_property(<GLOBAL |
DIRECTORY [dir] |
TARGET [target ...] |
SOURCE [src1 ...] |
TEST [test1 ...] |
CACHE [entry1 ...]>
[APPEND]
PROPERTY <name> [value ...])
第一個參數決定了屬性可以影響的作用域,必須為以下值:
GLOBAL 全局作作用域,不接受名字
DIRECTORY 預設為目前路徑,但是同樣也可以用[dir]指定路徑
TARGET 目标作用,可以是0個或多個已有的目标
SOURCE 源作用域, 可以是0個過多個源檔案
TEST 測試作用域, 可以是0個或多個已有的測試
CACHE 必須指定0個或多個cache中已有的條目
-
SET_DIRECTORY_PROPERTIES(PROPERTIES prop1 value1 prop2 value2)
功能:設定某個路徑的一種屬性
prop1 prop2代表屬性,取值為:
INCLUDE_DIRECTORIES
LINK_DIRECTORIES
INCLUDE_REGULAR_EXPRESSION
ADDITIONAL_MAKE_CLEAN_FILES
-
MESSAGE([STATUS|WARNING|AUTHOR_WARNING|FATAL_ERROR|SEND_ERROR] “message todisplay”…)
功能:向終端輸出使用者定義的資訊或變量的值
SEND_ERROR 産生錯誤,生成過程被跳過
STATUS 輸出字首為—的資訊
FATAL_ERROR 立即終止所有cmake過程
-
FIND_LIBRARY(<VAR> name1 [path1 path2 …])
功能:用于查找庫檔案 name1 的路徑,如果找到則将路徑儲存在 VAR 中(此路徑為一個絕對路徑),如果沒有找到則=結果為 <VAR>-NOTFOUND
-
FIND_PACKAGE(<Name>)
功能:找相應庫的子產品
windows下并不是很重要,但是在Unix下就非常重要了,find_package可以根據cmake内置的.cmake的腳本去找相應的庫的子產品,内建了很多庫的子產品變量,當調用了FIND_PACKAGE之後會有相應的變量生效
-
SET(VAR [VALUE] [CACHE TYPEDOCSTRING [FORCE]])
功能:用于設定變量,相當于為變量取别名
SET(CMAKE_BUILE_TYPE DEBUG) 設定編譯類型debug 或者release,debug 版會生成相關調試資訊,可以使用GDB 進行調試;release不會生成調試資訊
SET(CMAKE_C_FLAGS_DEBUG “-g -Wall”) 設定編譯器的類型
-
FILE
功能:檔案操作指令
# 将message寫入filename檔案中,會覆寫檔案原有内容
file(WRITE filename "message")
# 将message寫入filename檔案中,會追加在檔案末尾
file(APPEND filename "message")
# 從filename檔案中讀取内容并存儲到var變量中,如果指定了numBytes和offset,
# 則從offset處開始最多讀numBytes個位元組,另外如果指定了HEX參數,則内容會以十六進制形式存儲在var變量中
file(READ filename var [LIMIT numBytes] [OFFSET offset] [HEX])
# 重命名檔案
file(RENAME <oldname> <newname>)
# 删除檔案, 等于rm指令
file(REMOVE [file1 ...])
# 遞歸的執行删除檔案指令, 等于rm -r
file(REMOVE_RECURSE [file1 ...])
# 根據指定的url下載下傳檔案
# timeout逾時時間; 下載下傳的狀态會儲存到status中; 下載下傳日志會被儲存到log; sum指定所下載下傳檔案預期的MD5值,如果指定會自動進行比對,如果不一緻,則傳回一個錯誤; SHOW_PROGRESS,進度資訊會以狀态資訊的形式被列印出來
file(DOWNLOAD url file [TIMEOUT timeout] [STATUS status] [LOG log] [EXPECTED_MD5 sum] [SHOW_PROGRESS])
# 建立目錄
file(MAKE_DIRECTORY [dir1 dir2 ...])
# 會把path轉換為以unix的/開頭的cmake風格路徑,儲存在result中
file(TO_CMAKE_PATH path result)
# 它會把cmake風格的路徑轉換為本地路徑風格:windows下用"\",而unix下用"/"
file(TO_NATIVE_PATH path result)
# 将會為所有比對查詢表達式的檔案生成一個檔案list,并将該list存儲進變量variable裡, 如果一個表達式指定了RELATIVE, 傳回的結果将會是相對于給定路徑的相對路徑, 查詢表達式例子: *.cxx, *.vt?
NOTE: 按照官方文檔的說法,不建議使用file的GLOB指令來收集工程的源檔案
file(GLOB variable [RELATIVE path] [globbing expressions]...)
CMake常用變量
UNIX 如果為真,表示為 UNIX-like 的系統,包括 AppleOS X 和 CygWin
WIN32 如果為真,表示為 Windows 系統,包括 CygWin
APPLE 如果為真,表示為 Apple 系統
CMAKE_SIZEOF_VOID_P 表示 void* 的大小(例如為 4 或者 8),可以使用其來判斷目前建構為 32 位還是 64 位
CMAKE_CURRENT_LIST_DIR 表示正在處理的CMakeLists.txt 檔案的所在的目錄的絕對路徑(2.8.3 以及以後版本才支援)
CMAKE_ARCHIVE_OUTPUT_DIRECTORY 用于設定 ARCHIVE 目标的輸出路徑
CMAKE_LIBRARY_OUTPUT_DIRECTORY 用于設定 LIBRARY 目标的輸出路徑
CMAKE_RUNTIME_OUTPUT_DIRECTORY 用于設定 RUNTIME 目标的輸出路徑
簡單的例子

建立一個Qt工程,沒有做任何修改,在項目中添加 CMakeLists.txt 檔案,編寫完成之後按照下圖配置以cmake編譯