目錄
1,CMake介紹
2,配置文件CMakeLists.txt
1,CMake介紹
????????CMake 是一個開源的、跨平臺的自動化構建系統生成工具,廣泛用于 C 和 C++ 項目的構建管理。它使用一個名為 CMakeLists.txt 的配置文件來定義如何構建項目,并能夠生成適用于不同編譯器和操作系統的構建文件(如 Makefile、Visual Studio項目等),從而實現跨平臺的一致性構建。
2,配置文件CMakeLists.txt
????????CMakeLists.txt 是 CMake 的核心配置文件,存在于每個需要構建的目錄中。配置指令常用的如下:
? ? ? ? 1,構建項目程序的簡單配置指令。?
# 聲明cmake使用的最低版本
cmake_minimum_required(VERSION 3.20)# 構建項目的信息。下面對應名稱、版本、描述、項目使用的語言
project(TestProject VERSION 1.1.1 DESCRIPTION "This is a TestProject" LANGUAGES CXX)# 設置使用C++11版本(14, 17, 20版本類似)
set(CMAKE_CXX_STANDARD 11)# 指定頭文件的搜索路徑:有target_include_directories和include_directories
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)# CMAKE_CURRENT_SOURCE_DI宏是表示CMakeLists.txt的路徑
? ? ? ? 2,set() 和 file() 設置變量的值。它們用于將一個或多個值組合起來賦給自定義的變量。用途如下:
# 指定編譯的源文件(頭文件不需要加入,cmake它不會讓它參與編譯)
# 方法一:指定有限個參與編譯。自定義SRC保存找到源文件路徑的變量名
set(SRC fun1.cpp fun2.cpp fun3.cpp main.cpp)?# 方法二:將指定目錄下的所有源文件參與編譯(目錄下非遞歸式,即子目錄不包含)
# PROJECT_SOURCE_DIR宏本質是cmake后面根的路徑名
#?自定義SRC保存找到的所有源文件路徑的變量名
aux_source_directories(${PROJECT_SOURCE_DIR}/*.cpp ${PROJECT_SOURCE_DIR}/*.cc SRC)?
# 方法三:目前最流行的file。GLOB 表示非遞歸查找;GLOB_RECURSE遞歸式查找
file(GLOB SRC ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp *.cc)# 指定庫的存放路徑。其實這里就是把指定的傳輸路徑的字符串設置到定義庫路徑的宏中
# CMAKE_LIBRARY_OUTPUT_DIRECTORY動態庫(.so,.dll)輸出路徑
# CMAKE_ARCHIVE_OUTPUT_DIRECTORY靜態庫(.a, .lib)輸出路徑
# 這里可以使用debug或release構建方式,即CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG 或?CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/lib) # 將生成的動態庫傳輸到lib下
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/lib) # 將生成的靜態庫傳輸到lib下# 指定可執行文件的輸出路徑。CMAKE_RUNTIME_OUTPUT_DIRECTORY(現代寫法)和EXECUTABLE_OUTPUT_PATH(過時寫法)
set(EXECUTABLE_OUTPUT_PATH /root/Test)#可選:分別設置 Debug/Release 輸出路徑
#set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG /root/Test/debug)
#set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE /root/Test/release)# 拼接字符串。將字符串賦給tmp和tmp1
set(tmp Hello Cmake)
set(tmp1 ${tmp} ${CMAKE_CURRENT_SOURCE_DIR})
? ? ? ? 3,動靜態庫的相關指令配置。
# 把指定的源文件編譯成一個庫(靜態庫或動態庫)
file(GLOB LIBS ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
add_library(myshared SHARED ${LIBS}) ?# 定義動態庫 ?
add_library(mystatic STATIC ${LIBS}) ?# 定義靜態庫# 指定庫的存放路徑
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/lib) # 將生成的動態庫傳輸到lib下
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/lib) # 將生成的靜態庫傳輸到lib下# 說明程序鏈接時,自定義庫的路徑
link_directories(${CMAKE_CURRENT_SOURCE_DIR}/lib) ?# 指定自定義庫的路徑# 鏈接自定義生成的庫
# 方法一:古老用法。鏈接靜態庫時可以使用;鏈接動態庫不推薦link_libraries(mystatic) ? ? ?# 鏈接庫mystatic
# 方法二:新用法。非常推薦。
target_link_libraries(test PRIVATE myshared) ?# 可執行程序test鏈接庫myshared
????????4,可執行文件的相關指令配置。
# 指定可執行文件的輸出路徑。CMAKE_RUNTIME_OUTPUT_DIRECTORY(現代寫法)和EXECUTABLE_OUTPUT_PATH(過時寫法)
set(EXECUTABLE_OUTPUT_PATH /root/Test)# 指定編譯的源文件(頭文件不需要加入,cmake它不會讓它參與編譯)
file(GLOB SRC ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp *.cc)# 通過源文件列表生成可執行文件目標,即告訴CMake把哪些源文件編譯成一個可執行程序
add_executable(test ${SRC})
# add_executable(test fun1.cpp fun2.cpp fun3.cpp main.cpp)
? ? ? ? 5,message 輸出日志。該命令用于在終端輸出變量,以提示用戶信息。
語法:
????????message([<mode>] "message text" ...)
參數說明:
????????<mode>(可選):指定消息的類型或行為。
????????"message text":要輸出的消息內容,可以包含變量 ${VAR}。消息類型(Mode)取值如下:
????????STATUS:輸出狀態信息(用 -- ?前綴顯示),不會中斷構建。
????????WARNING:輸出警告信息,不會中斷構建,但會高亮顯示。
????????SEND_ERROR:輸出錯誤信息,并中斷當前cmake構建階段,但繼續生成項目。
????????FATAL_ERROR:輸出錯誤信息,并完全中斷構建和生成的過程。樣例:
????????set(tmp Hello Cmake)
????????set(tmp1 ${tmp} ${CMAKE_CURRENT_SOURCE_DIR})
????????message(STATUS ${tmp})
????????message(STATUS ${tmp1})????????message(STATUS "************************************")
? ? ? ? 6,list處理列表。列表是用分號 “;” 分隔的一系列字符串,盡管你可能會看到使用空格分隔的值,在內部它們會被轉換成分號分隔的形式。該命令提供了一系列的操作來操作這些列表,包括添加、刪除、搜索和排序等。這里說明添加和刪除。
語法:
????????list(APPEND <list> [<element> ...])? # 將一個或多個元素追加到指定的列表末尾
????????list(REMOVE_ITEM <list> [<value> ...])? # 從列表中移除所有與給定值匹配的項
樣例:
????????set(MY_LIST a b c)? ?# 初始化一個列表MY_LIST
????????list(APPEND MY_LIST d e f)? ?# 添加新元素到列表末尾
????????message("MY_LIST: ${MY_LIST}")??# 輸出結果MY_LIST: a;b;c;d;e;f
????????set(MY_LIST a b c b d b)?# 初始化一個包含重復項的列表
????????list(REMOVE_ITEM MY_LIST b)?# 移除所有等于 "b" 的項
????????message("MY_LIST: ${MY_LIST}")??# 輸出結果MY_LIST: a;c;d
? ? ? ? list還有很多個模式運用,這里不做過多說明。明白原理后,在所需要的場景下自行查找即可
? ? ? ? 7,link_libraries() 和 target_link_libraries()。這兩種指令都是用于鏈接指定的庫。link_libraries()命令設置的是全局鏈接庫,會影響后續定義的所有目標。
link_libraries(mylib)
# 后續所有生成的可執行文件都會鏈接mylib庫add_executable(myapp main.cpp)?
????????target_link_libraries() 是現代 CMake 中用于為特定目標(可執行文件或庫)指定鏈接庫的方式。
語法:
????????target_link_libraries(<target-name> [PRIVATE|PUBLIC|INTERFACE] <library> ...)
參數說明:
????????<target-name>:之前通過 add_executable() 或 add_library() 定義的目標名稱。
????????PRIVATE:僅當前目標使用此庫。????????PUBLIC:不僅當前目標使用此庫,而且任何依賴于這個目標的其他目標也會繼承這個? ? ? ? ? ? 庫。
????????INTERFACE:當前目標本身不需要這些庫,但依賴它的目標需要。這點理解若困難可? ? ? ? ? ? 直接看下面樣例。
????????<library>:鏈接的庫文件。
樣例1:
????????// 可指定程序鏈接庫
????????target_link_libraries(myapp PRIVATE /path/to/libmylib.a) # 靜態庫 ????????target_link_libraries(myapp PRIVATE /path/to/libmylib.so) # 動態庫
樣例2:
????????# libA 庫需要鏈接 libB,后面的目標不會鏈接 libB
????????add_library(libA STATIC a.cpp)
????????target_link_libraries(libA PRIVATE libB)
????????# libD 庫需要鏈接 libE,并且它的使用者也需要鏈接 libE
????????add_library(libD STATIC d.cpp)
????????target_link_libraries(libD PUBLIC libE)
????????# libF 庫的使用者需要鏈接 libG,但 libF 自身并不直接使用 libG
????????add_library(libF INTERFACE)
????????target_link_libraries(libF INTERFACE libG)
? ? ? ? 注意:可執行程序鏈接庫的順序是先生成可執行程序,在進行動靜態庫的鏈接。
? ? ? ? 8,add_subdirectory 嵌套 CMakeLists.txt 文件。add_subdirectory 用于向構建過程添加一個子目錄。這個子目錄應該包含自己的 CMakeLists.txt 文件,定義了如何編譯該目錄下的源代碼以及如何將其鏈接到其他目標(如可執行文件或庫,大多數情況是庫文件)。
語法:
????????add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
參數說明:
????????source_dir:指定要添加的子目錄路徑,可以是相對路徑也可以是絕對路徑。
????????[binary_dir]可選參數:指定輸出文件存放的目錄。如果未指定,則默認為 source_dir? ? ? ? ? 對應的構建目錄。
????????[EXCLUDE_FROM_ALL]可選參數:暫時不做說明。
????????假設你有一個項目結構如下:
/my_project
|—— CMakeLists.txt
|—— /src
| ? |—— main.cpp
|—— /lib
? ? |—— CMakeLists.txt
? ? |—— /math
? ? ? ? |—— math.cpp
? ? ? ? |—— math.h????????/my_project 目錄是項目的根目錄,其中包含一個頂級 CMakeLists.txt 文件。/src 目錄包含了項目的主源文件(如 main.cpp),而 /lib/math 則包含了一個數學庫的實現(math.cpp 和 math.h)。
????????項目根目錄下的 CMakeLists.txt 文件內容如下:
cmake_minimum_required(VERSION 3.10)
# 設置項目名稱
project(MyProject)# 添加 lib 目錄中的子項目
add_subdirectory(lib)# 添加 src 目錄中的可執行文件
add_subdirectory(src)
????????lib 目錄下的 CMakeLists.txt 文件內容如下:
# 定義一個靜態庫
add_library(MathLib STATIC math/math.cpp)
# 包含頭文件路徑
target_include_directories(MathLib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/math)
????????在 src 目錄下,這里可以創建另一個 CMakeLists.txt 文件來編譯可執行文件,并鏈接之前定義的 MathLib 庫:
# 添加可執行文件
add_executable(MyExecutable main.cpp)
# 鏈接 MathLib 庫
target_link_libraries(MyExecutable MathLib)
????????通過這種方式,add_subdirectory 命令使得能夠輕松地組織和管理復雜的項目結構。每個子目錄可以有自己的 CMakeLists.txt 文件,從而讓項目更加模塊化和易于維護。
? ? ? ? 最后說明下Qt Creator中的CMake配置,Qt Creator環境中CMake配置