cmake學習 - 初出茅廬

1、基本概念

1.1 構建方式

CMake 構建方式可分爲兩種:內部構建和外部構建。應優先選擇外部構建,此方式產生的中間文件和最終文件不會污染原工程文件。

內部構建(in-source build)
是指產生的中間文件及最終目標產出物均生成至當前工做目錄。因爲 cmake 沒有相似 clean 之類可清空生成的中間文件指令,需手動刪除。所以,不推薦此方式。OpenWrt 採用此方式構建工程。html

clipboard.png

外部構建(out-of-source build)
經過創建一個臨時文件夾,在此文件夾內執行構建操做,將生成的中間文件和最終的目標文件均生成至此文件夾來消除對原有工程文件的污染。java

clipboard.png

1.2 目錄樹

經過目錄樹變量可輕鬆引用項目源代碼目錄路徑和構建後的二進制文件目錄路徑。

源代碼樹(Source Tree)包含app

  • CMake 輸入文件(CMakeLists.txt)
  • 程序源文件(hello.cpp)
  • 程序頭文件(hello.h)

二進制樹(Binary Tree)包含函數

  • 本地構建系統文件(Makefiles)
  • 構建過程當中產生的文件(Libraries、Executables、Any other build generated files)

兩者關係工具

  • in-source build 時,兩者指向同一目錄。
  • out-of-source build,兩者指向不一樣目錄。

1.3 目標對象

Target 是 CMake 中很是重要的一個概念,不少高級操做都須要提供一個 Target 對象。

Target 對象ui

  • add_executable 建立可執行程序對象
  • add_library 建立共享庫或靜態庫對象

2、基本規則

2.1 工程結構

CMake 工程由 CMakeLists.txt 文件和 .h .hpp .c .cpp 等文件組成。每層目錄必須包含一個 CMakeLists.txt 文件。
  • 一層目錄結構
    clipboard.png
  • 多層目錄結構
    clipboard.png
  • 標準目錄結構
    clipboard.png

2.2 書寫方式

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 )

3、經常使用變量

3.1 系統變量

CMAKE_SOURCE_DIR
執行 cmake 命令時操做的目標目錄,通常爲頂層 CMakeLists.txt 文件所在目錄。spa

CMAKE_BINARY_DIR
執行 cmake 命令時所在的執行目錄。.net

CMAKE_CURRENT_SOURCE_DIR
當前 CMakeLists.txt 文件所在目錄。

3.2 工程變量

PROJECT_SOURCE_DIR
當前工程的頂層源碼所在目錄,通常爲 project 所在 CMakeLists.txt 文件的目錄。

PROJECT_BINARY_DIR
該工程在構建後的二進制目錄中對應的目錄。

3.3 構建方式

CMAKE_BUILD_TYPE
指定工程構建類型,取值包括 Debug, Release, RelWithDebInfo, MinSizeRel。

BUILD_SHARED_LIBS
經過設置該全局變量爲on或off,可自動生成共享庫或靜態庫。若是 add_library 中已明確指定庫類型,則無效。

3.4 搜索路徑

CMAKE_MODULE_PATH
以";"分割的目錄列表,指定要由其加載的 CMake 模塊的 find、find_package 搜索路徑。默認狀況下是空的,它由項目設置。

3.5 安裝變量

CMAKE_INSTALL_PREFIX
執行安裝操做時,此目錄將預先添加至全部安裝目錄以前,拼接成新的安裝路徑。

4、經常使用指令

4.1 工程選項

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)

4.2 構建可執行程序或標準庫

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)

4.3 文件包含

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")

4.4 使用 pkg-config

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})

4.5 設置選項

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)

4.6 工程安裝

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 的狀況。
結尾帶斜槓時只拷貝其下的全部文件和目錄,不帶斜槓不然包含當前目錄。

5、基本語法

5.1 註釋

CMake 中使用 「#」 表示註釋。
# 所需 cmake 工具的最低版本
cmake_minimum_required(VERSION 3.1)

5.2 輸出

message 指令用於輸出正常信息、警告信息和錯誤信息。
# 正常信息
message(STATUS "normal message.")

# 警告信息
message(WARNING "warning message.")

# 錯誤信息
message(FATAL_ERROR "fatal error message.")

...

5.1 變量

可經過 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

5.2 列表

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

5.4 函數

經過 function() 與 endfunction() 定義函數,函數參數列表、參數個數和具體參數由 ARGC、ARGV、ARGVN 表示。
# 定義函數
function(foo)
    message("there are ${ARGC} arguments: ${ARGV}")
    message("argument 0 is ${ARGV0}")
endfunction()

# 調用函數
foo(first second third fourth)

5.5 條件

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)))

5.6 判斷

CMake 語法中只有 if 語句沒有 switch 語句。
if(<condition>)
    <commands>
elseif(<condition>) # optional block, can be repeated
    <commands>
else()              # optional block
    <commands>
endif()

5.7 循環

CMake 語法僅包含 while 語句,沒有 do while、while do、until 等其它循環語句。
while(<condition>)
    <commands>
    <break>        # 跳出循環
    <continue>     # 進入下一個循環
endwhile()

參考資料

相關文章
相關標籤/搜索