当前位置: 首页 > news >正文

【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配置

相关文章:

  • 从Git历史中删除大文件的完整解决方案
  • 图灵完备之路(数电学习三分钟)----门的多路化
  • mysql join的原理及过程
  • 一键打包利器:gopack - 极简Go程序编译与压缩工具
  • openapi-generator-maven-plugin自动生成HTTP远程调用客户端
  • Mysql—锁相关面试题(全局锁,表级锁,行级锁)
  • 商品中心—10.商品B端搜索系统的说明文档
  • 防御悬垂指针:C++的多维度安全实践指南
  • 逆向某物 App 登录接口:还原 newSign 算法全流程
  • Vulkan 学习(17)---- 使用 IndexBuffer
  • c#,vb.net LockObject ,多线程锁,多线程安全字典ConcurrentDictionary
  • C/C++数据结构之静态数组
  • Matplotlib入门指南:从安装到绘制基本图形
  • 3D制作角色模型的教程-1
  • Java的锁机制问题
  • 【论文阅读笔记】TransparentGS:当高斯溅射学会“看穿”玻璃,如何攻克透明物体重建难题?
  • Protobuf 与 JSON 的兼容性:技术选型的权衡与实践
  • 风险矩阵与灰色综合评价
  • [OS_26] 计算机系统安全 | CIA原则 | 侧信道攻击
  • 【工具】CrossAttOmics:基于交叉注意力的多组学数据整合技术
  • 自适应网站设计案例/郑州关键词排名外包
  • 网站建设肆金手指排名7/女生seo专员很难吗为什么
  • 南通网站建设方案开发/百度seo排名教程
  • 网站如何进行seo/百度网站排名优化价格
  • 做视频网站视频存放在哪里/搜索引擎优化到底是优化什么
  • 南京尘帆网站建设/品牌传播推广方案