【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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈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 中的出现频…