CMake簡述
CMake旨在成為一個跨平臺的構(gòu)建流程管理器况木,因此它定義了它自己的腳本語言奋隶,具有一定的語法和內(nèi)置功能饵骨。 CMake本身是一個軟件程序陶贼,因此應(yīng)該使用腳本文件調(diào)用它來解釋和生成實際的構(gòu)建文件啤贩。
開發(fā)人員可以使用CMake語言為項目編寫簡單或復(fù)雜的構(gòu)建腳本。
使用CMake語言構(gòu)建邏輯和定義可以在CMakeLists.txt中編寫拜秧,也可以使用<project_name> .cmake編寫痹屹。 但作為最佳實踐,主腳本命名為CMakeLists.txt而不是cmake枉氮。
- CMakeLists.txt文件位于要構(gòu)建的項目的源文件志衍。
- CMakeLists.txt一般放置在整個工程項目文件夾的根目錄下。
- 如果有多個模塊聊替,并且每個模塊可以單獨編譯和構(gòu)建楼肪,則可以將CMakeLists.txt插入到子文件夾中(本文僅提及單個CMakeLists.txt的示例)。
- cmake文件可以用作腳本佃牛,它運行cmake命令來準(zhǔn)備環(huán)境預(yù)處理或拆分任務(wù)淹辞,這些任務(wù)可以在CMakeLists.txt之外編寫
- cmake文件還可以為項目定義模塊 ,這些項目可以和庫程序文件分離構(gòu)建,也可以是復(fù)雜的多模塊項目的額外方法俘侠。
編寫Makefile可能比編寫CMake腳本更難象缀。 通過語法和邏輯的CMake腳本與高級語言具有相似性,因此開發(fā)人員可以更輕松地創(chuàng)建他們的cmake腳本爷速,而不會在Makefile中迷失央星。
常用的命令:
下文的示例會盡量用到這些命令
- message:打印給定消息
- cmake_minimum_required:設(shè)置要使用的最低的cmake版本
- add_executable:添加具有給定名稱的可執(zhí)行目標(biāo)
- add_library:從列出的源文件中添加要構(gòu)建的庫目標(biāo)
- add_subdirectory:添加一個子目錄來構(gòu)建
還有一些命令可以讓開發(fā)人員編寫條件語句,循環(huán)惫东,迭代列表莉给,分配:
- if, endif
- elif, endif
- while, endwhile
- foreach, endforeach
- list
- return
- set_property(分配值給變量)
縮寫不是強制性的毙石,但在編寫CMake腳本時建議使用。 CMake不使用';'來理解陳述的結(jié)尾颓遏。所有條件語句都應(yīng)該以相應(yīng)的結(jié)束命令結(jié)束(endif徐矩,endwhile,endforeach)CMake的所有這些屬性可幫助開發(fā)人員編寫復(fù)雜的構(gòu)建過程叁幢,包括多個模塊滤灯,庫和平臺。
CMake環(huán)境變量
環(huán)境變量用于配置編譯器標(biāo)志曼玩,鏈接器標(biāo)志鳞骤,常規(guī)構(gòu)建過程的測試配置。 必須引導(dǎo)編譯器搜索庫的給定目錄黍判。
從以下URL可以看到環(huán)境變量的詳細(xì)列表,可以參見一下鏈接:
https://cmake.org/cmake/help/latest/manual/cmake-env-variables.7.html
某些環(huán)境變量被預(yù)定義的CMake變量覆蓋豫尽。 例如 定義CMAKE_CXX_FLAGS時,CXXFLAGS將被覆蓋顷帖。
下面是一個示例用例美旧,當(dāng)您想在編譯過程中啟用所有警告時,您可以編寫-Wall to build命令窟她。 如果使用CMake構(gòu)建代碼陈症,可以使用set命令添加-Wall標(biāo)志。
set(CMAKE_CXX_FLAGS,"-Wall")
defined flags
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
CMake變量
CMake包括預(yù)定義變量震糖,這些變量默認(rèn)設(shè)置為源樹和系統(tǒng)組件的位置。
變量區(qū)分大小寫趴腋,而不是命令吊说。 在變量的定義中,您只能使用字母數(shù)字字符和下劃線优炬,短劃線(_颁井, - )。
您可以在以下URL中找到有關(guān)CMake變量的更多詳細(xì)信息
https://cmake.org/cmake/help/v3.5/manual/cmake-language.7.html#variables
一些變量是根據(jù)根文件夾預(yù)定義的:
- CMAKE_BINARY_DIR:構(gòu)建樹和二進(jìn)制輸出文件夾頂級的完整路徑蠢护,默認(rèn)情況下雅宾,它定義為構(gòu)建樹的頂級。
- CMAKE_HOME_DIRECTORY:HOME目錄頂部的路徑
- CMAKE_SOURCE_DIR:源文件目錄頂級的完整路徑葵硕。
- CMAKE_INCLUDE_PATH:用于查找文件眉抬,路徑的路徑
可以使用$ {<variable_name>}訪問變量值
message("CXX Standard: ${CMAKE_CXX_STANDARD}")
set(CMAKE_CXX_STANDARD 14)
就像上面的變量一樣,您可以定義自己的變量懈凹。 您可以調(diào)用set命令將值設(shè)置為新變量或更改現(xiàn)有變量的值蜀变,如下所示:
set("APP_VERSION","1.0.1")
message("${APP_VERSION}")
CMake 列表
CMake中的所有值都存儲為字符串,但在某些上下文中可以將字符串視為列表介评。
通過連接由半列';'分隔的元素表示為字符串的元素列表
set(files a.txt b.txt c.txt)
# sets files to "a.txt;b.txt;c.txt"
要訪問值列表库北,您可以使用CMake的foreach命令爬舰,如下所示:
foreach(file ${files})
message("Filename: ${file}")
endforeach()
完整的表達(dá)式列表可以看這里
https://cmake.org/cmake/help/v3.8/manual/cmake-generator-expressions.7.html
使用CMake構(gòu)建C ++項目
在前面的部分中,我們介紹了編寫CMake腳本的核心原則寒瓦。 現(xiàn)在情屹,我們可以構(gòu)建一個基本的鏈表為示例。
如圖所示:
很明顯杂腰,對于這樣一個小項目來說垃你,使用CMake是多余的,但是當(dāng)事情變得復(fù)雜時颈墅,它會有很大幫助蜡镶。
為了構(gòu)建main.cpp,在項目的根目錄下創(chuàng)建一個CMakeLists.txt,并且寫入如下代,然后執(zhí)行cmake命令
/**/
cmake_minimum_required(VERSION 3.9.1)
/*設(shè)定項目的名稱*/
project(cmake_tor)
/*我們編譯的目標(biāo)文件*/
add_executable(cmake_tor main.cpp)
然后在vscode終端中使用運行cmake命令,CMake會生成如下文件和目錄
- Makefile腳本,這個是我們執(zhí)行對編譯后的程序,執(zhí)行tarball安裝方式的 時候需要用到make腳本恤筛。
- CMakeCache.txt:這個是CMake會根據(jù)你的開發(fā)環(huán)境自動生成一些腳本的預(yù)設(shè)配置官还。如果當(dāng)前的預(yù)設(shè)配置不符合你的要求,從該文件拷貝相關(guān)的配置條目到CMakeLists.txt,修改配置選項后,重新執(zhí)行一次cmake即可生成符合你需求的配置。
-
CMakeFiles目錄:里面包含日志文件和一些臨時的二進(jìn)制文件,一般我們是不用理會的.
問題導(dǎo)入
我們的目的是生成一個二進(jìn)制文件毒坛,但我們這里首先看一下剛才配置有哪些不足之處望伦?
- 首先,我們希望cmake生成的文件放到一個指定的目錄里面,這樣我們的項目不至于雜亂無章。
- 其次,我希望能夠使用自己指定的C/C++編譯器,而不是cmake預(yù)定義的操作系統(tǒng)默認(rèn)的編譯器煎殷。
- 最后,希望執(zhí)行make命令的時候,編譯后的可執(zhí)行程序和庫文件存放到一個有別于其他cmake文件夾的特殊目錄屯伞。
下面先看看我們之后改進(jìn)的項目目錄結(jié)構(gòu),如下圖,這是更符合我們實際開發(fā)工作中的一個目錄結(jié)構(gòu)。
那么豪直,我們帶著這三個問題定制自己的CMake配置方案吧劣摇!
首先,我們在項目的根目錄先手動創(chuàng)建一個build的文件夾,在VSCode的終端重定向到build目錄之下.
$ mkdir build
$ cd build
然后,在CMakeLists.txt使用以下cmake腳本,每個腳本的語句,代碼中有注解
cmake_minimum_required(VERSION 3.1.0)
#設(shè)定c編譯器和c++編譯器,必須放在整個腳本的開頭
set(CMAKE_C_COMPILER /usr/local/bin/gcc)
set(CMAKE_CXX_COMPILER /usr/local/bin/g++)
#工程項目的名稱
project(cmake_tor)
#包含headers和source目錄
include_directories(
"${PROJECT_SOURCE_DIR}/headers"
"${PROJECT_SOURCE_DIR}/source"
)
# 修正在macOS下CMAKE_CXX_STANDARD判斷C++編譯器標(biāo)準(zhǔn)的
#出錯的bug,如果你用到是Windows/Linux系統(tǒng),可以忽略這條語句
if (POLICY CMP0025)
cmake_policy(SET CMP0025 NEW)
endif ()
#讓CMake自動檢測gcc的支持的c++標(biāo)準(zhǔn),
#根據(jù)CMake的版本號判斷它所支持c++標(biāo)準(zhǔn)
if(CMAKE_VERSION VERSION_LESS "3.8")
set(CMAKE_CXX_STANDARD 14)
message("The compile ${CMAKE_CXX_COMPILER} use C++14 standard!!")
elseif(CMAKE_VERSION VERSION_LESS "3.11")
set(CMAKE_CXX_STANDARD 17)
message("The compile ${CMAKE_CXX_COMPILER} use C++17 standard!!")
else()
set(CMAKE_CXX_STANDARD 20)
message("The compile ${CMAKE_CXX_COMPILER} use C++20 standard!!")
endif()
set(CMAKE_CXX_EXTENSIONS OFF)
#構(gòu)建自己的軟件系統(tǒng)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/app)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/libs)
add_executable(main "${PROJECT_SOURCE_DIR}/source/main.cpp")
add_library(shape SHARED "${PROJECT_SOURCE_DIR}/source/shape.c")
最后執(zhí)行cmake和make弓乙,我們會發(fā)現(xiàn)如下圖,正如我們所愿在指定的目錄下生成了一個可執(zhí)行文件和共享對象文件
$ cmake
$ make
結(jié)束語:
第一次接觸CMake的同學(xué),可能覺得無從入手,單獨花上一段時間去完全掌握它得不償失,本文是對以前遇到的一些典型問題做成一個易懂的教程末融。
帶著問題去stackflow尋找一些相關(guān)問題的答案是很好的學(xué)習(xí)方法之一,至少你在碰壁的時候,不會為了某個方面迷失了自我,然后自己去根據(jù)前人提供的建議去實踐并歸納到一個文件里,這樣就變成你自己已經(jīng)掌握的技能了。
技術(shù)文~~分享至此,希望你喜歡暇韧。