cmake跨平臺(tái)構(gòu)建工具的學(xué)習(xí)筆記
前言
CMake是一個(gè)跨平臺(tái)的安裝編譯工具,可以用簡單的語句來描述所有平臺(tái)的安裝(編譯過程)。
CMake可以說已經(jīng)成為大部分C++開源項(xiàng)目標(biāo)配
因此,作為一名C C++發(fā)開人員,看到cmake不應(yīng)該一臉茫然…
作為初學(xué)者,通俗的認(rèn)為cmake就是一個(gè)linux下自動(dòng)構(gòu)建makefile等文件的實(shí)用工具!
廣泛使用cmake的原因: 跨平臺(tái)開發(fā)方便共享操作,使寫Makefile更簡便;
跨平臺(tái)開發(fā)
假設(shè)有一個(gè)跨平臺(tái)項(xiàng)目,其中C++代碼可能會(huì)在不同的OS系統(tǒng)/IDE上共享;
Win下的VSLinux下的gccMAC下的Xcode
當(dāng)我們想添加一個(gè)bar.cpp 的源文件,我們就需要將其添加到各種OS使用的每個(gè)工具中:
為了保持運(yùn)行環(huán)境的一致性,則必須多次進(jìn)行類似的更新,還必須手動(dòng)執(zhí)行(在本例中,圖中用紅色標(biāo)記的箭頭)。
這種方法因?yàn)槭謩?dòng)也容易出錯(cuò),而且不靈活。
CMake通過在開發(fā)過程中添加額外的步驟來解決這個(gè)設(shè)計(jì)缺陷。
您可以在CMakeLists.txt文件中描述您的項(xiàng)目,并使用CMake自動(dòng)生成構(gòu)建項(xiàng)目的工具,使用跨平臺(tái)CMake代碼:
同樣的操作-添加新的bar.cpp文件,現(xiàn)在只需一步即可完成:
跨平臺(tái)的性質(zhì)沒有變,照樣有很多不同的OS在共享代碼,但是只需要一個(gè)cmake可以很好地維護(hù)起來;
CMake語法特性
基本語法格式:指令(參數(shù) 1 參數(shù) 2…)
- 參數(shù)使用括號括起
- 參數(shù)之間使用空格或分號分開(這里有點(diǎn)違背我們用逗號分隔參數(shù)的習(xí)慣)
指令是大小寫無關(guān)的,參數(shù)和變量是大小寫相關(guān)的
語法指令部分有點(diǎn)像SQL,是大小寫無關(guān)的
set(HELLO hello.cpp) # 設(shè)置變量HELLO的函數(shù),后續(xù)會(huì)介紹 # 下面兩條指令等價(jià) add_executable(hello main.cpp hello.cpp) ADD_EXECUTABLE(hello main.cpp ${HELLO})
變量使用${}方式取值,但是在 if 條件控制語句中應(yīng)直接使用變量名
CMake重要指令和常用變量
重要指令
cmake版本,項(xiàng)目工程,變量的設(shè)置:
cmake_minimum_required - 指定CMake的最小版本要求
# 語法:cmake_minimum_required(VERSION versionNumber [FATAL_ERROR]) # CMake最小版本要求為2.8.3 2cmake_minimum_required(VERSION 2.8.3)
linux下 cmake --version查看自己的cmake版本
project - 定義工程名稱,并可指定工程支持的語言
# 語法:project(projectname [CXX] [C] [Java]) -- 方框中的為可選項(xiàng) # 指定工程名為HELLOWORLD project(HELLOWORLD)
set - 顯式的定義變量
# 語法:set(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]]) # 定義SRC變量,其值為main.cpp hello.cpp set(SRC sayhello.cpp hello.cpp) #注意參數(shù)之間 空格/; 分隔哦!
頭文件的設(shè)置,庫文件的路徑,庫文件的生成,庫文件的鏈接:
include_directories - 向工程添加多個(gè)特定的 頭 文 件 搜索路徑 —>相當(dāng)于指定g++編譯器的-I(大寫i)參數(shù)
(有了動(dòng)態(tài)庫和靜態(tài)庫,當(dāng)然有對應(yīng)他的頭文件了)
# 語法:include_directories([AFTER|BEFORE] [SYSTEM] dir1 dir2 …) # 將/usr/include/myincludefolder 和 ./include 添加到頭文件搜索路徑中 include_directories(/usr/include/myincludefolder ./include)
link_directories - 向工程添加多個(gè)特定的 庫 文 件 搜索路徑 —>相當(dāng)于指定g++編譯器的-L參數(shù)
# 語法:link_directories(dir1 dir2 …) # 將/usr/lib/mylibfolder 和 ./lib 添加到庫文件搜索路徑中 link_directories(/usr/lib/mylibfolder ./lib)
add_library - 生成共享庫文件
# 語法:add_library(libname [SHARED|STATIC|MODULE] [EXCLUDE_FROM_ALL] source1 source2 … sourceN) # 通過變量 SRC 生成 libhello.so 共 享 動(dòng)態(tài)庫hello,通過 (SHARED | STATIC)來選擇 add_library(hello SHARED ${SRC}) # 通過src/Swap.cpp 生成 libswap_library.a 共 享 靜態(tài)庫swap_library,通過 (SHARED | STATIC)來選擇 add_library( swap_library STATIC src/Swap.cpp )
target_link_libraries - 為 target 添加需要鏈接的共享庫 —>相同于指定g++編譯器-l(小L)參數(shù)
# 語法:target_link_libraries(target library1library2…) # 將hello動(dòng)態(tài)庫文件鏈接到可執(zhí)行文件main target_link_libraries(main hello)
編譯參數(shù)選擇,編譯生成exe:
add_compile_options - 添加編譯參數(shù) -->相當(dāng)于g++編譯器 -std=c++11 -O2…
# 語法:add_compile_options(xxxx); # 添加編譯參數(shù) -std=c++11 -O2 add_compile_options(-std=c++11 -O2)
add_executable - 生成可執(zhí)行文件(最重要的一步,如果沒可執(zhí)行程序怎么運(yùn)行?)
# 語法:**add_library(exename source1 source2 … sourceN)** # 編譯main.cpp生成可執(zhí)行文件main add_executable(main main.cpp)
其他工程源文件管理等雜項(xiàng):
add_subdirectory - 向當(dāng)前工程 添加 存放源文件的子目錄,并可以指定中間二進(jìn)制和目標(biāo)二進(jìn)制存放的位置 – 多目錄工程
# 語法:add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL]) # 添加src子目錄,src中需有一個(gè)CMakeLists.txt add_subdirectory(src)
aux_source_directory - 發(fā)現(xiàn)一個(gè)目錄下 所有的源代碼文件 并將列表 存儲(chǔ)在 一個(gè) 變量中,這個(gè)指令臨時(shí)被用來自動(dòng)構(gòu)建源文件列表
# 語法:aux_source_directory(dir VARIABLE) # 定義SRC變量,其值為當(dāng)前目錄下所有的源代碼文件 aux_source_directory(. SRC) #配合src, 編譯SRC變量所代表的源代碼文件,生成main可執(zhí)行文件 add_executable(main ${SRC})
常用變量
CMAKE_C_FLAGS gcc編譯選項(xiàng)
CMAKE_CXX_FLAGS g++編譯選項(xiàng)
# 利用set(), 在CMAKE_CXX_FLAGS編譯選項(xiàng)后追加-std=c++11 set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
CMAKE_BUILD_TYPE 編譯類型(Debug, Release)
#利用set(), 設(shè)定編譯類型為debug,調(diào)試時(shí)需要選擇debug set(CMAKE_BUILD_TYPE Debug) # 設(shè)定編譯類型為release,發(fā)布時(shí)需要選擇release set(CMAKE_BUILD_TYPE Release)
下面幾個(gè)自己玩:
- CMAKE_C_COMPILER:指定C編譯器
- CMAKE_CXX_COMPILER:指定C++編譯器
- EXECUTABLE_OUTPUT_PATH:可執(zhí)行文件輸出的存放路徑
- LIBRARY_OUTPUT_PATH:庫文件輸出的存放路徑
下面幾個(gè)了解一下:
- CMAKE_BINARY_DIR
- PROJECT_BINARY_DIR
- <projectname>__BINARY_DIR
這三個(gè)變量指代的內(nèi)容是一致的。
如果是 in source build(內(nèi)部構(gòu)建),指的就是工程頂層目錄。
如果是 out-of-source(外部構(gòu)建 --推薦使用), 指的是工程編譯發(fā)生的目錄。
PROJECT_BINARY_DIR 跟其他指令稍有區(qū)別,不過現(xiàn)在,你可以理解為他們是一致的。
CMAKE_SOURCE_DIR
PROJECT_SOURCE_DIR
<projectname>__SOURCE_DIR
這三個(gè)變量指代的內(nèi)容是一致的,不論采用何種編譯方式,都是工程頂層目錄。
也就是在 in source build時(shí),他跟 CMAKE_BINARY_DIR 等變量一致。
PROJECT_SOURCE_DIR 跟其他指令稍有區(qū)別,現(xiàn)在,你可以理解為他們是一致的。
CMake編譯工程
CMake目錄結(jié)構(gòu):項(xiàng)目主目錄(各種.c.h等源碼的項(xiàng)目目錄),存在一個(gè)CMakeLists.txt文件
兩種方式設(shè)置編譯規(guī)則:
包含源文件的子文件夾包含CMakeLists.txt文件,主目錄的CMakeLists.txt通過add_subdirectory添加子目錄(這個(gè)子目錄也包含一個(gè)CMakeLists.txt)即可;
-相當(dāng)于 多目錄 的工程,好多目錄有好多.c .h
包含源文件的子文件夾未包含CMakeLists.txt文件,子目錄編譯規(guī)則就只體現(xiàn)在主目錄的CMakeLists.txt中;
相當(dāng)于只有一個(gè)主目錄的CMakeLists.txt文件 – 單目錄工程;
兩種構(gòu)建方式 內(nèi)部構(gòu)建(in-source build):不推薦使用
內(nèi)部構(gòu)建會(huì)在源文件的同級目錄下產(chǎn)生一大堆中間文件,這些中間文件并不是我們最終所需要的,和工程源文件放在一起會(huì)顯得雜亂無章。
## 內(nèi)部構(gòu)建 # 在當(dāng)前項(xiàng)目主目錄下,編譯本目錄的CMakeLists.txt,生成Makefile等文件 cmake . # 在哪個(gè)目錄下調(diào)用cmake,生成的中間文件就會(huì)存在這個(gè)目錄下,和CMakeLists.txt位置無關(guān) # 執(zhí)行make命令,生成target可執(zhí)行程序 make
外部構(gòu)建(out-of-source build):推薦使用
將編譯輸出文件與源文件放到不同目錄中,這樣源文件中的代碼結(jié)構(gòu)不會(huì)變化太多,清晰明了;
## 外部構(gòu)建 # 1. 在當(dāng)前目錄下,創(chuàng)建build文件夾 mkdir build # 2. 進(jìn)入到build文件夾 cd build # 3. 編譯上級目錄的CMakeLists.txt,生成Makefile和其他文件 cmake .. # 在哪個(gè)目錄下調(diào)用cmake,生成的中間文件就會(huì)存在這個(gè)目錄下,和CMakeLists.txt位置無關(guān) # 4. 執(zhí)行make命令,生成target make
編譯實(shí)戰(zhàn)
hello.hpp
#pragma once #include<iostream> using namespace std; void Print() { cout<<"Hello CMake!"<<endl; }
test.cpp
#include"hello.hpp" int main() { Print(); return 0; }
可以看到,我們目的是main調(diào)用hello.hpp里的Print()函數(shù),打印Hello CMake;
這里將hello.hpp文件放在 與test.cpp源文件同級目錄的inculde目錄下;
這樣#include"hello.hpp"如果不指定include目錄就會(huì)找不到; (正確寫法:#include"./include/hello.hpp")
CMakeLists.txt
這里也能體現(xiàn)出來cmake簡化了構(gòu)建Makefile的過程(項(xiàng)目越大,越復(fù)雜 cmake的簡化作用越明顯)!
cmake_minimum_required(VERSION 2.8) #指定最小版本 project(HelloCMake) #指定工程名字 include_directories(./include) #添加頭文件路徑 -->等價(jià)于 g++ xxx -Iinclude add_executable(hello test.cpp) #編譯生成可執(zhí)行程序 -->等價(jià)于g++ -o hello test.cpp
內(nèi)部構(gòu)建
當(dāng)前目錄結(jié)構(gòu):
我們在當(dāng)前目錄下直接運(yùn)行:cmake . 生成 Makefile,并且make,運(yùn)行程序:
運(yùn)行后的源文件主目錄結(jié)構(gòu):
可以看到,內(nèi)部構(gòu)建除了之前的工程源文件之外,多了一些cmake編譯產(chǎn)生的中間文件,工程業(yè)務(wù)龐大可能會(huì)造成混淆,所以我們不建議這種方法;
外部構(gòu)建
當(dāng)前目錄結(jié)構(gòu):
我們在當(dāng)前目錄 下 的build目錄下 運(yùn)行:cmake … 生成 Makefile,并且make,運(yùn)行程序:
運(yùn)行后的build目錄結(jié)構(gòu):
運(yùn)行后的源文件主目錄結(jié)構(gòu):
可以看到,外部構(gòu)建之前的源文件主目錄沒有新的cmake中間文件結(jié)合進(jìn)來,那些文件去了我們可以設(shè)置的build目錄中,與源文件區(qū)分開了,所以我們建議這種方法;
當(dāng)然,可以通過其他的cmake操作或者bash指令,將生成的Makefile或者可執(zhí)行程序進(jìn)行output從build目錄中移動(dòng)到別的指定目錄,而且別忘了還有.sh shell腳本;
小結(jié)
cmake的好處:
- 跨平臺(tái)開發(fā)的時(shí)候,cmake相當(dāng)于對編譯過程進(jìn)行了二次封裝,提高了該工程的跨平臺(tái)性,各種OS的上策被cmake統(tǒng)一管理,方便了類似添加源文件等一系列改動(dòng);
- 簡化了生成Makefile等構(gòu)建工程文件的復(fù)雜度!
(我們借助這種好的工具,便于管理構(gòu)建項(xiàng)目,讓我們更多專注于業(yè)務(wù)的開發(fā),只能說大老牛,真香~)
到此這篇關(guān)于cmake跨平臺(tái)構(gòu)建工具的文章就介紹到這了,更多相關(guān)cmake跨平臺(tái)構(gòu)建工具內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++ SOCKET多線程實(shí)現(xiàn)聊天小程序
這篇文章主要為大家詳細(xì)介紹了C++ SOCKET多線程實(shí)現(xiàn)聊天小程序,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-06-06詳解設(shè)計(jì)模式中的Command命令模式及相關(guān)C++實(shí)現(xiàn)
這篇文章主要介紹了詳解設(shè)計(jì)模式中的Command命令模式及相關(guān)C++實(shí)現(xiàn),命令模式強(qiáng)調(diào)調(diào)用操作的對象和操作的具體實(shí)現(xiàn)者之間的解耦,需要的朋友可以參考下2016-03-03c++中l(wèi)og4cplus日志庫使用的基本步驟和示例代碼
這篇文章主要給大家介紹了關(guān)于c++中l(wèi)og4cplus日志庫使用的相關(guān)資料,log4cplus是一款開源的c++日志庫,具有線程安全,靈活,以及多粒度控制的特點(diǎn),log4cplus可以將日志按照優(yōu)先級進(jìn)行劃分,使其可以面向程序的調(diào)試,運(yùn)行,測試,后期維護(hù)等軟件全生命周期,需要的朋友可以參考下2024-06-06VS2010+Opencv+MFC讀取圖像和視頻顯示在Picture控件
這篇文章主要為大家詳細(xì)介紹了VS2010+Opencv+MFC讀取圖像和視頻顯示在Picture控件,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-08-08詳解基于C++實(shí)現(xiàn)約瑟夫環(huán)問題的三種解法
約瑟夫環(huán)問題是算法中相當(dāng)經(jīng)典的一個(gè)問題,其問題理解是相當(dāng)容易的,并且問題描述有非常多的版本,并且約瑟夫環(huán)問題還有很多變形,通過這篇約瑟夫問題的講解,一定可以帶你理解透徹2021-06-06