輿情監(jiān)測系統(tǒng)永久免費seo整站優(yōu)化哪家專業(yè)
在Linux系統(tǒng)下,經(jīng)常使用CMakeLists.txt文件來鏈接、編譯C++工程,大部分人clone的代碼里都是有CMakeLists.txt文件的,只需要cmake ..
和make
就完事了,但在工作中,你必須要有從無到有編寫CMakeLists.txt文件的能力。
一、簡單CMakeLists.txt文件的編寫
1.先看文件目錄
在repository4文件夾下存在好幾個C++相關的文件和一個CMakeLIsts.txt文件,文件清單如下表:
文件(夾)名 | 文件(夾)類型/用途 |
---|---|
repository4 | 工程文件夾 |
calc.h | 頭文件,聲明了幾個函數(shù)定義 |
add.cpp/div.cpp/mult.cpp/sub.cpp | 頭文件中聲明的函數(shù)的實現(xiàn) |
test_calc.cpp | 調用前面實現(xiàn)的幾個函數(shù) |
CMakeLists.txt | 編寫此文件,用于此工程的鏈接和編譯 |
以上除CMakeLists.txt文件以外的文件自己在保證調用、語法、功能正確的前提下隨便編寫。
2.編寫CMakeLists.txt文件
(1)編寫簡單CMakeLists.txt文件的流程
(2)編寫簡單CMakeLists.txt文件
cmake_minimum_required(VERSION 3.16) #cmake最低版本要求,不得高于你計算機安裝的版本set(CMAKE_CXX_STANDARD 11) #指定C++標準project(test_calculate) #設置項目名稱“test_calculate”aux_source_directory(${PROJECT_SOURCE_DIR} SRC) #添加源文件到變量SRC中,宏PROJECT_SOURCE_DIR指的是正在編寫的CMakeLists.txt文件所在的文件夾include_directories(${PROJECT_SOURCE_DIR}) #制定頭文件路徑,${}符號是CMake語法中從變量取出變量的值的符號add_executable(test_cacl ${SRC}) #使用源文件生成可執(zhí)行文件test_cacl,源文件的路徑及名稱位于SRC變量中
這是非常簡單的一個CMakeLists.txt文件,僅用于新手了解cmake的體驗裝。
3.建立build文件夾,運行CMakeLists.txt文件,測試文件是否編寫正確
建立build文件夾是為了保證源碼文件的整潔,鏈接、編譯生成的文件均在build文件夾下。
mkdir build #在repository4文件夾下執(zhí)行此命令生成build文件夾
cd build #進入build文件夾
cmake .. #使用CMakeLists.txt文件鏈接項目
make #編譯項目 生成可執(zhí)行文件
./test_calc #在編譯正確后,運行生成的可執(zhí)行文件test_calc
運行截圖如下
4.稍微改進一下,顯得整齊點
上面文件夾的內容顯得比較凌亂,對其進行整理,整理后的文件目錄如下,文件內容不變
將函數(shù)實現(xiàn)的cpp文件放在src目錄下,將頭文件放在include目錄下
對應的CMakeLists.txt文件的內容如下
cmake_minimum_required(VERSION 3.16)set(CMAKE_CXX_STANDARD 11)project(test_calculate)aux_source_directory(${PROJECT_SOURCE_DIR}/src SRC) #修改include_directories(${PROJECT_SOURCE_DIR}/include) #修改add_executable(test_cacl ${SRC} test_calc.cpp) #修改
執(zhí)行命令不變!
二、編寫嵌套CMakeLists.txt文件
1.先看文件目錄
在repository5文件夾下存在好幾個C++相關的文件和一個CMakeLIsts.txt文件,文件清單如下表:
文件(夾)名 | 文件夾中的文件 | 文件(夾)類型/用途 |
---|---|---|
repository5 | 以下文件(夾) | 工程文件夾 |
build | 鏈接、編譯產(chǎn)生的文件 | 用于存放鏈接、編譯時產(chǎn)生的文件 |
include | calc.h / convert.h | 頭文件,聲明了幾個函數(shù)定義 |
calc | calc.cpp / CMakeLists.txt | 頭文件calc.h中聲明的函數(shù)的實現(xiàn) |
conv | conv.cpp / CMakeLists.txt | 頭文件convert.h中聲明的函數(shù)的實現(xiàn) |
test_calc | test_calc.cpp / CMakeLists.txt | 調用calc.cpp實現(xiàn)的幾個函數(shù) |
test_conv | test_conv.cpp / CMakeLists.txt | 調用conv.cpp實現(xiàn)的幾個函數(shù) |
CMakeLists.txt | 編寫此文件,用于此工程的鏈接和編譯 |
這些文件總共生成兩個可執(zhí)行文件,一個是計算相關的calc,一個是轉換大小寫字母的conv,我們需要在實現(xiàn)頭文件中聲明的那些函數(shù)的源文件所在的文件夾、調用頭文件中函數(shù)的測試文件(main函數(shù))所在的文件夾 以及 工程項目repository文件夾中創(chuàng)建CMakeLists.txt文件。
以上除CMakeLists.txt文件以外的文件自己在保證調用、語法、功能正確的前提下隨便編寫。
2.編寫嵌套CMakeLists.txt文件
(1)編寫嵌套CMakeLists.txt文件的流程
(2)編寫外層CMakeLists.txt文件
cmake_minimum_required(VERSION 3.16)
set(CMAKE_CXX_STANDARD 11)
project(test)#添加子文件夾
add_subdirectory(calc)
add_subdirectory(conv)
add_subdirectory(test_calc)
add_subdirectory(test_conv)
(3)編寫內層CMakeLists.txt文件
a.編寫calc文件夾中的CMakeLists.txt文件
cmake_minimum_required(VERSION 3.16)
set(CMAKE_CXX_STANDARD 11)
project(calc)aux_source_directory(./ SRC) # ./=${PROJECT_SOURCE_DIR},在當前CMakeLists.txt所在文件夾(calc)中搜索源文件,并放置在SRC變量中
include_directories(../include) #添加頭文件路徑,../表示上一層目錄,../include即在上一層目錄下的include中
add_library(calculate STATIC ${SRC}) #取出SRC變量的值,生成一個名為calculate的靜態(tài)庫
b.編寫test_calc文件夾中的CMakeLists.txt文件
cmake_minimum_required(VERSION 3.16)
set(CMAKE_CXX_STANDARD 11)
project(calculator)
aux_source_directory(./ SRC)
include_directories(../include)link_libraries(calculate) #鏈接生成的靜態(tài)庫
add_executable(calculator ${SRC}) #生成名為calculator的可執(zhí)行文件
與calc相關的CMakeLists.txt就寫好了
c.剩下的兩個與conv相關的CMakeLists.txt文件其實與上面兩個編寫是一樣的,只是更改一下相關名稱而已,其內容如下:
conv文件夾中的CMakeLists.txt:
cmake_minimum_required(VERSION 3.16)
set(CMAKE_CXX_STANDARD 11)
project(conv)aux_source_directory(./ SRC)
include_directories(../include)
add_library(convert STATIC ${SRC})
test_conv文件夾中的CMakeLists.txt:
cmake_minimum_required(VERSION 3.16)
set(CMAKE_CXX_STANDARD 11)
project(convertor)
aux_source_directory(./ SRC)
include_directories(../include)
link_libraries(convert)
add_executable(convertor ${SRC})
3.在項目文件夾下創(chuàng)建build文件夾,測試剛才編寫的CMakeLists.txt文件
mkdir build
cd build
cmake ..
make
./test_conv/convertor
4. 同樣改進一下,指定一下生成的庫、可執(zhí)行文件的存放目錄
(1)在外層CMakeLists.txt文件中定義要存放生成的庫、可執(zhí)行文件的變量以及路徑
set(LIBPATH ${PROJECT_SOURCE_DIR}/lib) #設置生成庫的路徑,并放置在變量LIBPATH中
set(EXEPATH ${PROJECT_SOURCE_DIR}/bin) #設置可執(zhí)行文件的路徑,并放置在變量EXEPATH中
#文件夾bin和lib會自動生成
(2)在內層CMakeLists.txt文件中使用上面兩個全局變量LIBPATH
和EXEPATH
set(LIBRARY_OUTPUT_PATH ${LIBPATH}) #設置庫的生成目錄,在calc和conv文件夾下的CMakeLists.txt中添加
link_directories(../lib) #設置要鏈接的庫的目錄,在test_calc和test_conv文件夾下的CMakeLists.txt中添加
set(EXECUTABLE_OUTPUT_PATH ${EXEPATH}) #設置可執(zhí)行文件的生成目錄,在test_calc和test_conv文件夾下的CMakeLists.txt中添加
(3)添加后在當前工程的build路徑下執(zhí)行以下命令來測試CMakeLists.txt文件
cmake ..
make
../bin/convertor #當前在build文件夾中,bin文件夾和build并列,因此需要../
三、cmake常用函數(shù)
1.基礎命令
命令 | 功能 | 備注 |
---|---|---|
# | 單行注釋 | |
#[ [ ] ] | 塊注釋 | |
${ } | 從變量或宏中取出其值 | 例如:${PROJECT_SOURCE_DIR} |
cmake_minimum_required(VERSION 3.0) | 指定使用的 cmake 的最低版本 | 非必須,如果不加可能會有警告 |
project() | 定義工程名稱,并可指定工程的版本、工程描述、web主頁地址、支持的語言 | 如果不需要這些都是可以忽略的,只需要指定出工程名字即可 |
add_executable(可執(zhí)行程序名 源文件名稱) | 使用后面的源文件生成可執(zhí)行程序 | 源文件名可以是一個也可以是多個,如有多個可用空格或;間隔 |
set(VAR [value] | 將[value]存入變量VAR中 | [value]可以是多個,空格或;間隔 |
set(CMAKE_CXX_STANDARD 11) | 設置C++的標準 | CMAKE_CXX_STANDARD是預定義的宏 |
aux_source_directory(< dir > < variable >) | dir:要搜索的目錄,variable:將從dir目錄下搜索到的源文件列表存儲到該變量中 | |
file(GLOB/GLOB_RECURSE 變量名 要搜索的文件路徑和文件類型) | GLOB: 將指定目錄下搜索到的滿足條件的所有文件名生成一個列表,并將其存儲到變量中,GLOB_RECURSE:遞歸搜索指定目錄,將搜索到的滿足條件的文件名生成一個列表,并將其存儲到變量中 | GLOB與GLOB_RECURSE 二選一 |
include_directories(headpath) | 添加含頭文件路徑 | headpath:頭文件路徑 |
add_library(庫名稱 STATIC/SHARED 源文件1 [源文件2] …) | 使用源文件生成庫 | STATIC:靜態(tài)庫,SHARED:動態(tài)庫 |
2.包含庫文件
link_libraries(<static lib> [<static lib>...])
參數(shù)1:指定出要鏈接的第一個靜態(tài)庫的名字,可以是全名 libxxx.a,也可以是掐頭(lib)去尾(.a)之后的名字 xxx;
參數(shù)2-N:要鏈接的其它靜態(tài)庫的名字(根據(jù)實際情況是否需要);
如果該靜態(tài)庫不是系統(tǒng)提供的(自己制作或者使用第三方提供的靜態(tài)庫)可能出現(xiàn)靜態(tài)庫找不到的情況,此時可以將靜態(tài)庫的路徑也指定出來:
link_directories(<lib path>)
在cmake中鏈接動態(tài)庫的命令如下:
target_link_libraries(<target> <PRIVATE|PUBLIC|INTERFACE> <item>... [<PRIVATE|PUBLIC|INTERFACE> <item>...]...)
target:指定要加載的庫的文件的名字:該文件可能是一個源文件、一個動態(tài)庫/靜態(tài)庫文件、一個可執(zhí)行文件
PRIVATE
|PUBLIC
|INTERFACE
:動態(tài)庫的訪問權限,默認為PUBLIC
;
如果各個動態(tài)庫之間沒有依賴關系,無需做任何設置,三者沒有沒有區(qū)別,一般無需指定,使用默認的 PUBLIC
即可,動態(tài)庫的鏈接具有傳遞性,如果動態(tài)庫 A 鏈接了動態(tài)庫B、C,動態(tài)庫D鏈接了動態(tài)庫A,此時動態(tài)庫D相當于也鏈接了動態(tài)庫B、C,并可以使用動態(tài)庫B、C中定義的方法。
3.日志
message([STATUS|WARNING|AUTHOR_WARNING|FATAL_ERROR|SEND_ERROR] "message to display" ...)
(無) :重要消息
STATUS
:非重要消息
WARNING
:CMake 警告, 會繼續(xù)執(zhí)行
AUTHOR_WARNING
:CMake 警告 (dev), 會繼續(xù)執(zhí)行
SEND_ERROR
:CMake 錯誤, 繼續(xù)執(zhí)行,但是會跳過生成的步驟
FATAL_ERROR
:CMake 錯誤, 終止所有處理過程
例如:
# 輸出一般日志信息
message(STATUS "source path: ${PROJECT_SOURCE_DIR}")
# 輸出警告信息
message(WARNING "source path: ${PROJECT_SOURCE_DIR}")
# 輸出錯誤信息
message(FATAL_ERROR "source path: ${PROJECT_SOURCE_DIR}")
4.變量操作
命令 | 功能 |
---|---|
set(變量名1 ${變量名1} ${變量名2} …) | 將從第二個參數(shù)開始往后所有的字符串進行拼接,結果覆蓋寫入到第一個參數(shù)中 |
list(APPEND < list> [< element> …]) | APPEND表示進行數(shù)據(jù)追加,后邊的參數(shù)和set就一樣了 |
list(REMOVE_ITEM < list> < value>) | 從list中移除后面的value |
list(LENGTH < list> < outputvariable>) | 獲取 list 的長度,< output variable>:新創(chuàng)建的變量,用于存儲列表的長度 |
list(GET < list> < element index> < output variable>) | 讀取列表中指定索引的的元素,可以指定多個索引 |
list (JOIN < list> < glue> < output variable>) | 將列表中的元素用連接符(glue)連接起來組成一個字符串 |
list(FIND < list> < value> < output variable>) | 查找列表是否存在指定的元素,若果未找到,返回-1 |
list(INSERT < list> < element_index> < element> [< element> …]) | 在list中指定的位置插入若干元素 |
list (PREPEND < list> [< element> …]) | 將元素插入到列表的0索引位置 |
list (POP_BACK < list> [< out-var>…]) | 將列表中最后元素移除 |
list (POP_FRONT < list> [< out-var>…]) | 將列表中首元素移除 |
list (REMOVE_ITEM < list> < value> [< value> …]) | 將指定的元素從列表中移除 |
list (REMOVE_AT < list> < index> [< index> …]) | 將指定索引的元素從列表中移除 |
list (REMOVE_DUPLICATES < list>) | 移除列表中的重復元素 |
list(REVERSE < list>) | 列表翻轉 |
列表排序
list (SORT <list> [COMPARE <compare>] [CASE <case>] [ORDER <order>])
/*
COMPARE:指定排序方法。有如下幾種值可選:STRING:按照字母順序進行排序,為默認的排序方法FILE_BASENAME:如果是一系列路徑名,會使用basename進行排序NATURAL:使用自然數(shù)順序排序
CASE:指明是否大小寫敏感。有如下幾種值可選:SENSITIVE: 按照大小寫敏感的方式進行排序,為默認值INSENSITIVE:按照大小寫不敏感方式進行排序
ORDER:指明排序的順序。有如下幾種值可選:ASCENDING:按照升序排列,為默認值DESCENDING:按照降序排列
*/
5.宏定義
在進行程序測試的時候,我們可以在代碼中添加一些宏定義,通過這些宏來控制這些代碼是否生效,如下所示:
#include <stdio.h>
#define NUMBER 3int main()
{int a = 10;
#ifdef DEBUGprintf("我是一個程序猿, 我不會爬樹...\n");
#endiffor(int i=0; i<NUMBER; ++i){printf("hello, GCC!!!\n");}return 0;
}
在程序的第七行對DEBUG宏進行了判斷,如果該宏被定義了,那么第八行就會進行日志輸出,如果沒有定義這個宏,第八行就相當于被注釋掉了,因此最終無法看到日志輸入出(上述代碼中并沒有定義這個宏)。
為了讓測試更靈活,我們可以不在代碼中定義這個宏,而是在測試的時候去把它定義出來,其中一種方式就是在gcc/g++命令中去指定,如下:
gcc test.c -DDEBUG -o app
在gcc/g++命令中通過參數(shù) -D指定出要定義的宏的名字,這樣就相當于在代碼中定義了一個宏,其名字DEBUG。
在CMake中我們也可以做類似的事情,對應的命令叫做add_definitions()
:
add_definitions(-D宏名稱)//針對上面的例子在對應CMakeLists.txt文件中寫這句就等于gcc test.c -DDEBUG -o app
//add_definitions(-DDEBUG)
下面的列表中為大家整理了一些CMake中常用的宏:
宏 | 功能 |
---|---|
PROJECT_SOURCE_DIR | 使用cmake命令后緊跟的目錄,一般是工程的根目錄 |
PROJECT_BINARY_DIR | 執(zhí)行cmake命令的目錄 |
CMAKE_CURRENT_SOURCE_DIR | 當前處理的CMakeLists.txt所在的路徑 |
CMAKE_CURRENT_BINARY_DIR | target 編譯目錄 |
EXECUTABLE_OUTPUT_PATH | 重新定義目標二進制可執(zhí)行文件的存放位置 |
LIBRARY_OUTPUT_PATH | 重新定義目標鏈接庫文件的存放位置 |
PROJECT_NAME | 返回通過PROJECT指令定義的項目名稱 |
CMAKE_BINARY_DIR | 項目實際構建路徑,假設在build目錄進行的構建,那么得到的就是這個目錄的路徑 |