CMake 構建方式可分爲兩種:內部構建和外部構建。應優先選擇外部構建,此方式產生的中間文件和最終文件不會污染原工程文件。
內部構建(in-source build)
是指產生的中間文件及最終目標產出物均生成至當前工做目錄。因爲 cmake 沒有相似 clean 之類可清空生成的中間文件指令,需手動刪除。所以,不推薦此方式。OpenWrt 採用此方式構建工程。html
外部構建(out-of-source build)
經過創建一個臨時文件夾,在此文件夾內執行構建操做,將生成的中間文件和最終的目標文件均生成至此文件夾來消除對原有工程文件的污染。java
經過目錄樹變量可輕鬆引用項目源代碼目錄路徑和構建後的二進制文件目錄路徑。
源代碼樹(Source Tree)包含app
二進制樹(Binary Tree)包含函數
兩者關係工具
Target 是 CMake 中很是重要的一個概念,不少高級操做都須要提供一個 Target 對象。
Target 對象ui
CMake 工程由 CMakeLists.txt 文件和 .h .hpp .c .cpp 等文件組成。每層目錄必須包含一個 CMakeLists.txt 文件。
CMake 語法支持大小寫兩種方式,建議統一採用指令小寫參數大寫的編碼方式。vscode 指令小寫可智能提示。
指令小寫編碼
# 所需 cmake 工具的最低版本 cmake_minimum_required(VERSION 3.1) # 工程名稱 project(hello-world) # 生成可執行程序 add_executable(hello-world main main.c )
指令大寫url
# 所需 cmake 工具的最低版本 CMAKE_MINIMUM_REQUIRED(VERSION 3.1) # 工程名稱 PROJECT(hello-world) # 生成可執行程序 ADD_EXECUTABLE(hello-world main main.c )
CMAKE_SOURCE_DIR
執行 cmake 命令時操做的目標目錄,通常爲頂層 CMakeLists.txt 文件所在目錄。spa
CMAKE_BINARY_DIR
執行 cmake 命令時所在的執行目錄。.net
CMAKE_CURRENT_SOURCE_DIR
當前 CMakeLists.txt 文件所在目錄。
PROJECT_SOURCE_DIR
當前工程的頂層源碼所在目錄,通常爲 project 所在 CMakeLists.txt 文件的目錄。
PROJECT_BINARY_DIR
該工程在構建後的二進制目錄中對應的目錄。
CMAKE_BUILD_TYPE
指定工程構建類型,取值包括 Debug, Release, RelWithDebInfo, MinSizeRel。
BUILD_SHARED_LIBS
經過設置該全局變量爲on或off,可自動生成共享庫或靜態庫。若是 add_library 中已明確指定庫類型,則無效。
CMAKE_MODULE_PATH
以";"分割的目錄列表,指定要由其加載的 CMake 模塊的 find、find_package 搜索路徑。默認狀況下是空的,它由項目設置。
CMAKE_INSTALL_PREFIX
執行安裝操做時,此目錄將預先添加至全部安裝目錄以前,拼接成新的安裝路徑。
cmake_minimum_required
指定工程所需 cmake 工具的最低版本
語法 cmake_minimum_required(VERSION <min>[...<max>] [FATAL_ERROR]) 示例 cmake_minimum_required(VERSION 3.1)
project
指定工程名稱,可經過 ${PROJECT_NAME} 引用工程名。工程名大小寫都可。
語法 project(<PROJECT-NAME> [VERSION <major>[.<minor>[.<patch>[.<tweak>]]]] [DESCRIPTION <project-description-string>] [HOMEPAGE_URL <url-string>] [LANGUAGES <language-name>...]) 示例 project(SampleApp)
add_executable
構建可執行程序
語法 add_executable(<name> [WIN32] [MACOSX_BUNDLE] [EXCLUDE_FROM_ALL] [source1] [source2 ...]) 示例 add_executable(${PROJECT_NAME} main.cpp utils.cpp parse.cpp)
add_library
語法 add_library(<name> [STATIC | SHARED | MODULE] [EXCLUDE_FROM_ALL] [source1] [source2 ...]) 示例 # 默認靜態庫 add_library(${PROJECT_NAME} button.cpp edit.cpp) # 靜態庫 add_library(${PROJECT_NAME STATIC} button.cpp edit.cpp) # 動態庫 add_library(${PROJECT_NAME SHARED} button.cpp edit.cpp)
target_include_directories
指定編譯時查找所需頭文件的目錄集合
語法 target_include_directories(<target> [SYSTEM] [BEFORE] <INTERFACE|PUBLIC|PRIVATE> [items1...] [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...]) 示例 target_include_directories(${PROJECT_NAME} PUBLIC ${App_SOURCE_DIR}/include ${Math_SOURCE_DIR}/include ${Ui_SOURCE_DIR}/include ) 說明 BEFORE 選項可將當前包含的目錄附加在全部頭文件包含目錄的前面。
target_link_libraries
指定可執行程序或庫程序連接時所需連接的庫文件(此指令有多種重載方式)
語法 target_link_libraries(<target> ... <item>... ...) 示例 target_link_libraries(${PROJECT_NAME} Math # 子工程 Ui # 子工程 pthread # 系統庫 )
include
從一個文件或模塊中加載並運行 CMake 代碼。
語法 include(<file|module> [OPTIONAL] [RESULT_VARIABLE <var>] [NO_POLICY_SCOPE] 示例 include("../macro.cmake")
find_package
使用 pkg-config 組件查找相關庫文件的配置信息,包括頭文件路徑、庫文件路徑、版本號等信息。
語法 find_package(<PackageName> [version] [EXACT] [QUIET] [MODULE] [REQUIRED] [[COMPONENTS] [components...]] [OPTIONAL_COMPONENTS components...] [NO_POLICY_SCOPE]) 示例 find_package(PkgConfig)
pkg_check_modules
查找驗證模塊並返回符合驗證要求的庫信息。
語法 pkg_check_modules(<prefix> [REQUIRED] [QUIET] [NO_CMAKE_PATH] [NO_CMAKE_ENVIRONMENT_PATH] [IMPORTED_TARGET [GLOBAL]] <moduleSpec> [<moduleSpec>...]) 示例 pkg_check_modules(GST REQUIRED gstreamer-1.0>=1.8 gstreamer-app-1.0>=1.8)
返回對象
語法 # 頭文件目錄 <Pacakgename>_INCLUDE_DIRS # 庫文件目錄 <Packagename>_LIBRARIES 示例 $(GST_INCLUDE_DIRS) ${GST_LIBRARIES})
add_definitions
用於實現編譯器中須要-D選項的編譯參數設置
語法 add_definitions(-DFOO -DBAR ...) 示例 add_definitions(-DRAPIDJSON_HAS_STDSTRING)
add_compile_options
做爲 add_definitions 指令的替代者,可支持全部編譯參數設置。
語法 add_compile_options(<option> ...) 示例 if (MSVC) # warning level 4 and all warnings as errors add_compile_options(/W4 /WX) else() # lots of warnings and all warnings as errors add_compile_options(-Wall -Wextra -pedantic -Werror) endif()
option
可視化配置界面中提供一個可選擇「ON」與"OFF"的選項,默認值爲「OFF」。
語法 option(<variable> "<help_text>" [value]) 示例 option(LIB_TYPE "Build shared library or static library." ON)
install target
語法 install(TARGETS targets... [EXPORT <export-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> ...]] ) 示例 # 安裝可執行程序 install(TARGETS ${PROJECT_NAME} DESTINATION "/usr/bin") # 安裝庫文件 install(TARGETS ${PROJECT_NAME} DESTINATION "/usr/lib")
install directory
語法 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...]] [...]) 示例 # 安裝頭文件 install(DIRECTORY "${PROJECT_SOURCE_DIR}/include/" DESTINATION "/usr/include") 說明 前面的 include/ 斜槓必須帶上,否則會造成 /usr/include/include 的狀況。 結尾帶斜槓時只拷貝其下的全部文件和目錄,不帶斜槓不然包含當前目錄。
CMake 中使用 「#」 表示註釋。
# 所需 cmake 工具的最低版本 cmake_minimum_required(VERSION 3.1)
message 指令用於輸出正常信息、警告信息和錯誤信息。
# 正常信息 message(STATUS "normal message.") # 警告信息 message(WARNING "warning message.") # 錯誤信息 message(FATAL_ERROR "fatal error message.") ...
可經過 set 和 ${} 分別設置和讀取變量。CMake 變量也存在做用於和值拷貝與引用的關係,此處不展開。
# 設置變量 set(MY_VARIABLE "system variable or custom variable.") # 讀取變量 message("MY_VARIABLE = ${MY_VARIABLE}") # 設置環境變量 set(ENV{JAVA_HOME} /opt/java/bin) # 讀取環境變量 message("LANG=$ENV{LANG}") # 判斷環境變量是否存在 if(NOT DEFINED ENV{JAVA_HOME}) <command> endif
list 可用於保存多個值
# 設置列表 set(APP_SOURCE) list(APPEND APP_SOURCE main.cpp math.cpp button.cpp) # 查看列表 message("${APP_SOURCES}") # 遍歷列表 foreach(SOURCE ${APP_SOURCES}) message("src = ${SOURCE}") endforeach
經過 function() 與 endfunction() 定義函數,函數參數列表、參數個數和具體參數由 ARGC、ARGV、ARGVN 表示。
# 定義函數 function(foo) message("there are ${ARGC} arguments: ${ARGV}") message("argument 0 is ${ARGV0}") endfunction() # 調用函數 foo(first second third fourth)
Condition 用於決定判斷和循環流程的走向。
if(<constant>) True: 1, ON, YES, TRUE, Y, 非零值 False:0, OFF, NO, FALSE,N, IGNORE, NOTFOUND, 空字符串,以 -NOTFOUND 結尾。 if(<variable|string>) if(NOT <condition>) if(<cond1> AND <cond2>) if(<cond1> OR <cond2>) if(COMMAND command-name) if(POLICY policy-id) if(TARGET target-name) if(<variable|string> IN_LIST <variable|string>) if(DEFINED <name>|CACHE{<name>}|ENV{<name>}) if(TEST test-name) if(EXISTS path-to-file-or-dirctory) if(file1 IS_NEWER_THAN file2) if(IS_DIRECTORY path-to-directory) if(IS_SYMLINK file-name) if(IS_ABSOLUTE path) if(<variable|string> MATCHES regex) if(<variable|string> LESS <variable|string>) if(<variable|string> GREATER <variable|string>) if(<variable|string> EQUAL <variable|string>) if(<variable|string> LESS_EQUAL <variable|string>) if(<variable|string> GREATER_EQUAL <variable|string>) if(<variable|string> STRLESS <variable|string>) if(<variable|string> STRGREATER <variable|string>) if(<variable|string> STREQUAL <variable|string>) if(<variable|string> STRLESS_EQUAL <variable|string>) if(<variable|string> STRGREATER_EQUAL <variable|string>) if(<variable|string> VERSION_LESS <variable|string>) if(<variable|string> VERSION_GREATER <variable|string>) if(<variable|string> VERSION_EQUAL <variable|string>) if(<variable|string> VERSION_LESS_EQUAL <variable|string>) if(<variable|string> VERSION_GREATER_EQUAL <variable|string>) if((condition) AND (condition OR (condition)))
CMake 語法中只有 if 語句沒有 switch 語句。
if(<condition>) <commands> elseif(<condition>) # optional block, can be repeated <commands> else() # optional block <commands> endif()
CMake 語法僅包含 while 語句,沒有 do while、while do、until 等其它循環語句。
while(<condition>) <commands> <break> # 跳出循環 <continue> # 進入下一個循環 endwhile()