本博客記錄:在使用cmake進行構建工程時,寫CMakeLists.txt 文件時,常使用到的命令與變量, 不斷補充更新中。
相關鏈接
官方地址: https://cmake.org/cmake/help/
git上很好實踐教程: https://github.com/ttroy50/cmake-examples
CMKAE中腳本相關的命令
cmake_minimum_required 命令
語法與參數介紹
語法: cmake_minimum_required(VERSION min[...policy_max] [FATAL_ERROR])
-
min 指定了編譯當前的cmake需要的最old的版本號,如果cmake版本號小於指定的版本號時,運行cmake 就報錯。
舉例:當前有cmake版本號為
3.10.2
, 運行如下的CMakeLists.txt 文件時, 就會報錯:cmake_minimum_required(VERSION 3.12)
運行
cmake
命令,報錯如下:提示運行版本小於要求的最小版本。CMake Error at CMakeLists.txt:1 (cmake_minimum_required): CMake 3.10.3 or higher is required. You are running version 3.10.2 -- Configuring incomplete, errors occurred!
-
... 表示min或max版本號之間的連接符。
-
policy_max 參數與cmake的policy setting相關,當指定了【policy_max】參數(要大於等於min版本號)時, 所有【小於等於 policy_max版本 或者 小於等於當前運行版本(誰小取誰)】中的已經的policy都設置為NEW.
policy 可以理解為版本之間的變更,例如語法新增加、約束變嚴等, policy使用
CMPXXXX
格式的編號,例如:CMP0000表示cmake文件中必須指定要求的最低版本號,CMP0002表示....等。
在新的版本中,如果要指定policy的新的規定, 語法為:cmake_policy(SET CMPXXXX NEW)
, 有時候為了新版本兼容之前寫的CMakeLists.txt文件, 則可以使用原來的policy, 語法為:cmake_policy(SET CMPXXXX OLD)
.
可以使用cmake_policy(VERSION min[...max])
指定policy的要求min與max版本號:
- 當不指定max版本號時,cmake會把min版本以及之前的版本引入的所有policy設置為NEW, 大於min版本號引入的policy默認不設置。
- 當指定max版本號時, cmake會把 【max版本或者當前運行的版本號(誰小取誰)】以及之前的版本號引入的的所有polixy設置為NEW, 超過的版本引入的policy默認不設置。
當使用cmake_minimum_required(VERSION)
命令時,會隱式地調用cmake_policy(VERSION)
命令用於設置policy相關的版本要求。
舉例: 下面的cmake命令:
cmake_mini_mum_required(VERSION 3.12...3.15)
# 上面命令會隱示地調用下面這條命令
cmake_policy(VERSION 3.12...3.15)
- FATAL_ERROR
該選項在2.6涉及2.6版本以下有用, 當指定該選項時,如果當前支行的版本號小於要求的版本號,就會報錯;如果不指定該選項時,只會報warning. 2.6版本之后,都是報錯了,所以用不着該選項了。
引入的變量
- CMAKE_MINIMUM_REQUIRED_VERSION : 設置該變量的值為
min
.
file 命令
file 命令專門用於訪問文件系統對文件與路徑進行操作的。
讀相關
寫相關
文件系統相關
file(GLOB variable 通配符表達式)
語法與參數
使用語法為: file(GLOB <variable> [LIST_DIRECTORIES true|false] [RELATIVE <path>] [CONFIGURE_DEPENDS] [<globbing-expressions>...])
含義: GLOB, 就是globbing的縮寫, 該命令查找所有在當前目錄(CMakeLists.txt所在目錄,即CMAKE_CURRENT_SOURCE_DIR
變量)下所有滿足匹配通配符表達式的文件,並保存到給定的變量中。
- GLOB: 是關鍵字。
- variable: 保存文件名的變量
- LIST_DIRECTORIES true| false : 表示是否要保存文件的路徑,默認保存。 (試了一下,置為false為什么不管用呢?)
- RELATIVE path: 給定該參數時,保存的路徑中是相對於給定path的路徑名。
- globbing-expressions: 通配符表達式。
使用舉例
file(GLOB source_list "src/*.cpp")
注意事項
不建議使用該命令搜索源文件名,原因是:如果CMakeLists.txt文件沒有變化,但是你增加了源文件, 此時給的結果不一樣正確。(我試了一下,ubuntu下可以給出正確結果)
路徑轉換相關
set命令
設置普通的命令
使用語法:set(<variable> <value>... [PARENT_SCOPE])
, 設置一個變量的值。 如果不給定值,就表示取消該變量的設置。
- PARENT_SCOPE: 表示在上層作用域內設置變量的值。
使用舉例
set(SOURCE_LIST 1.c 2.c 3.c)
設置cache 變量
使用語法與參數含義
語法:set(<variable> <value>... CACHE <type> <docstring> [FORCE])
, 該命令會設置的cache變量會被保存到CMakeCache.txt 文檔中, 可以打開看看的。
- CACHE 是關鍵字。
- type 表示變量的類型, 包含: BOOL、FILEPATH、PATH、STRING、INTERNAL。
- docstring: 類型注釋,表明該參數的含義。
- FORCE: 默認情況下,如果該cache 變量已經設置過了,再次執行該變量就不會被寫入,如果使用了FORCE關鍵字的話,只要命令被執行,就會對變量進行寫入的。
使用舉例
set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build." FORCE)
set_property 命令
使用語法與參數含義
該命令用於設置一個對象的屬性信息, 它的使用語法如下所示:
set_property(<GLOBAL |
DIRECTORY [<dir>] |
TARGET [<target1> ...] |
SOURCE [<src1> ...]
[DIRECTORY <dirs> ...] |
[TARGET_DIRECTORY <targets> ...]
INSTALL [<file1> ...] |
TEST [<test1> ...] |
CACHE [<entry1> ...] >
[APPEND] [APPEND_STRING]
PROPERTY <name> [<value1> ...])
- [對象類型] [對象名稱]: 指定了對象的類型以及要設置的對象名稱, 包含: GLOBAL, DIRECTORY, TARGET, SOURCE 等。例如
TARGET hello_main
. - PROPERTY 屬性名: 指定了要設置的屬性名以及屬性值。
使用舉例
cmake_minimum_required(VERSION 3.10.2)
project(hello_main)
add_executable(hello_main main.cpp)
set_property(TARGET hello_main PROPERTY CXX_STANDARD 11)
include 命令
** 語法與參數說明**
該命令用於導入文件或模塊中的CMAKE代碼, 類似於c語言中的include 功能。 使用語法為:
include(<file|module> [OPTIONAL] [RESULT_VARIABLE <var>]
[NO_POLICY_SCOPE])
- file | module: 指定的包含CMKE指定的文件 或者 模塊名。模塊名其實就是安裝cmake時已經提供的***.cmake文件(例如
/usr/share/cmake-3.10/Modules/
目錄下好多模塊) - OPTIONAL: 如果指定了該選項,當cmake查找不到指定文件時,不會報錯, 因為它是可選的嘛。
- RESULT_VARIABLE var: 用於保存查找到的文件路徑(查找成功時) 或者保存失敗結果NOTFOUND(失敗時)
舉例說明
cmake_minimum_required(VERSION 2.8)
project (hello_cpp11)
#這里導入CheckCXXCompilerFlag模塊, 並運行該模塊內的CHECK_CXX_COMPILER_FLAG命令。
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
message 命令
該命令是用於記錄log消息的,使用語法為:message([<mode>] "message text" ...)
。 其中,mode 關鍵字用於表示要記錄的log的類型,常用的有:
- FATAL_ERROR: cmake errer, 遇到該錯誤,cmake 直接停止處理。
- WARNING: 警告信息, 但是cmake會繼續執行下去的。
- STATUS: 用於記錄一些cmake 運行過程中的有用的信息。
例如:
message(STATUS "hello, world.")
set(NAME xiaoming)
messaeg(STATUS "hello, ${NAME}")
CMAKE中project相關命令
project 命令
語法與參數
使用語法為:project(項目名字, [VERSION 版本號] [DESCRIPTION 描述字符串] )
, 例如:
project(myproject, VERSION 1.0.0 DESCRIPTION "my first project" )
項目名字
, 即指定一個項目名字VERSION
, 指定項目的版本號, 可選字段, 一般不用不着它,不學習,不介紹DESCRIPTION
, 項目的描述, 可選字段,一般也不需要用它,不學習,不介紹- 還有其它的可選參數,例如
HOMEPAGE_URL
,LANGUAGES
, 用不着,不介紹
隱式引入的變量
PROJECT_NAME
: 它的值為 最近調用的project()
命令設置的項目名, 例如你的子目錄中調用了project()
命令,那么該變量名在子目錄中的值就是新設置的項目名。CMAKE_PROJECT_NAME
: 它的值為 最top 層的 project 設置的項目名PROJECT_SOURCE_DIR
: 最近 調用project()
命令定義的項目所在的源文件的絕對路徑。
例如:在根目錄中定義的CMakeLists.txt文件中調用了project()
命令, 在該作用域內, 該變量的值就是定義該CMakeLists.txt的絕對路徑。
如果在子目錄中定義的CMakeLists.txt文件中也調用了project()
命令, 在子目錄中CMakeLists.txt的作用域內,該變量的值就是子目錄的絕對路徑。PROJECT_BINARY_DIR
: 最近調用project()
命令定義的項目的binary的絕對路徑。 與調用cmake命令的位置有關, 通常會在build 目錄下調用cmake, 所以該binary目錄都在build 目錄內。<PROJECT-NAME>_SOURCE_DIR
: 首先不推薦使用它,如果你修改的項目名字,該變量名也需要適配。 它的值與PROJECT_SOURCE_DIR
變量的值相同。<PROJECT-NAME>_BINARY_DIR
: 不推薦使用, 與PROJECT_BINARY_DIR
的值相同。
add _executable 命令
普通的可執行文件
語法與參數說明
使用語法為:add_executable(name [WIN32] [MACOSX_BUNDLE] [EXCLUDE_FROM_ALL] [source1] [source2] ...)
. 例如:
cmake_minimum_required(VERSION 3.12)
add_executable(myMain 1.c 2.c)
-
name
: 即可執行文件的名字。windows平台下實際產生的可執行文件名為name.exe
, linux平台下產生的可執行文件名就是name
. -
WIN32關鍵字
: 用不着,不學習,跳過。 -
MACOSX_BUNDLE
: 用不着,不學習,跳過。 -
source1
: 源文件列表, 多個源文件使用空格分開,說明如下:- 從3.1版本開始, 可以使用“generator expressions"語法表示($<...>)依賴的源文件列表。
- 在該命令中可以暫時不寫依賴的源文件列表, 后續由
target_sources()
再添加源文件列表。
-
EXCLUDE_FROM_ALL
:當指定該參數時,要構建的target 就會被排除在all target 列表之外, 這樣當執行make
或make all
時, 該target 不會被編譯。
相關變量
CMAKE_RUNTIME_OUTPUT_DIRECTORY
: 該變量指定了生成的可執行文件的保存路徑.
import可執行文件
用到的時候補。
alias可執行文件
使用語法:add_library(<name> ALIAS <target>)
, 為給定的target添加一個別名name. 例如:
add_library(other_name ALIAS mylib)
add_library 命令
Normal Libraries
語法與參數說明
使用語法:add_library(<name> [STATIC | SHARED | MODULE] [EXCLUDE_FROM_ALL] [<source>...])
, 該命令用於添加一個庫文件的target, 包含靜態庫、動態庫等。
- name: target的名字。
- [STATIC | SHARED | MODULE]: STATIC 表示靜態庫,SHARED 表示動態庫,MODULE表示模塊庫,可以在運行時使用 dlopen 之類的命令動態加載的插件。
- EXCLUDE_FROM_ALL: 與
add_executable
命令中的參數相同,當指定該參數時,要構建的target 就會被排除在all target 列表之外。 - source: 源文件列表。
例如舉例
add_library(hello_library STATIC src/Hello.cpp)
相關變量
- ARCHIVE_OUTPUT_DIRECTORY: 修改靜態庫的輸出路徑。
- LIBRARY_OUTPUT_DIRECTORY: 修改動態庫的輸出路徑。
- ARCHIVE_OUTPUT_NAME: 修改靜態庫的輸出路徑。
- LIBRARY_OUTPUT_NAME: 修改動態庫的輸出路徑。
target_include_directories 命令
語法與參數說明
語法:target_include_directories(<target> [SYSTEM] [AFTER|BEFORE] <INTERFACE|PUBLIC|PRIVATE> [items1...] [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
當編譯給定target時,該命令用於指令要包含的路徑名。 當使用 gcc 編譯器編譯目標時,就會使用-I
選項指定該命令添加的路徑, 使用-I directory/include
.
- target: 要編譯的目標文件
- SYSTEM: 感覺用不到,跳過。
- AFTER 或 BEFORE: 控制把需要添加的路徑append 還是 prepend 到已有的路徑列表中。
- INTERFACE/PUBLIC/PRIVATE: 這幾個關鍵字很有用。
- 從內部實現上講: 當使用
PRIVATE
或PUBLIC
指定路徑名時, 會把路徑名添加到target的INCLUDE_DIRECTORIES
屬性中; 當使用PUBLIC
或INTERFACE
指定路徑名時, 會把路徑名添加到target的INTERFACE_INCLUDE_DIRECTORIES
的屬性中。 - 從外部表現上講:使用
PRIVATE
關鍵字時,添加的路徑只會在編譯當前target時使用到。 當使用INTERFACE
關鍵字時,添加的路徑只會在編譯任何鏈接到當前target的目標文件時使用到。 使用PUBLIC
關鍵字時,會包含以兩種使用。 因此,通常情況下,如果target是可執行文件,建議使用PRIVATE
, 如果target是動態或靜態庫, 建議使用PUBLIC
,比較方便。
- 從內部實現上講: 當使用
命令舉例
target_include_directories(mylib PUBLIC include/1.h PUBLIC ${PROJECT_SOURCE_DIR}/include)
target_include_directories(mytarget PRIVATE ${PROJECT_SOURCE_DIR}/include)
target_link_libraries命令
語法及參數含義
使用語法: target_link_libraries(<target> <PRIVATE|PUBLIC|INTERFACE> <item>...[<PRIVATE|PUBLIC|INTERFACE> <item>...]...)
該命令的用於指定一個target的鏈接階段的依賴庫。 它還可以 propagate any include directories with PUBLIC or INTERFACE scope from the linked library target.
PRIVATE|PUBLIC|INTERFACE的作用
暫時不太明白。
使用舉例
target_link_libraries( hello_binary PRIVATE hello_library)
install 命令
Installing Target
語法與參數
該命令用於安裝指定的target到指定目錄內。 全量的使用語法為:
install(TARGETS targets ... [EXPORT <export-name>]
[RUNTIME_DEPENDENCIES args...|RUNTIME_DEPENDENCY_SET <set-name>]
[[ARCHIVE|LIBRARY|RUNTIME|OBJECTS|FRAMEWORK|BUNDLE|
PRIVATE_HEADER|PUBLIC_HEADER|RESOURCE]
[DESTINATION <dir>]
[PERMISSIONS permissions...]
[CONFIGURATIONS [Debug|Release|...]]
[COMPONENT <component>]
[NAMELINK_COMPONENT <component>]
[OPTIONAL] [EXCLUDE_FROM_ALL]
[NAMELINK_ONLY|NAMELINK_SKIP]
] [...]
[INCLUDES DESTINATION [<dir> ...]]
)
- TARGET targets: 指明了要安裝的target.
- ARCHIVE|LIBRARY|RUNTIME等: 指明了target的類型。
- DESTINATION dir: 指明了要安裝到的路徑。當使用相對路徑時,是相對於變量
CMAKE_INSTALL_PREFIX
的, 該變量默認為/usr/local/
, 也可以在CMakeLists.txt文件中指定,也可以在運行CMAKE命令時指定,例如:cmake .. -DCMAKE_INSTALL_PREFIX=/install/location
使用舉例
install(TARGETS mylib LIBRARY DESTINATION lib)
install(TARGETS mybin RUNTIME DESTINATION bin)
Installing Directories
該命令用於安裝指定的目錄(包含目錄內的文件)到指定目錄。
使用語法與參數說明
install(DIRECTORY dirs...
TYPE <type> | DESTINATION <dir>
[FILE_PERMISSIONS permissions...]
[DIRECTORY_PERMISSIONS permissions...]
[USE_SOURCE_PERMISSIONS] [OPTIONAL] [MESSAGE_NEVER]
[CONFIGURATIONS [Debug|Release|...]]
[COMPONENT <component>] [EXCLUDE_FROM_ALL]
[FILES_MATCHING]
[[PATTERN <pattern> | REGEX <regex>]
[EXCLUDE] [PERMISSIONS permissions...]] [...])
- DIRECTORY dirs: 要安裝的頭文件的目錄路徑,默認為相對於當前的路徑。 注意:如果路徑以
/
結尾時, 會把路徑里面的內容復制到給定路徑,如果沒有以/
結尾,則也會復制該層目錄的。 - DESTINATION: 要安裝到的目錄路徑。
使用舉例
install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/ DESTINATION include)
Installing Files
使用語法與參數介紹
該命令用於安裝指定的文件到指定目錄:
install(<FILES|PROGRAMS> files...
TYPE <type> | DESTINATION <dir>
[PERMISSIONS permissions...]
[CONFIGURATIONS [Debug|Release|...]]
[COMPONENT <component>]
[RENAME <name>] [OPTIONAL] [EXCLUDE_FROM_ALL])
- FILES files: 指定要安裝的文件。
- DESTINATION dir: 指定要安裝的路徑。
使用舉例
install(FILES cmake.config DESTINATION etc)
target_compile_definitions
使用語法與參數定義
該命令用於指定指定編譯給定的target時,要定義的宏名稱:
target_compile_definitions(<target>
<INTERFACE|PUBLIC|PRIVATE> [items1...]
[<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
- target: 要指定編譯的target。
- INTERFACE/PUBLIC/PRIVATE: 與之前介紹的類似, 從內部實現是講: 當使用
INTERFACE
和PUBLIC
時,會把宏定義指定賦值給INTERFACE_COMPILE_DEFINITIONS
變量, 當使用PUBLIC
和PRIVATE
時,會把宏定義內容賦值給COMPILE_DEFINITIONS
變量。從外部表現上講, 當使用INTERFACE
和PUBLIC
時,表示編譯任何鏈接到該target(當target是一個庫時)的目標文件時,都增加了該宏定義。當使用PUBLIC
或PRIVATE
時,表示編譯當前target時,才使用該宏定義。 - items1: 表示要定義的宏名字。
其它方法:1. 修改變量CMAKE_CXX_FLAGS
(c++) 或者CMAKE_C_FLAGS
(C代碼),也可以實現該效果,但是建議使用target_compile_definitions
命令。
2. 在執行cmake 命令時,也可以通過參數指定,例如:cmake .. -DCMAKE_CXX_FLAGS="-DCHINA"
, 它就會定義一個CHINA
的宏定義。
使用舉例
main函數定義如下:
#include <iostream>
int main() {
#ifdef CHINA
std::cout << "I Love CHINA" << std::endl;
#endif
return 0;
}
cmake_minimum_required(VERSION 3.10.2)
add_executable(myTarget main.c)
target_compile_definations(myTarget PRIVATE CHINA)
add_subdirectory 命令
該命令用於增加一個構建的子目錄。 注意執行的數據流: cmake 命令會執行完子目錄中的CmakeLists.txt文件之后,再執行后面的命令。
使用語法與參數說明
使用語法為: add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
- source_dir: 要添加的子目錄, 建議使用相對路徑啊(相對於當前位置)。
- binary_dir: 用於保存輸出文件位置。 一般都不寫。
- EXCLUDE_FROM_ALL: 該參數很熟悉了,就是編譯的時候(make 或 make all),默認不被編譯。如果想要編譯它,顯示自己執行。
舉例
cmake_minimum_required(VERSION 3.10.2)
project(example)
add_subdirectory(subdir1)
add_subdirectory(subdir2)
set_target_properties 命令
該命令用於設置給定target的一些屬性值,類似於類對象的成員變量的值。 它們會影響到該target如何被構建的。
使用語法與參數說明
使用語法為:
set_target_properties(target1 target2 ...
PROPERTIES prop1 value1
prop2 value2 ...)
- target1... : 要設置的target的名字。
- PROPERTIES: 后面跟要設置的屬性的名字以及它們的值。
使用舉例
cmake_minimum_required(VERSION 3.10.2)
project(hello_main)
add_executable(hello_main main.cpp)
set_target_properties(hello_main PROPERTIES CXX_STANDARD 11)
target_compile_features 命令
該命令用於 Specifies compiler features required when compiling a given target.
使用語法與參數說明
使用語法為:target_compile_features(<target> <PRIVATE|PUBLIC|INTERFACE> <feature> [...])
.
- target: 要編譯的目標文件的名稱。
- PRIVATE | PUBLIC | INTERFACE : 這個關鍵字已經介紹過N次了,它指明了什么場景下生效該設置。
- feature: 就是支持的一些feature了,例如:
cxx_std_98
、cxx_std_11
、cxx_rvalue_references
等。
使用舉例
cmake_minimum_required(VERSION 3.10.2)
project(hello_main)
add_executable(hello_main main.cpp)
target_compile_features(hello_main PRIVATE cxx_std_11)
cmake中的常用變量
CMAKE_SOURCE_DIR
表示:源碼的根目錄,也就是最top層 CMakeLists.txt文件存在的目錄。
CMAKE_BINARY_DIR
表示:為編譯的binary的根目錄,也就是運行CMake時的目錄,一般就是build
目錄。
CMAKE_CURRENT_SOURCE_DIR
表示:當前正在運行的CMakeLists.txt文件的目錄
CMAKE_CURRENT_BINARY_DIR
表示:當前正處於的編譯目錄,例如如果正在運行src目錄下的CMakeLists.txt, 該變量通常為build/src
目錄。
CMAKE_CXX_FLAGS 和 CMAKE_C_FLAGS
表示:當使用g++(或gcc)編譯文件時,用於設置compiler flags, 也就是宏定義。
CMAKE_CXX_STANDARD
表示:該變量用於編譯target時,使用的c++標准,支持98, 11, 14, 17, 20, 23
. 該變量的作用原理是:用於初始化target的CXX_STANDARD
屬性。
C++編譯器相關的宏命令
check_cxx_compiler_flag 命令
該宏定義在CheckCXXCompilerFlag.cmake
模塊中, 可以打開該文件看它的實現的。 它的功能是用於檢測c++編譯器是否支持給定的編譯選項,並把檢測結果寫的給定變量中。
使用語法為:check_cxx_compiler_flag(<flag> <var>)
,
- flag: 要檢測的c++編譯選項
- var: 保存檢測結果的cache 變量。
使用舉例