紙上學(xué)來(lái)終覺(jué)淺,覺(jué)知此時(shí)要躬行。學(xué)習(xí)一項(xiàng)技術(shù)最好的武器就是去實(shí)踐和復(fù)盤(pán)。接觸cmake有一年多了,但是真正學(xué)會(huì)cmake也是在用cmake編譯項(xiàng)目的過(guò)程中,逐漸掌握了這門(mén)技術(shù)。本文想帶著讀者從一個(gè)小的點(diǎn)開(kāi)始逐漸完善,最后做出一個(gè)涵蓋絕大部分功能和滿足日常需求的cmake demo工程。作者將在github中新建一個(gè)新的倉(cāng)庫(kù),然后逐漸向上提交代碼。最后作者會(huì)開(kāi)源本項(xiàng)目的github網(wǎng)址,讀者可以自行根據(jù)commit版本提示找到每一部分的源碼。
二.增量開(kāi)發(fā)打造一個(gè)cmake demo 2.1 github 版本管理的使用在這里我要安利一下,前些天寫(xiě)的這篇github教程。涵蓋從進(jìn)課題組開(kāi)始,完成項(xiàng)目所需要的所有日常指令。有需要的朋友可以參考一下。
四個(gè)指令玩轉(zhuǎn)git
sudo apt install cmake# ubuntu16.04 默認(rèn) 3.0.5
最基本的項(xiàng)目是將一個(gè)源代碼文件生成可執(zhí)行文件。對(duì)于這么簡(jiǎn)單的項(xiàng)目,只需要一個(gè)三行的 CMakeLists.txt 文件即可,這是本篇教程的起點(diǎn)。在 目錄中創(chuàng)建一個(gè) CMakeLists.txt 文件,如下所示:
cmake_minimum_required(VERSION 3.0)
# set the project name
project(Tutorial)
# add the executable
add_executable(Tutorial tutorial.cpp)
cmake_minimum_required 指定使用 CMake 的最低版本號(hào),project 指定項(xiàng)目名稱,add_executable 用來(lái)生成可執(zhí)行文件,需要指定生成可執(zhí)行文件的名稱和相關(guān)源文件。
注意,此示例在 CMakeLists.txt 文件中使用小寫(xiě)命令。CMake 支持大寫(xiě)、小寫(xiě)和混合大小寫(xiě)命令。tutorial.cpp 文件在commit first目錄中,可用于計(jì)算數(shù)字的平方根。
// tutorial.cpp
#include#include#include#includeint main(int argc, char* argv[])
{if (argc< 2) {std::cout<< "Usage: "<< argv[0]<< " number"<< std::endl;
return 1;
}
// convert input to double
const double inputValue = atof(argv[1]);
// calculate square root
const double outputValue = sqrt(inputValue);
std::cout<< "The square root of "<< inputValue
<< " is "<< outputValue
<< std::endl;
return 0;
}
mkdir build
cd build
cmake ..
cmake --build .
可執(zhí)行文件Tutorial就在build目錄下。
zzy@zzy-virtual-machine:~/LearnCmake/build$ ./Tutorial 5
The square root of 5 is 2.23607
2.3 優(yōu)化 CMakeLists.txt 文件之前CMakeList.txt如下:
cmake_minimum_required(VERSION 3.0)
# set the project name
project(Tutorial)
# add the executable
add_executable(Tutorial tutorial.cpp)
指定了項(xiàng)目名后,后面可能會(huì)有多個(gè)地方用到這個(gè)項(xiàng)目名,如果更改了這個(gè)名字,就要改多個(gè)地方,比較麻煩,那么可以使用 == PROJECT_NAME== 來(lái)表示項(xiàng)目名。
add_executable(${PROJECT_NAME} tutorial.cpp)
生成可執(zhí)行文件需要指定相關(guān)的源文件,如果有多個(gè),那么就用空格隔開(kāi),比如:
add_executable(${PROJECT_NAME} test1.cpp test2.cpp test3.cpp)
我們也可以用一個(gè)變量來(lái)表示這多個(gè)源文件:
set(SRC_LIST test1.cpp test2.cpp test3.cpp )
add_executable(${PROJECT_NAME} ${SRC_LIST})
set 命令指定SRC_LIST變量來(lái)表示多個(gè)源文件,用 ${var_name} 獲取變量的值。
于是原來(lái)的 CMakeLists.txt 文件就可以變成如下所示:
cmake_minimum_required(VERSION 3.0)
# set the project name
project(Tutorial)
SET(SRC_LIST tutorial.cpp)
# add the executable
add_executable(${PROJECT_NAME} ${SRC_LIST})
這樣可配置性就增強(qiáng)了很多,有利于后續(xù)項(xiàng)目擴(kuò)展。
我們可以在 CMakeLists.txt 為可執(zhí)行文件和項(xiàng)目提供一個(gè)版本號(hào)。首先,修改 CMakeLists.txt 文件,使用 project 命令設(shè)置項(xiàng)目名稱和版本號(hào)。
cmake_minimum_required(VERSION 3.0)
# set the project name and version
project(Tutorial VERSION 1.0)
configure_file(TutorialConfig.h.in TutorialConfig.h)//配置頭文件將版本號(hào)傳遞給源代碼
由于 TutorialConfig.h 文件會(huì)被自動(dòng)寫(xiě)入 build 目錄,因此必須將該目錄添加到搜索頭文件的路徑列表中。將以下行添加到 CMakeLists.txt 文件的末尾:
target_include_directories(${PROJECT_NAME} PUBLIC
${PROJECT_BINARY_DIR}
)
安裝剛才的方式用cmake … 構(gòu)建項(xiàng)目的過(guò)程中會(huì)在build目錄中生成TutorialConfig.h
#define Tutorial_VERSION_MAJOR 1
#define Tutorial_VERSION_MINOR 0
下一步在 tutorial.cpp 包含頭文件 TutorialConfig.h,最后通過(guò)以下代碼打印出可執(zhí)行文件的名稱和版本號(hào)。
if (argc< 2) { // report version
std::cout<< argv[0]<< " Version "<< Tutorial_VERSION_MAJOR<< "."
<< Tutorial_VERSION_MINOR<< std::endl;
std::cout<< "Usage: "<< argv[0]<< " number"<< std::endl;
return 1;
}
接下來(lái)將tutorial.cpp 源碼中的 atof 替換為 std::stod,這是 C++11 的特性。
const double inputValue = std::stod(argv[1]);
在 CMake 中支持特定 C++標(biāo)準(zhǔn)的最簡(jiǎn)單方法是使用 CMAKE_CXX_STANDARD 標(biāo)準(zhǔn)變量。在 CMakeLists.txt 中設(shè)置CMAKE_CXX_STANDARD為11,CMAKE_CXX_STANDARD_REQUIRED設(shè)置為T(mén)rue。確保在 add_executable 命令之前添加CMAKE_CXX_STANDARD_REQUIRED命令。
# specify the C++ standard
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
此時(shí)完整的CMakeList.txt
cmake_minimum_required(VERSION 3.0)
# set the project name
project(Tutorial VERSION 1.0)
# specify the C++ standard
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
configure_file(TutorialConfig.h.in TutorialConfig.h)
SET(SRC_LIST tutorial.cpp)
# add the executable
add_executable(${PROJECT_NAME} ${SRC_LIST})
target_include_directories(${PROJECT_NAME} PUBLIC
${PROJECT_BINARY_DIR}
)
根據(jù)剛才的方法編譯運(yùn)行
zzy@zzy-virtual-machine:~/LearnCmake/build$ ./Tutorial 5
The square root of 5 is 2.23607
zzy@zzy-virtual-machine:~/LearnCmake/build$ ./Tutorial
./Tutorial Version 1.0
Usage: ./Tutorial number
代碼保存在github commit second版本中
Author: zzy<825830916@qq.com>Date: Sun Dec 4 20:03:34 2022 +0800
commit second
commit f5d7e8288b3956fa78028dec6fbb3d0268cfbbb0
Author: zzy<825830916@qq.com>Date: Sun Dec 4 19:37:38 2022 +0800
commit first
2.4 添加庫(kù)現(xiàn)在我們將向項(xiàng)目中添加一個(gè)庫(kù),這個(gè)庫(kù)包含計(jì)算數(shù)字平方根的實(shí)現(xiàn),可執(zhí)行文件使用這個(gè)庫(kù),而不是編譯器提供的標(biāo)準(zhǔn)平方根函數(shù)。
我們把庫(kù)放在名為 MathFunctions 的子目錄中。此目錄包含頭文件 MathFunctions.h 和源文件 mysqrt.cpp。源文件有一個(gè)名為 mysqrt 的函數(shù),它提供了與編譯器的 sqrt 函數(shù)類似的功能,MathFunctions.h 則是該函數(shù)的聲明。
在 MathFunctions 目錄下創(chuàng)建一個(gè) CMakeLists.txt 文件,并添加以下一行:
add_library(MathFunctions mysqrt.cpp)
為了使用== MathFunctions== 這個(gè)庫(kù),我們將在頂級(jí) CMakeLists.txt 文件中添加一個(gè)add_subdirectory(MathFunctions)命令指定庫(kù)所在子目錄,該子目錄下應(yīng)包含 CMakeLists.txt 文件和代碼文件。
可執(zhí)行文件要使用庫(kù)文件,需要能夠找到庫(kù)文件和對(duì)應(yīng)的頭文件,可以分別通過(guò)target_link_libraries和target_include_directories來(lái)指定。
使用target_link_libraries將新的庫(kù)文件添加到可執(zhí)行文件中,使用target_include_directories將 MathFunctions 添加為頭文件目錄,添加到 Tutorial 目標(biāo)上,以便 mysqrt.h 可以被找到。
然后在測(cè)試文件中把函數(shù)名設(shè)置為mysqrt。
const double outputValue = mysqrt(inputValue);
完整的CMakeList.txt
cmake_minimum_required(VERSION 3.0)
# set the project name
project(Tutorial VERSION 1.0)
# specify the C++ standard
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
configure_file(TutorialConfig.h.in TutorialConfig.h)
SET(SRC_LIST tutorial.cpp)
add_subdirectory(MathFunctions)
# add the executable
add_executable(${PROJECT_NAME} ${SRC_LIST})
target_link_libraries(${PROJECT_NAME} PUBLIC MathFunctions)
target_include_directories(${PROJECT_NAME} PUBLIC
${PROJECT_BINARY_DIR}
${PROJECT_SOURCE_DIR}/MathFunctions
)
安裝剛才的方式編譯運(yùn)行,可以得到。
zzy@zzy-virtual-machine:~/LearnCmake/build$ ./Tutorial 5
Computing sqrt of 5 to be 3
Computing sqrt of 5 to be 2.33333
Computing sqrt of 5 to be 2.2381
Computing sqrt of 5 to be 2.23607
Computing sqrt of 5 to be 2.23607
Computing sqrt of 5 to be 2.23607
Computing sqrt of 5 to be 2.23607
Computing sqrt of 5 to be 2.23607
Computing sqrt of 5 to be 2.23607
Computing sqrt of 5 to be 2.23607
The square root of 5 is 2.23607
代碼在github倉(cāng)庫(kù)提交版本 commit third中
2.5 將庫(kù)設(shè)置為可選選項(xiàng)現(xiàn)在將 MathFunctions 庫(kù)設(shè)為可選的,雖然對(duì)于本教程來(lái)說(shuō),功能已經(jīng)完成了,但對(duì)于較大的項(xiàng)目來(lái)說(shuō),這種情況很常見(jiàn)。
第一步是向頂級(jí) CMakeLists.txt 文件添加一個(gè)選項(xiàng)。
option(USE_MYMATH "Use tutorial provided math implementation" ON)
option表示提供用戶可以選擇的選項(xiàng)。命令格式為:option( "description [initial value])。
==USE_MYMATH ==這個(gè)選項(xiàng)缺省值為 ON,用戶可以更改這個(gè)值。此設(shè)置將存儲(chǔ)在緩存中,以便用戶不需要在每次構(gòu)建項(xiàng)目時(shí)設(shè)置該值。
下一個(gè)更改是使 MathFunctions 庫(kù)的構(gòu)建和鏈接成為條件。于是創(chuàng)建一個(gè) if 語(yǔ)句,該語(yǔ)句檢查選項(xiàng)USE_MYMATH的值。
在 if 塊中,有 add_subdirectory 命令和 list 命令,APPEND表示將元素MathFunctions追加到列表EXTRA_LIBS中,將元素 ${PROJECT_SOURCE_DIR}/MathFunctions 追加到列表EXTRA_INCLUDES中。EXTRA_LIBS 存儲(chǔ) MathFunctions 庫(kù),EXTRA_INCLUDES 存儲(chǔ) MathFunctions 頭文件。
變量EXTRA_LIBS用來(lái)保存需要鏈接到可執(zhí)行程序的可選庫(kù),變量EXTRA_INCLUDES用來(lái)保存可選的頭文件搜索路徑。這是處理可選組件的經(jīng)典方法,我將在下一步介紹現(xiàn)代方法。
接下來(lái)對(duì)源代碼的進(jìn)行修改。首先,在 tutorial.cpp 中包含 MathFunctions.h 頭文件,
然后,還在 tutorial.cpp 中,使用 USE_MYMATH 選擇使用哪個(gè)平方根函數(shù):
#ifdef USE_MYMATH
#include "MathFunctions.h"
#endif
#ifdef USE_MYMATH
const double outputValue = mysqrt(inputValue);
#else
const double outputValue = sqrt(inputValue);
#endif
因?yàn)樵创a使用了 USE_MYMATH 宏,可以用下面的行添加到 tutorialconfig.h.in 文檔中:
// TutorialConfig.h.in
#cmakedefine USE_MYMATH
完整的CMakeLists如下:
cmake_minimum_required(VERSION 3.0)
# set the project name
project(Tutorial VERSION 1.0)
# specify the C++ standard
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
configure_file(TutorialConfig.h.in TutorialConfig.h)
SET(SRC_LIST tutorial.cpp)
if(USE_MYMATH)
add_subdirectory(MathFunctions)
list(APPEND EXTRA_LIBS MathFunctions)
list(APPEND EXTRA_INCLUDES ${PROJECT_SOURCE_DIR}/MathFunctions)
endif()
# add the executable
add_executable(${PROJECT_NAME} ${SRC_LIST})
target_link_libraries(${PROJECT_NAME} PUBLIC ${EXTRA_LIBS})
target_include_directories(${PROJECT_NAME} PUBLIC
${PROJECT_BINARY_DIR}
${EXTRA_INCLUDES}
)
option(USE_MYMATH "Use tutorial provided math implementation" ON)
測(cè)試:
zzy@zzy-virtual-machine:~/LearnCmake/build$ cmake .. -USE_MYMATH=OFF
zzy@zzy-virtual-machine:~/LearnCmake/build$ ./Tutorial 5
The square root of 5 is 2.23607
代碼在commit four版本中
commit 31e20019090c3fc6b0edc4e1bb96a56d818b63ee
Author: zzy<825830916@qq.com>Date: Sun Dec 4 20:27:57 2022 +0800
commit four
commit a48dbcd622b99708dd4fac0af6e82a769737b7bf
Author: zzy<825830916@qq.com>Date: Sun Dec 4 20:16:35 2022 +0800
third commit
commit 14a1b053935e4d2d2036044470b3efcd86600010
Author: zzy<825830916@qq.com>Date: Sun Dec 4 20:03:34 2022 +0800
commit second
commit f5d7e8288b3956fa78028dec6fbb3d0268cfbbb0
Author: zzy<825830916@qq.com>Date: Sun Dec 4 19:37:38 2022 +0800
commit first
三.結(jié)語(yǔ)到這里整個(gè)教程就結(jié)束了,教程源碼在https://github.com/tongjiaxuan666/CmakeLearn
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購(gòu),新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧