【C++開發】CMake構建工具

目錄

1,CMake介紹

2,配置文件CMakeLists.txt


1,CMake介紹

????????CMake 是一個開源的、跨平臺的自動化構建系統生成工具,廣泛用于 C 和 C++ 項目的構建管理。它使用一個名為 CMakeLists.txt 的配置文件來定義如何構建項目,并能夠生成適用于不同編譯器和操作系統的構建文件(如 Makefile、Visual Studio項目等),從而實現跨平臺的一致性構建。

2,配置文件CMakeLists.txt

????????CMakeLists.txt 是 CMake 的核心配置文件,存在于每個需要構建的目錄中。配置指令常用的如下:

? ? ? ? 1,構建項目程序的簡單配置指令。?

# 聲明cmake使用的最低版本
cmake_minimum_required(VERSION 3.20)

# 構建項目的信息。下面對應名稱、版本、描述、項目使用的語言
project(TestProject VERSION 1.1.1 DESCRIPTION "This is a TestProject" LANGUAGES CXX)

# 設置使用C++11版本(14, 17, 20版本類似)
set(CMAKE_CXX_STANDARD 11)

# 指定頭文件的搜索路徑:有target_include_directories和include_directories
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)

# CMAKE_CURRENT_SOURCE_DI宏是表示CMakeLists.txt的路徑

? ? ? ? 2,set() 和 file() 設置變量的值。它們用于將一個或多個值組合起來賦給自定義的變量。用途如下:

# 指定編譯的源文件(頭文件不需要加入,cmake它不會讓它參與編譯)
# 方法一:指定有限個參與編譯。自定義SRC保存找到源文件路徑的變量名

set(SRC fun1.cpp fun2.cpp fun3.cpp main.cpp)?

# 方法二:將指定目錄下的所有源文件參與編譯(目錄下非遞歸式,即子目錄不包含)

# PROJECT_SOURCE_DIR宏本質是cmake后面根的路徑名

#?自定義SRC保存找到的所有源文件路徑的變量名
aux_source_directories(${PROJECT_SOURCE_DIR}/*.cpp ${PROJECT_SOURCE_DIR}/*.cc SRC)?
# 方法三:目前最流行的file。GLOB 表示非遞歸查找;GLOB_RECURSE遞歸式查找
file(GLOB SRC ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp *.cc)

# 指定庫的存放路徑。其實這里就是把指定的傳輸路徑的字符串設置到定義庫路徑的宏中

# CMAKE_LIBRARY_OUTPUT_DIRECTORY動態庫(.so,.dll)輸出路徑

# CMAKE_ARCHIVE_OUTPUT_DIRECTORY靜態庫(.a, .lib)輸出路徑
# 這里可以使用debug或release構建方式,即CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG 或?CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE

set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/lib) # 將生成的動態庫傳輸到lib下
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/lib) # 將生成的靜態庫傳輸到lib下

# 指定可執行文件的輸出路徑。CMAKE_RUNTIME_OUTPUT_DIRECTORY(現代寫法)和EXECUTABLE_OUTPUT_PATH(過時寫法)
set(EXECUTABLE_OUTPUT_PATH /root/Test)

#可選:分別設置 Debug/Release 輸出路徑
#set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG /root/Test/debug)
#set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE /root/Test/release)

# 拼接字符串。將字符串賦給tmp和tmp1

set(tmp Hello Cmake)
set(tmp1 ${tmp} ${CMAKE_CURRENT_SOURCE_DIR})

? ? ? ? 3,動靜態庫的相關指令配置。

# 把指定的源文件編譯成一個庫(靜態庫或動態庫)
file(GLOB LIBS ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
add_library(myshared SHARED ${LIBS}) ?# 定義動態庫 ?
add_library(mystatic STATIC ${LIBS}) ?# 定義靜態庫

# 指定庫的存放路徑
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/lib) # 將生成的動態庫傳輸到lib下
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/lib) # 將生成的靜態庫傳輸到lib下

# 說明程序鏈接時,自定義庫的路徑
link_directories(${CMAKE_CURRENT_SOURCE_DIR}/lib) ?# 指定自定義庫的路徑

# 鏈接自定義生成的庫
# 方法一:古老用法。鏈接靜態庫時可以使用;鏈接動態庫不推薦

link_libraries(mystatic) ? ? ?# 鏈接庫mystatic

# 方法二:新用法。非常推薦。
target_link_libraries(test PRIVATE myshared) ?# 可執行程序test鏈接庫myshared

????????4,可執行文件的相關指令配置。

# 指定可執行文件的輸出路徑。CMAKE_RUNTIME_OUTPUT_DIRECTORY(現代寫法)和EXECUTABLE_OUTPUT_PATH(過時寫法)
set(EXECUTABLE_OUTPUT_PATH /root/Test)

# 指定編譯的源文件(頭文件不需要加入,cmake它不會讓它參與編譯)
file(GLOB SRC ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp *.cc)

# 通過源文件列表生成可執行文件目標,即告訴CMake把哪些源文件編譯成一個可執行程序
add_executable(test ${SRC})
# add_executable(test fun1.cpp fun2.cpp fun3.cpp main.cpp)

? ? ? ? 5,message 輸出日志。該命令用于在終端輸出變量,以提示用戶信息。

語法:

????????message([<mode>] "message text" ...)

參數說明:

????????<mode>(可選):指定消息的類型或行為。
????????"message text":要輸出的消息內容,可以包含變量 ${VAR}。

消息類型(Mode)取值如下:

????????STATUS:輸出狀態信息(用 -- ?前綴顯示),不會中斷構建。
????????WARNING:輸出警告信息,不會中斷構建,但會高亮顯示。
????????SEND_ERROR:輸出錯誤信息,并中斷當前cmake構建階段,但繼續生成項目。
????????FATAL_ERROR:輸出錯誤信息,并完全中斷構建和生成的過程。

樣例:
????????set(tmp Hello Cmake)
????????set(tmp1 ${tmp} ${CMAKE_CURRENT_SOURCE_DIR})
????????message(STATUS ${tmp})
????????message(STATUS ${tmp1})

????????message(STATUS "************************************")

? ? ? ? 6,list處理列表。列表是用分號 “;” 分隔的一系列字符串,盡管你可能會看到使用空格分隔的值,在內部它們會被轉換成分號分隔的形式。該命令提供了一系列的操作來操作這些列表,包括添加、刪除、搜索和排序等。這里說明添加和刪除。

語法:

????????list(APPEND <list> [<element> ...])? # 將一個或多個元素追加到指定的列表末尾

????????list(REMOVE_ITEM <list> [<value> ...])? # 從列表中移除所有與給定值匹配的項

樣例:
????????set(MY_LIST a b c)? ?# 初始化一個列表MY_LIST
????????list(APPEND MY_LIST d e f)? ?# 添加新元素到列表末尾
????????message("MY_LIST: ${MY_LIST}")??# 輸出結果MY_LIST: a;b;c;d;e;f


????????set(MY_LIST a b c b d b)?# 初始化一個包含重復項的列表
????????list(REMOVE_ITEM MY_LIST b)?# 移除所有等于 "b" 的項
????????message("MY_LIST: ${MY_LIST}")??# 輸出結果MY_LIST: a;c;d

? ? ? ? list還有很多個模式運用,這里不做過多說明。明白原理后,在所需要的場景下自行查找即可

? ? ? ? 7,link_libraries() 和 target_link_libraries()。這兩種指令都是用于鏈接指定的庫。link_libraries()命令設置的是全局鏈接庫,會影響后續定義的所有目標。

link_libraries(mylib)
# 后續所有生成的可執行文件都會鏈接mylib庫

add_executable(myapp main.cpp)?

????????target_link_libraries() 是現代 CMake 中用于為特定目標(可執行文件或庫)指定鏈接庫的方式。

語法:

????????target_link_libraries(<target-name> [PRIVATE|PUBLIC|INTERFACE] <library> ...)

參數說明:

????????<target-name>:之前通過 add_executable() 或 add_library() 定義的目標名稱。
????????PRIVATE:僅當前目標使用此庫。

????????PUBLIC:不僅當前目標使用此庫,而且任何依賴于這個目標的其他目標也會繼承這個? ? ? ? ? ? 庫。

????????INTERFACE:當前目標本身不需要這些庫,但依賴它的目標需要。這點理解若困難可? ? ? ? ? ? 直接看下面樣例。

????????<library>:鏈接的庫文件。

樣例1:

????????// 可指定程序鏈接庫

????????target_link_libraries(myapp PRIVATE /path/to/libmylib.a) # 靜態庫 ????????target_link_libraries(myapp PRIVATE /path/to/libmylib.so) # 動態庫

樣例2:

????????# libA 庫需要鏈接 libB,后面的目標不會鏈接 libB

????????add_library(libA STATIC a.cpp)

????????target_link_libraries(libA PRIVATE libB)

????????# libD 庫需要鏈接 libE,并且它的使用者也需要鏈接 libE

????????add_library(libD STATIC d.cpp)

????????target_link_libraries(libD PUBLIC libE)

????????# libF 庫的使用者需要鏈接 libG,但 libF 自身并不直接使用 libG

????????add_library(libF INTERFACE)

????????target_link_libraries(libF INTERFACE libG)

? ? ? ? 注意:可執行程序鏈接庫的順序是先生成可執行程序,在進行動靜態庫的鏈接。

? ? ? ? 8,add_subdirectory 嵌套 CMakeLists.txt 文件。add_subdirectory 用于向構建過程添加一個子目錄。這個子目錄應該包含自己的 CMakeLists.txt 文件,定義了如何編譯該目錄下的源代碼以及如何將其鏈接到其他目標(如可執行文件或庫,大多數情況是庫文件)。

語法:

????????add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])

參數說明:

????????source_dir:指定要添加的子目錄路徑,可以是相對路徑也可以是絕對路徑。
????????[binary_dir]可選參數:指定輸出文件存放的目錄。如果未指定,則默認為 source_dir? ? ? ? ? 對應的構建目錄。
????????[EXCLUDE_FROM_ALL]可選參數:暫時不做說明。

????????假設你有一個項目結構如下:

/my_project
|—— CMakeLists.txt
|—— /src
| ? |—— main.cpp
|—— /lib
? ? |—— CMakeLists.txt
? ? |—— /math
? ? ? ? |—— math.cpp
? ? ? ? |—— math.h

????????/my_project 目錄是項目的根目錄,其中包含一個頂級 CMakeLists.txt 文件。/src 目錄包含了項目的主源文件(如 main.cpp),而 /lib/math 則包含了一個數學庫的實現(math.cpp 和 math.h)。

????????項目根目錄下的 CMakeLists.txt 文件內容如下:

cmake_minimum_required(VERSION 3.10)

# 設置項目名稱
project(MyProject)

# 添加 lib 目錄中的子項目
add_subdirectory(lib)

# 添加 src 目錄中的可執行文件
add_subdirectory(src)

????????lib 目錄下的 CMakeLists.txt 文件內容如下:

# 定義一個靜態庫
add_library(MathLib STATIC math/math.cpp)
# 包含頭文件路徑
target_include_directories(MathLib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/math)

????????在 src 目錄下,這里可以創建另一個 CMakeLists.txt 文件來編譯可執行文件,并鏈接之前定義的 MathLib 庫:

# 添加可執行文件
add_executable(MyExecutable main.cpp)
# 鏈接 MathLib 庫
target_link_libraries(MyExecutable MathLib)

????????通過這種方式,add_subdirectory 命令使得能夠輕松地組織和管理復雜的項目結構。每個子目錄可以有自己的 CMakeLists.txt 文件,從而讓項目更加模塊化和易于維護。


? ? ? ? 最后說明下Qt Creator中的CMake配置,Qt Creator環境中CMake配置

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/910399.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/910399.shtml
英文地址,請注明出處:http://en.pswp.cn/news/910399.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

大模型MetaGPT面試題匯總及參考答案

目錄 MetaGPT 的核心目標與設計理念是什么? 它如何實現多角色協同(如 Planner、Coder、Reviewer、Tester)? 不同 agent 之間的通信機制是怎樣的? MetaGPT 是如何進行任務拆分與任務分配的? 它如何實現可執行的反饋循環(self-correcting)? 在實際項目中如何監控各…

深入理解 HTTP 狀態碼 —— 前端后端必備知識

&#x1f4da;深入理解 HTTP 狀態碼 —— 前端后端必備知識 作者&#xff1a;lvzi 日期&#xff1a;2025 年 6 月 22 日 標簽&#xff1a;HTTP、前端、后端、狀態碼、Web基礎 &#x1f4a1;引言 在 Web 開發過程中&#xff0c;我們經常會遇到形如 200 OK、404 Not Found、500…

Python商務數據分析——Python 入門基礎知識學習筆記

一、簡介 1.1 Python 特性 解釋型語言&#xff1a;代碼無需編譯可直接運行&#xff0c;適合快速開發。 動態類型&#xff1a;變量類型在運行時確定&#xff08;如x1后x"str"仍合法&#xff09;。 面向對象&#xff1a;支持類、對象、繼承等特性&#xff0c;代碼可…

IT小白到高手:HCIA、HCIP、HCIE認證攻略

大家好&#xff0c;這里是G-LAB IT實驗室。6月&#xff12;&#xff12;日&#xff0c;周日&#xff01;HCIA&#xff0b;CCNA開新班啦&#xff01; 01 華為HCIA、HCIP、HCIE有必要考證嗎 在如今競爭激烈的IT行業&#xff0c;華為的認證體系已成為眾多網絡工程師的重要參考。…

【IndexDB】前端IndexedDB終極指南

前端 IndexedDB 詳細教程 IndexedDB 是一個瀏覽器內置的 NoSQL 數據庫系統&#xff0c;允許在客戶端存儲大量結構化數據&#xff0c;并支持高性能搜索。相比 localStorage&#xff0c;IndexedDB 更適合存儲大量數據并提供更復雜的查詢功能。 基本概念 數據庫&#xff1a;每個…

擴散模型與強化學習(1):字節Seedance中的人類偏好優化實踐

擴散模型與強化學習(0)&#xff1a;專欄匯總與導航 前言&#xff1a;最近強化學習在Diffusion Models得到了越來越多廣泛的應用&#xff0c;本專欄將系統性地介紹當前Diffusion Models中實用且前沿的技術進展。這篇博客介紹字節最新的視頻生成模型Seedance 1.0: Exploring the …

【內存】Linux 內核優化實戰 - vm.max_map_count

目錄 vm.max_map_count參數全面解析一、參數定義與核心作用二、默認值與關鍵調整場景1. 默認限制與不足場景2. 典型報錯案例 三、操作指南&#xff1a;查看與修改方法四、場景化建議值與配置示例五、關鍵注意事項六、延伸知識&#xff1a;內存映射的底層邏輯 vm.max_map_count參…

組件之間的雙向綁定:v-model

&#x1f90d; 前端開發工程師、技術日更博主、已過CET6 &#x1f368; 阿珊和她的貓_CSDN博客專家、23年度博客之星前端領域TOP1 &#x1f560; 牛客高級專題作者、打造專欄《前端面試必備》 、《2024面試高頻手撕題》、《前端求職突破計劃》 &#x1f35a; 藍橋云課簽約作者、…

GetX 實現 MVVM 架構, 高效 路由管理 和 狀態管理

GetX是Flutter中的一個高效的狀態管理與路由管理框架&#xff0c;結合MVVM架構能簡化代碼邏輯。以下是使用GetX實現MVVM架構&#xff0c;并完成路由和狀態管理的核心思路與實踐&#xff1a; 一、MVVM架構在GetX中的映射 MVVM&#xff08;Model-View-ViewModel&#xff09;與G…

Qt項目,記事本

一、項目說明 項目功能&#xff1a; &#xff08;1&#xff09;打開文件&#xff1a;點擊打開文件按鈕彈出對話框&#xff0c;選擇文本文件后&#xff0c;在主窗口編輯界面顯示內容。 &#xff08;2&#xff09;關閉文件&#xff1a;關閉打開的文件&#xff0c;并詢問是否保存…

【全開源】填表問卷統計預約打卡表單系統+uniapp前端

一.系統介紹 填表問卷統計預約打卡表單系統是ThinkPHPUniApp開發的一款集信息填表、預約報名&#xff0c;簽到打卡、活動通知、報名投票、班級統計等功能的自定義表單統計小程序。 二.搭建環境 系統環境&#xff1a;CentOS、 運行環境&#xff1a;寶塔 Linux 網站環境&…

開源 python 應用 開發(一)python、pip、pyAutogui、python opencv安裝

最近有個項目需要做視覺自動化處理的工具&#xff0c;最后選用的軟件為python&#xff0c;剛好這個機會進行系統學習。短時間學習&#xff0c;需要快速開發&#xff0c;所以記錄要點步驟&#xff0c;防止忘記。 鏈接&#xff1a; 開源 python 應用 開發&#xff08;一&#x…

SpringCloud + Zookeeper + Feign整合及Feign原理

知其然 SpringCloud Zookeeper Spring Cloud 與 Zookeeper的整合只需要添加相關的starter依賴和增加相關注解即可完成。 pom.xml 如下&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.…

深入探索 OpenCV 圖像識別:從基礎到深度學習

在當今數字化時代&#xff0c;圖像識別技術已經滲透到我們生活的方方面面&#xff0c;從智能手機中的拍照翻譯功能到自動駕駛汽車的目標檢測系統&#xff0c;圖像識別的應用無處不在。作為一名算法工程師&#xff0c;我有幸深入研究并實踐了 OpenCV 在圖像識別領域的強大功能。…

Hadoop部署(HA)高可用集群

一、準備工作 1.把集群全部停掉 在三臺節點上都做&#xff08;在xshell通過右鍵----> 發送輸入到--->所有會話&#xff09; 2..在/export/servers下創建HA目錄 sudo mkdir -p /export/servers/HA 3.創建用戶和設置所屬主和所屬組 #創建用戶 sudo adduser ygre #設置…

STM32 CAN位同步、錯誤處理

一、接收方數據采樣 CAN總線沒有時鐘線&#xff0c;總線上的所有設備通過約定波特率的方式確定每一個數據位的時長發送方以約定的位時長每隔固定時間輸出一個數據位接收方以約定的位時長每隔固定時間采樣總線的電平&#xff0c;輸入一個數據位理想狀態下&#xff0c;接收方能依…

django serializer __all__中 額外添加外鍵里的某一個屬性

在Django中使用序列化器&#xff08;Serializer&#xff09;時&#xff0c;你可能會遇到需要將模型&#xff08;Model&#xff09;中的外鍵字段轉換成其關聯對象的一部分屬性的情況。默認情況下&#xff0c;序列化器會自動序列化外鍵字段&#xff0c;但如果你想要在序列化結果中…

Redis快的原因

Redis 高性能的核心原因 Redis 之所以能達到極高的性能&#xff08;10萬 QPS&#xff09;&#xff0c;主要源于以下幾個關鍵設計&#xff1a; 1. 純內存操作 核心優勢&#xff1a;所有數據存儲在內存中&#xff0c;避免了磁盤 I/O 瓶頸 內存訪問速度比磁盤快 10萬倍以上&am…

【大模型微調】6.模型微調實測與格式轉換導出

引言 本文繼續研究 LLaMA-Factory 微調數據的流程&#xff0c;側重于微調結果與模型導出。 數據集準備 首先參考 LLaMA-Factory 核心開發者的文章[1]&#xff0c;下載用于微調的公開的商品文案數據集 AdvertiseGen。 下載地址&#xff1a;https%3A//cloud.tsinghua.edu.cn/…

3085. 成為 K 特殊字符串需要刪除的最少字符數

3085. 成為 K 特殊字符串需要刪除的最少字符數 給你一個字符串 word 和一個整數 k。 如果 |freq(word[i]) - freq(word[j])| < k 對于字符串中所有下標 i 和 j 都成立&#xff0c;則認為 word 是 k 特殊字符串。 此處&#xff0c;freq(x) 表示字符 x 在 word 中的出現頻…