文章目錄
- 一、前言
- 二、一些基本概念
- 1、cmake
- 2、列表項編譯工具鏈toolchain
- 2.1 預處理器
- 2.2 編譯器(gcc/g++)
- 2.3 彙編器
- 2.4 鏈接器
- 3、編譯/項目構建
- 3.1 少量文件
- 3.2 大量文件結構複雜
- 3.3 大量文件結構複雜(不依賴於平台)
- 4、構建過程
- 5、庫與進程
- 6、版本發佈
- 7、庫鏈接的傳遞性
- 三、常用基本命令
- 1、CMakeLists.txt文件通過 # 註釋行,通過 #[[內容]] 註釋塊
- 2、指定使用的本地cmak工具最低版本
- 3、定義工程名稱,還可指定版本、描述、URL、支持的語言
- 4、設置C++語言標準,默認使用C++11標準
- 4.1 設置標準版本
- 4.2 版本支持與否的處理
- 4.3 C++語言擴展的開關
- 5、定義“可執行程序”輸出及名字,鏈接若干源文件
- 5.1 多個源文件可用空格或分號隔開,也可用變量存儲源文件名
- 5.2 使用變量(默認字符串類型)存儲多個源文件名
- 6、製作動態/靜態庫:動態庫有可執行權限,靜態庫沒有可執行權限
- 7、設置可執行文件/庫的輸出路徑,若路徑不存在自動生成
- 7.1 指定—可執行文件輸出路徑
- 7.1 指定—庫輸出路徑
- 8、搜索文件(不必一一指定源文件)
- 8.1 aux_source_directory(路徑 變量名)
- 8.2 file(GLOB/GLOB_RECURSE 變量名 要搜索的文件路徑及類型)
- 9、變量操作
- 9.1 字符串拼接——會覆蓋原本變量字符串
- 9.2 字符串追加——不會覆蓋
- 9.3 字符串移除
- 9.4 list命令的其它功能
- 10、指定頭文件路徑
- 11、鏈接三方庫(靜態、動態)
- 11.1 靜態庫的鏈接——指定庫的路徑和庫名
- 11.2 動態庫的鏈接——指定庫的路徑和庫名,鏈接動態庫的語句在生成可執行程序/庫之後
- 12、日誌——調試命令message,可以打印變量值,默認為STATUS等級
- 13、自定義宏——add_definitions
- 14、定義可配置項
- 15、條件語句
- 15.1 單個分支:如果ENABKE_DEBUG為ON,則定義調試宏
- 15.2 多個分支:根據系統類型添加不同的預定義宏
- 16、CMake嵌套
- 參考資料
一、前言
- 個人學習、工作自用筆記,若有錯誤請看參考文檔與視頻
二、一些基本概念
1、cmake
- cmake是一個項目構建工具,可以跨平台,makefile寫起來繁瑣,依賴於系統。
- 可以通過命令行、可以通過GUI
2、列表項編譯工具鏈toolchain
- 預處理器、編譯器、彙編器、鏈接器
2.1 預處理器
- 頭文件展開、宏替換、去除註釋
2.2 編譯器(gcc/g++)
- 將源文件編譯為彙編文件(詞法/語法/語義分析、目標代碼生成)
2.3 彙編器
- 得到二進制文件(windows系統下為.obj文件,linux下為.o文件)
2.4 鏈接器
- 將多個二進制文件鏈接,生成一個可執行程序或動態/靜態鏈接庫
3、編譯/項目構建
3.1 少量文件
- 通過gcc/g++命令將源代碼編譯為可執行程序或庫
3.2 大量文件結構複雜
- 編寫Makefile文件,填寫若干指令,告訴編譯器如何編譯文件,使用批處理命令make執行編譯
3.3 大量文件結構複雜(不依賴於平台)
- 編寫CMakeLists.txt,使用cmake命令生成Makefile等一系列文件,後續步驟如3.2所示
4、構建過程
- FirsetStep: cmake CMakeLists.txt文件所在路徑
- SecondStep: make
5、庫與進程
- 動態庫在內存中有且僅有一份,且不屬於某個進程
6、版本發佈
- 版本發佈包括:include頭文件+靜態/動態庫;
- 因為庫為二進制,所以需要提供頭文件,其為庫文件的接口與説明
7、庫鏈接的傳遞性
- 庫鏈接具有傳遞性
三、常用基本命令
1、CMakeLists.txt文件通過 # 註釋行,通過 #[[內容]] 註釋塊
2、指定使用的本地cmak工具最低版本
cmake_minimum_required(3.16)
3、定義工程名稱,還可指定版本、描述、URL、支持的語言
project(qgis v1.0)
4、設置C++語言標準,默認使用C++11標準
4.1 設置標準版本
set(CMAKE_CXX_STANDARD 17)
- 也可以在執行cmake命令的時候,設置CMAKE_CXX_STANDARD宏來指定C++標準
- cmake CMakeLists.txt文件所在路徑 -DCMAKE_CXX_STANDARD=11
- -D表示設置宏的值
4.2 版本支持與否的處理
- 當編譯器不支持指定的C++標準版本時,若將該變量設為ON,CMake將報錯並終止構建過程
- 若將該變量設為OFF,CMake將自動降級到編譯器支持的最接近的C++標準版本
set(CMAKE_CXX_STANDARD_REQUIRED ON)
4.3 C++語言擴展的開關
- 若設為OFF,可確保項目遵循C++標準,具有更好的可移植性;
- 設為ON,則允許使用編譯器特定的C++語言擴展
set(CMAKE_CXX_EXTENSIONS OFF)
5、定義“可執行程序”輸出及名字,鏈接若干源文件
5.1 多個源文件可用空格或分號隔開,也可用變量存儲源文件名
add_executable(qgis a.cpp b.app)
5.2 使用變量(默認字符串類型)存儲多個源文件名
- 使用固定語法${變量名}取值
set(SRC a.cpp b.cpp)
add_executable(qgis ${SRC})
6、製作動態/靜態庫:動態庫有可執行權限,靜態庫沒有可執行權限
- 庫全名的組成:lib+庫名+.後綴
- 下方命令生成libqgis.a或libqgis.so文件(Linux)
- 若未指定庫類型,默認生成靜態庫文件
add_library(庫名 STATIC ${SRC})
add_library(庫名 SHARED ${SRC})
7、設置可執行文件/庫的輸出路徑,若路徑不存在自動生成
7.1 指定—可執行文件輸出路徑
- EXECUTABLE_OUTPUT_PATH為cmake自帶的指定可執行文件/動態庫輸出路徑的變量
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
7.1 指定—庫輸出路徑
- EXECUTABLE_OUTPUT_PATH為cmake自帶的指定靜態/動態庫輸出路徑的變量
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
8、搜索文件(不必一一指定源文件)
8.1 aux_source_directory(路徑 變量名)
- PROJECT_SOURCE_DIR為項目的絕對路徑,CMAKE_CURRENT_SOURCE_DIR為CMakeLists.txt所在路徑
aux_source_directory(${PROJECT_SOURCE_DIR}/src SRC_LIST)
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/src SRC_LIST)
add_executable(qgis ${SRC_LIST})
8.2 file(GLOB/GLOB_RECURSE 變量名 要搜索的文件路徑及類型)
- 指定搜索.cpp後綴文件
file(GLOB SRC_LIST ${PROJECT_SOURCE_DIR}/src/*.cpp) - 遞歸搜索文件夾中的文件
file(GLOB_RECURSE SRC_LIST ${PROJECT_SOURCE_DIR}/src/*.cpp)
add_executable(qgis ${SRC_LIST})
9、變量操作
9.1 字符串拼接——會覆蓋原本變量字符串
- 使用set拼接兩個字符串變量(源文件分佈在多個目錄下,使用file讀取多個字符串)
set(變量名 ${變量名1} ${變量名2} …)
9.2 字符串追加——不會覆蓋
- 使用list對變量追加字符串(拼接),list就是變量
list(APPEND list名 ${變量名1} ${變量名2} …)
9.3 字符串移除
- 多個字符串拼接後會在底層維護字符串之間的分隔符(;),規範字符串的移除
list(REMOVE_ITEM list名 字符串或${變量名1})
9.4 list命令的其它功能
- 獲取list的長度
list(LENGTH list名 存儲長度的變量名) - 獲取列表中指定索引值的元素,可以指定多個索引
- 索引從0開始,從前往後;也可以為負數,從後往前
list(GET list名 索引1 索引2) - 將列表中的字符串用連接符(字符串)連接起來,組成一個字符串
list(JOIN list名 連接符 新創建的字符串變量名) - 查找列表中是否存在指定的元素,若未找到,返回負一
list(FIND list名 字符串或變量名 新創建的變量名) - 指定位置插入若干元素
list(INSERT list名 索引 若干字符串或變量名) - 0索引位置插入若干元素
list(PREPEND list名 索引 若干字符串或變量名) - 移除列表最後一個元素
list(POP_BACK list名 彈出元素變量名(可選)) - 移除列表最後一個元素
list(POP_FRONT list名 彈出元素變量名(可選)) - 移除列表中指定索引元素
list(REMOVE_AT list名 索引1 索引2 …) - 移除列表中的重複元素
list(REMOVE_DUPLICATES list名) - 翻轉列表
list(REVERSE list名) - 列表排序
- 排序方法COMPARE:STRING|FILE_BASENAME|NATURAL
- 大小寫敏感CASE:SENSITIVE|INSENSITIVE
- 排序順序ORDER:ASCENDING|DESCENDING
list(SORT list名 STRING SENSITIVE ASCENDING)
10、指定頭文件路徑
- 指定頭文件路徑後,源文件include頭文件時只寫文件名.h即可,不必填寫全路徑
include_directories(${PROJECT_SOURCE_DIR}/include)
11、鏈接三方庫(靜態、動態)
- 系統庫直接指定庫的名字即可,因為系統知道其位置;第三方庫需要告訴當前項目庫的路徑
- 若三方庫為靜態庫,編譯會將其打包到可執行文件;若三方庫為動態庫,後續部署項目,需要拷貝動態庫並設置環境變量
- link_directories設置庫的查詢位置
- 實際link_libraries和target_link_libraries均可鏈接動態庫和靜態庫,推薦後者
11.1 靜態庫的鏈接——指定庫的路徑和庫名
link_directories(${PROJECT_SOURCE_DIR}/lib)
link_libraries(庫名1 庫名1 ……)
11.2 動態庫的鏈接——指定庫的路徑和庫名,鏈接動態庫的語句在生成可執行程序/庫之後
link_directories(${PROJECT_SOURCE_DIR}/lib)
add_executable(qgis ${SRC})
target_link_libraries(target(可執行文件/庫/源文件) 權限PRIVATE/PUBLIC/INTERFACE(可省略,默認PUBLIC) 庫名)
12、日誌——調試命令message,可以打印變量值,默認為STATUS等級
- 消息類型:STATUS|WARNING|AUTHOR_WARNING|SEND_ERROR|FATAL_ERROR
- STATUS:非重要消息
- WARNING:CMake警告,會繼續執行
- AUTHOR_WARNING:CMake重要警告(dev),會繼續執行
- SEND_ERROR:CMake錯誤,繼續執行,但是會跳過生成的步驟
- FINAL_ERROR:CMake致命錯誤,終止所有處理過程
message(消息類型 "輸出字符串")
13、自定義宏——add_definitions
- 通過在代碼中定義宏,控制測試代碼是否生效(#ifdef 宏 測試語句 #endif)
- 可以不在代碼中定義宏,在gcc/g++命令中指定宏:例如指定DEBUG宏(g++ test.cpp -DDEBUG -o app)
- 在CMake中也可以做類似的事情,命令為add_definitions,宏名稱前加-D
add_definitions(-DDEBUG_OUTPUT)
14、定義可配置項
- 下列命令定義了一個名為ENABKE_DEBUG的可配置選項,為布爾型變量
- 第二個參數是對配置項的描述,第三個為變量的值,默認為ON
option(ENABKE_DEBUG "Enable debug output" ON)
15、條件語句
15.1 單個分支:如果ENABKE_DEBUG為ON,則定義調試宏
- 可在執行CMake命令時候,通過cmake -DDEBUG_DEBUG=OFF 關閉宏,不輸出調試語句
if(ENABLE_DEBUG)
add_definitions(-DDEBUG_OUTPUT)
endif()
15.2 多個分支:根據系統類型添加不同的預定義宏
if(WIN32)
# 針對windows系統設置宏
add_definitions(-DWINDOWS_VERSION)
elseif(UNIX)
# 針對類Unix系統設置宏
else()
# 其它系統:報錯
message(FINAL_ERROR, "UnKnown operating system")
endif()
16、CMake嵌套
- source_dir為子節點(模塊)對應的目錄
- 主目錄含一個父CMakeLists.txt文件,每個模塊含一個子CMakeLists.txt文件
- 通過以下命令在父文件中添加子文件目錄
add_subdirectory(source_dir)
參考資料
參考1:CMake 保姆級教程(上) 參考2:CMake 保姆級教程(下) 參考3:CMake 保姆級教程—bilibili視頻【C/C++】 參考4:完全入門CMake語法與CMakeList編寫
本文章為轉載內容,我們尊重原作者對文章享有的著作權。如有內容錯誤或侵權問題,歡迎原作者聯繫我們進行內容更正或刪除文章。