文章目錄
- 安裝與配置
- 編譯單個源文件
- 編譯前的準備
- 開始編譯
- 編譯多個源文件
- 多個源文件在同一目錄下
- 多個源文件在不同目錄下
- math 目錄下的 CMakeLists.txt
- 根目錄的 CMakeLists.txt
- option 選項
- 導入外部庫
- 本地導入(find_package)
- 外部導入(FetchContent)
- 安裝與測試
- 安裝
- 測試
- 生成安裝包
安裝與配置
- 進入 官網下載
dmg
文件:
(在紅圈中根據自己的Mac版本任選一個 dmg
下載)
-
安裝完成后,從菜單欄選擇:Tools–How to Install For Command Line Use
-
在終端命令行中輸入彈出彈窗中第二項
to install symlinks to '/usr/local/bin', run:
的指令:
-
檢查是否配置成功:
cmake --version
可以正常識別,配置成功。
編譯單個源文件
編譯前的準備
使用 CMake 進行編譯之前需要具備三大內容:
他們的作用及內容如下:
源文件
main.cpp
#include <iostream>int main(int argc, const char * argv[]) {// insert code here...std::cout << "Hello, World!\n";return 0;
}
cmake 構建規則
CMakeLists.txt
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
# cmake最低版本需求,不加入此行會受到警告信息PROJECT(HELLO)
# 項目名稱,同時會自動生成 PROJECT_NAME 變量,
# 使用${PROJECT_NAME} 即可訪問到 hello_cmake。AUX_SOURCE_DIRECTORY(. SRC_LIST)
# 把當前目錄(.)下所有源代碼文件和頭文件加入變量SRC_LISTADD_EXECUTABLE(hello ${SRC_LIST}) # 生成應用程序 hello
在編譯單個文件時,也可以不添加第三句規則,而是直接在第四句規則中指定編譯的文件,例如,刪除第三句,并將第四句改為如下內容,本編譯規則依然有效:
ADD_EXECUTABLE(hello main.cpp) #生成應用程序 hello
AUX_SOURCE_DIRECTORY
:
- 第一個參數是目錄的路徑
- 第二個參數是變量名。當我們使用這個命令時,就會將指定目錄下的所有源文件保存到指定的變量名中。
- 這里將名為
main.cpp
的源文件編譯成一個名稱為hello
的可執行文件。
保存臨時構建文件和目標文件的文件夾
build
。
- 本示例中,該步驟本質上是創建一個可以位于文件系統上任何位置的構建文件夾(這里只是選擇了在當前文件夾中創建)。 所有臨時構建和目標文件都位于此目錄中,以保持源代碼樹的整潔。該種構建方式為外部構建。
- 其實也可以沒有這個文件夾,而是以內部構建的形式直接在源文件目錄構建項目,只是會導致臨時文件和源代碼放在一起,不好清理。
開始編譯
- 通過
cmake ..
命令開始進行編譯:
- 使用
cmake
生成的makefile
編譯得到可執行文件
- 此時在當前目錄下,就會生成可執行文件
hello
。
- 將其運行查看是否成功編譯:
編譯多個源文件
多個源文件在同一目錄下
與編譯單個源文件相比,難點主要是對 AUX_SOURCE_DIRECTORY 命令的使用。
如果不想使用 AUX_SOURCE_DIRECTORY 命令,也可以使用 set
來手動將多個源文件保存到變量名中:
set(SRC_LISTother.cppmain.cpp
)
多個源文件在不同目錄下
.
├── CMakeLists.txt
├── main.cc
└── math├── CMakeLists.txt├── MathFunctions.cc└── MathFunctions.h
在多個目錄下有著多個源文件的情況下,需要在每個目錄中都編寫一個 CMakeLists.txt
。這里為了方便,我們可以將 math
里的文件編譯為一個靜態庫再通過 main
函數調用。
math 目錄下的 CMakeLists.txt
math
目錄下的 CMakeLists.txt
主要做的事是將當前目錄下的文件編譯為一個靜態庫:
# 查找當前目錄下的所有源文件
# 并將名稱保存到 DIR_LIB_SRCS 變量
aux_source_directory(. DIR_LIB_SRCS)# 指定生成 MathFunctions 鏈接庫
add_library (MathFunctions ${DIR_LIB_SRCS})
- add_library:用于從某些源文件創建一個庫,默認生成在構建文件夾。
- 第一個參數為庫名(不需要 lib 前綴,會自動添加)
- 第二個參數用于指定 SHARED(動態庫)、STATIC(靜態庫)(如果不寫,則通過全局的
BUILD_SHARED_LIBS
的FALSE
或TRUE
來指定。上例中就沒有寫) - 第三個參數即為源文件列表。
根目錄的 CMakeLists.txt
# CMake 最低版本號要求
cmake_minimum_required (VERSION 2.8)# 項目信息
project (Demo3)# 查找目錄下的所有源文件
# 并將名稱保存到 DIR_SRCS 變量
aux_source_directory(. DIR_SRCS)# 添加 math 子目錄
add_subdirectory(math)# 指定生成目標
add_executable(Demo ${DIR_SRCS})# 添加鏈接庫
target_link_libraries(Demo MathFunctions)
- add_subdirectory:用于表示該項目包含一個子目錄,此時會去處理子目錄下的
CMakeLists.txt
與源文件。 - target_link_libraries:該命令用于指明可執行文件
Demo
需要鏈接MathFunctions
庫。- 第一個參數為可執行文件名
- 第二個參數為訪問權限(
PUBLIC
、PRIVATE
、INTERFACE
,默認為PUBLIC
) - 第三個參數為庫名(這里庫名使用了
math
目錄下的CMakeLists.txt
中生成的MathFunctions
鏈接庫) - 【后兩個參數可以為多個】
option 選項
面對 庫文件很大 或者 庫文件依賴第三方庫 的時候,我們可能希望將 該庫文件作為一個可選項(而不是非得鏈接不可)。
- 這里仍以
MathFunctions
為例進行實現。首先在頂層CMakeLists.txt
文件添加一個選項option
,其基本格式如下:
option (USE_MYMATH "should we use our own math functions?" ON)
- 第一個參數定義選項名稱。
- 第二個參數說明選項的含義。
- 第三個參數定義選項默認狀態,一般是
OFF
或者ON
,除去ON
之外,其他所有值都被認為是OFF
。
- 接下來就是將構建和連接
MathFunctions
設置為可選項。修改頂層CMakeLists.txt
文件如下所示:
if (USE_MYMATH)include_directories ("${PROJECT_SOURCE_DIR}/MathFunctions")add_subdirectory (math)# 將 ${EXTRA_LIBS} 變量中舊有的內容和 MathFunctions # 都加入到EXTRA_LIBS變量中set (EXTRA_LIBS ${EXTRA_LIBS} MathFunctions)
endif (USE_MYMATH)# add the executable
add_executable(Demo ${DIR_SRCS})
target_link_libraries(Demo ${EXTRA_LIBS})
PS: 這里我們使用了 USE_MYMATH
這個宏,倘若在源碼中也想使用它,那么需要由 CMake
通過在配置文件 Config.h
添加以下代碼:
#cmakedefine USE_MYMATH
之后源碼 include
該頭文件(Config.h)來實現。
導入外部庫
本地導入(find_package)
本節示例的目錄結構如下:
.
├── CMakeLists.txt
├── main.cpp
└── README.adoc
以 boost
為例,演示如何導入一個本地的第三方庫, MakeLists.txt
內容如下:
cmake_minimum_required(VERSION 3.5)# Set the project name
project (third_party_include)
# 使用庫文件系統和系統查找 boost install
# 注意這是第三方庫,而不是自己生成的靜態動態庫
find_package(Boost 1.46.1 REQUIRED COMPONENTS filesystem system)
if(Boost_FOUND)message ("boost found")
else()message (FATAL_ERROR "Cannot find Boost")
endif()# Add an executable
add_executable(third_party_include main.cpp)# link against the boost libraries
target_link_libraries( third_party_includePRIVATEBoost::filesystem
)
使用 find_package
命令來在本地搜索對應的第三方庫,它的參數的含義如下:
Boost
代表需要查詢的庫名稱;1.46.1
代表需要庫的最低版本;REQUIRED
表示該庫是必須的,如果找不到會報錯;COMPONENTS
用于檢測該庫的對應組件是否存在,如果不存在則認為找到的庫不滿足條件。filesystem
和system
代表搜索的位置,分別是 庫文件系統 和 文件系統。
外部導入(FetchContent)
FetchContent
是 3.11.0
版本開始提供的功能,只需要一個 URL
或者 Git
倉庫即可引入一個庫,這里以 GoogleTest
庫為例:
cmake_minimum_required(VERSION 3.14)
project(my_project)# GoogleTest requires at least C++11
set(CMAKE_CXX_STANDARD 11)include(FetchContent)
FetchContent_Declare(googletestURL https://github.com/google/googletest/archive/609281088cfefc76f9d0ce82e1ff6c30cc3591e5.zip
)
# 對于Windows:防止重寫父項目的編譯器/鏈接器設置
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)
include(FetchContent)
:表示引入FetchContent
。FetchContent_Declare(第三方庫)
:獲取第三方庫,可以是一個URL
或者一個Git
倉庫。FetchContent_MakeAvailable(第三方庫)
:將這個第三方庫引入項目。target_link_libraries(主項目 PRIVATE 子模塊::子模塊)
:鏈接這個第三方庫。
安裝與測試
安裝
示例的目錄結構如下:
.
├── CMakeLists.txt
├── config.h.in
├── License.txt
├── main.cc
└── math├── CMakeLists.txt├── MathFunctions.cc└── MathFunctions.h
math
目錄下的CMakeLists.txt
:
# 查找當前目錄下的所有源文件
# 并將名稱保存到 DIR_LIB_SRCS 變量
aux_source_directory(. DIR_LIB_SRCS)# 指定生成 MathFunctions 鏈接庫
add_library (MathFunctions ${DIR_LIB_SRCS})# 指定 MathFunctions 庫的安裝路徑
install (TARGETS MathFunctions DESTINATION lib)
install (FILES MathFunctions.h DESTINATION include)
通過 install
命令:
- 將靜態庫
MathFunctions
安裝到/usr/local/lib
目錄下 - 將頭文件
MathFunctions.h
安裝到/usr/local/include
目錄下。
根目錄
下的CMakeLists.txt
中的install
內容:
# 指定安裝路徑
install (TARGETS Demo DESTINATION bin)
install (FILES "${PROJECT_BINARY_DIR}/config.h"DESTINATION include)
- 將可執行程序
Demo
安裝到了/usr/local/lib
目錄下; - 將頭文件
config.h
安裝到/usr/local/lib
目錄下。
PS:/usr/local/
是默認安裝的根目錄,可以通過修改 CMAKE_INSTALL_PREFIX
變量來指定文件安裝文件的根目錄。
測試
CMake
提供了一個名為 CTest
的測試工具。它通過 add_test
命令來進行相關測試,項目根目錄的 CMakeLists.txt
文件中的 add_test
命令內容如下:
# 啟用測試
enable_testing()# 測試程序是否成功運行
add_test (test_run Demo 5 2)# 測試幫助信息是否可以正常提示
add_test (test_usage Demo)
set_tests_properties (test_usagePROPERTIES PASS_REGULAR_EXPRESSION "Usage: .* base exponent")# 測試 5 的平方
# add_test (test_5_2 Demo 5 2)# set_tests_properties (test_5_2
# PROPERTIES PASS_REGULAR_EXPRESSION "is 25")# 測試 10 的 5 次方
# add_test (test_10_5 Demo 10 5)# set_tests_properties (test_10_5
# PROPERTIES PASS_REGULAR_EXPRESSION "is 100000")# 測試 2 的 10 次方
# add_test (test_2_10 Demo 2 10)# set_tests_properties (test_2_10
# PROPERTIES PASS_REGULAR_EXPRESSION "is 1024")# 如果覺得上述過程過于復雜
# 也可以定義一個宏,用來簡化測試工作
macro (do_test arg1 arg2 result)add_test (test_${arg1}_${arg2} Demo ${arg1} ${arg2})set_tests_properties (test_${arg1}_${arg2}PROPERTIES PASS_REGULAR_EXPRESSION ${result})
endmacro (do_test)# 利用 do_test 宏,測試一系列數據
do_test (5 2 "is 25")
do_test (10 5 "is 100000")
do_test (2 10 "is 1024")
enable_testing
:用于啟動測試。add_test
:用于添加測試- 第一個參數為測試名;
- 第二個參數為可執行程序;
- 剩下的為可執行程序的參數。
set_tests_properties
:測試的提示信息。PASS_REGULAR_EXPRESSION
:測試屬性(正則表達式)來驗證輸出中是否包含了特定的字符串。這里驗證開方是否正確并且在計算錯誤時輸出輸出對應信息。macro
:宏,用于編寫一個重復性操作來簡化測試用例的編寫。do_test
:編寫的測試宏。
生成安裝包
如果想要生成安裝包,則需要使用 CMake
提供的打包工具 CPack
。此時需要在 CMakeLists.txt
中添加以下內容:
# 構建一個 CPack 安裝包
include (InstallRequiredSystemLibraries)
set (CPACK_RESOURCE_FILE_LICENSE"${CMAKE_CURRENT_SOURCE_DIR}/License.txt")
set (CPACK_PACKAGE_VERSION_MAJOR "${Demo_VERSION_MAJOR}")
set (CPACK_PACKAGE_VERSION_MINOR "${Demo_VERSION_MINOR}")
include (CPack)
include (InstallRequiredSystemLibraries)
:導入InstallRequiredSystemLibraries
模塊。- 設置一些
CPack
相關變量。 include (CPack)
:導入CPack
模塊。
接著執行 cmake
和 make
構建工程,此時再執行 cpack
命令即可生成安裝包:
#生成二進制安裝包
cpack -C CPackConfig.cmake#生成源碼安裝包
cpack -C CPackSourceConfig.cmake
當命令執行成功后,就會在當前目錄下生成 *.sh
、*.tar.gz
、*.tar.Z
這三個格式的安裝包。