從零學(xué)習(xí)cmake構(gòu)建系統(tǒng)
什么是cmake
根據(jù)其官網(wǎng)的定義,cmake是一個開源跨平臺的,用于構(gòu)建、測試和打包軟件的一個套件工具。與cmake相關(guān)的幾個概念需要明晰,如GCC,make和makefile。
- GCC:GCC是GNU Compiler Collection(就是GNU編譯器套件),也可以簡單認為是編譯器,它可以編譯很多種編程語言(括C、C++、Objective-C、Fortran、Java等等)
- make:make工具可以看成是一個智能的批處理工具,它本身并沒有編譯和鏈接的功能,而是用類似于批處理的方式通過調(diào)用makefile文件中用戶指定的命令來進行編譯和鏈接的。
- makefile,makefile就是GCC命令的集合,make工具就根據(jù)makefile中的命令進行編譯和鏈接的
- cmake,當項目非常大時,手寫makefile會非常煩碎,而且不同平臺makefile也會不同,所以cmake就是可以根據(jù)CMakeLists.txt自動生成makefile。
入門實踐
我們已經(jīng)對于cmake有了一個總體上的認識,接下來就通過官方提供的幾個例子介紹下如何使用cmake。
構(gòu)建單個源文件
項目只有一個源文件,結(jié)構(gòu)如下,我們一般會新建一個目錄存儲cmake運行的產(chǎn)物,這里我新建了一個build目錄。
├── CMakeLists.txt ├── build └── main.cc
main.cc的內(nèi)容如下
#include <stdio.h> #include <stdlib.h> /** * power - Calculate the power of number. * @param base: Base value. * @param exponent: Exponent value. * * @return base raised to the power exponent. */ double power(double base, int exponent) { int result = base; int i; if (exponent == 0) { return 1; } for(i = 1; i < exponent; ++i){ result = result * base; } return result; } int main(int argc, char *argv[]) { if (argc < 3){ printf("Usage: %s base exponent \n", argv[0]); return 1; } double base = atof(argv[1]); int exponent = atoi(argv[2]); double result = power(base, exponent); printf("%g ^ %d is %g\n", base, exponent, result); return 0; }
CMakeLists.txt的內(nèi)容如下:
# Cmake的最低版本號的要求 cmake_minimum_required (VERSION 2.8) # 項目信息 project (Demo1) # 指定生成目標 add_executable(Demo main.cc)
在build目錄下執(zhí)行cmake .. 然后執(zhí)行make命令就可以得到Demo1的可執(zhí)行文件。
同一個目錄,多個源文件
如果我們將Demo1中main.cc的power函數(shù)抽取出來放到MathFunctions.cc中,項目結(jié)構(gòu)如下:
├── CMakeLists.txt ├── MathFunctions.cc ├── MathFunctions.h ├── build └── main.cc
那么該如何編譯呢,我們可以通過在add_executable命令中增加將MathFunctions.cc,效果如下add_executable(Demo main.cc MathFunctions.cc),但是如果有很多文件的情況下,一個文件一個文件的添加很麻煩,cmake提供了aux_source_directory命令,該命令會查找指定目錄下所有的源文件,然后將結(jié)果存到指定的變量名。CMakeLists.txt文件內(nèi)容如下
# CMake 最低版本號要求 cmake_minimum_required (VERSION 2.8) # 項目信息 project (Demo2) # 查找目錄下的所有源文件 # 并將名稱保存到 DIR_SRCS 變量 aux_source_directory(. DIR_SRCS) # 指定生成目標 add_executable(Demo ${DIR_SRCS})
多個目錄多個源文件
現(xiàn)在我們將MathFounction.h和MathFounction.cpp移動到math目錄下,項目結(jié)構(gòu)如下:
├── CMakeLists.txt ├── build ├── main.cc └── math ├── CMakeLists.txt ├── MathFunctions.cc └── MathFunctions.h
面對這種情況我們需要在Demo3目錄下和math目錄下各自編寫一個CmakeLists.txt文件,我們可以將math目錄里面的文件編譯成靜態(tài)庫再由main函數(shù)調(diào)用。 Demo3目錄下的CMakeLists.txt內(nèi)容如下
# 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_subdictory(math)指明本項目包含一個子目錄math,這樣,math目錄下的CMakeLists.txt文件和源代碼也會被使用,最后一行target_link_libraries指明可執(zhí)行文件需要鏈接一個名為MathFunctions的鏈接庫。math目錄下CMakeLists.txt內(nèi)容如下
# 查找當前目錄下的所有源文件 # 并將名稱保存到 DIR_LIB_SRCS 變量 aux_source_directory(. DIR_LIB_SRCS) # 指定生成 MathFunctions 鏈接庫 add_library (MathFunctions ${DIR_LIB_SRCS})
該文件中使用命令add_library將src目錄中源文件編譯為靜態(tài)鏈接庫
自定義編譯選項
CMake允許為項目增加編譯選項,從而可以根據(jù)用戶的環(huán)境和要求選擇最合適的編譯方案,例如可以將MathFunctions庫設(shè)置為一個可選的庫,如果該選項為ON,則使用該庫定義的函數(shù)來進行運算,否則就調(diào)用標準庫的數(shù)學(xué)函數(shù)庫。 為了實現(xiàn)這樣的目的我們需要在頂層的CMakeLists.txt中添加該選項,其內(nèi)容如下
cmake_minimum_required (VERSION 2.8) # 項目信息 project (Demo4) set(CMAKE_INCLUDE_CURRENT_DIR ON) # 是否使用自己的 MathFunctions 庫 option (USE_MYMATH "Use provided math implementation" ON) # 加入一個配置頭文件,用于處理 CMake 對源碼的設(shè)置 configure_file ( "${PROJECT_SOURCE_DIR}/config.h.in" "${PROJECT_BINARY_DIR}/config.h" ) # 是否加入 MathFunctions 庫 if (USE_MYMATH) include_directories ("${PROJECT_SOURCE_DIR}/math") add_subdirectory (math) set (EXTRA_LIBS ${EXTRA_LIBS} MathFunctions) endif (USE_MYMATH) # 查找當前目錄下的所有源文件 # 并將名稱保存到 DIR_SRCS 變量 aux_source_directory(. DIR_SRCS) # 指定生成目標 add_executable (Demo ${DIR_SRCS}) target_link_libraries (Demo ${EXTRA_LIBS})
其中configure_file命令用于加入一個配置文件config.h,這個文件由CMake從config.h.in生成,通過這樣的機制可以通過預(yù)定義一些參數(shù)和變量來控制代碼的生成,config.h.in內(nèi)容如下:
#cmakedefine USE_MYMATH
其中的option命令添加了一個USE_MYMATH選項,并且默認值為ON。之后根據(jù)USE_MYMATH變量的值決定是否使用我門自己編寫的MathFounctions庫
然后需要更改main.cc文件讓其根據(jù)USE_MYMATH的值確定是否調(diào)用標準庫,內(nèi)容如下:
#include <stdio.h> #include <stdlib.h> #include <config.h> #ifdef USE_MYMATH #include <MathFunctions.h> #else #include <math.h> #endif int main(int argc, char *argv[]) { if (argc < 3){ printf("Usage: %s base exponent \n", argv[0]); return 1; } double base = atof(argv[1]); int exponent = atoi(argv[2]); #ifdef USE_MYMATH printf("Now we use our own Math library. \n"); double result = power(base, exponent); #else printf("Now we use the standard library. \n"); double result = pow(base, exponent); #endif printf("%g ^ %d is %g\n", base, exponent, result); return 0; }
值得注意的是這里引入了一個config.h,這個文件預(yù)定義了 USE_MYMATH 的值。但我們并不直接編寫這個文件,而是由CMake根據(jù)config.h.in自動生成。
最后
這篇文章主要介紹了cmake的簡單使用,更多關(guān)于cmake構(gòu)建系統(tǒng)的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
c++實現(xiàn)一個簡易的網(wǎng)絡(luò)緩沖區(qū)的實踐
這篇文章主要介紹了c++實現(xiàn)一個簡易的網(wǎng)絡(luò)緩沖區(qū)的實踐,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-12-12