c++ CMakeLists.txt详解

基本结构

  1. CMake 最低版本声明
    用于指定需要的最低 CMake 版本,确保兼容性。
cmake_minimum_required(VERSION 3.10)
  • 指定 CMake 的最低版本。
  • 确保用户的 CMake 版本符合项目需求,否则报错。
  • 版本选择建议根据项目使用的功能决定。例如,3.10 引入了 target_link_directories
  1. 项目名称和语言定义
    定义项目的名称及支持的编程语言。
project(ProjectName LANGUAGES C CXX)
  • ProjectName:项目名称,自动赋值给变量 ${PROJECT_NAME}
  • LANGUAGES:指定项目支持的语言,可以是 CCXX(C++)、Fortran 等。
  • 默认生成变量:
    • ${PROJECT_SOURCE_DIR}:项目根目录。
    • ${PROJECT_BINARY_DIR}:构建目录。
  1. 设置编译选项
    设置标准版本(如 C++17)或添加额外的编译器选项。
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
  • CMAKE_CXX_STANDARD:设置 C++ 标准(如 11、14、17、20)。
  • CMAKE_CXX_STANDARD_REQUIRED:强制使用指定版本。
  • CMAKE_CXX_EXTENSIONS:是否使用非标准扩展(如 -std=gnu++17)。
  1. 定义源文件和头文件路径
    将源代码组织到变量中,或直接指定路径。
set(SOURCES src/main.cpp src/foo.cpp)
set(INCLUDES include/)
  1. 生成可执行文件或库
    指定目标类型(可执行文件、静态库、动态库)。
# 添加可执行文件
add_executable(MyApp ${SOURCES})# 添加静态库
add_library(MyStaticLib STATIC src/foo.cpp src/bar.cpp)# 添加动态库
add_library(MySharedLib SHARED src/foo.cpp src/bar.cpp)
  1. 设置目标的头文件路径
    将头文件目录添加到目标的构建路径中。
target_include_directories(MyApp PRIVATE ${INCLUDES})
  1. 链接内部库
    链接外部依赖库或内部生成的库。
target_link_libraries(MyApp PRIVATE MyLib)
  1. 查找外部库(可选)
    查找并使用外部库(如 Boost 或 OpenCV)。
find_package(OpenCV REQUIRED)
target_link_libraries(MyApp PRIVATE ${OpenCV_LIBS})
  1. 安装规则
    指定生成的二进制文件、配置文件等的安装路径。
install(TARGETS MyApp DESTINATION bin)
install(FILES config/settings.conf DESTINATION etc)
  • install() 定义安装文件的位置。
  • 常见用途:
    • 安装可执行文件到 bin
    • 安装库到 lib
    • 安装配置文件到 etc
  1. 测试支持(可选)
    启用单元测试功能。
enable_testing()
add_test(NAME MyTest COMMAND MyApp --test)
  1. 子目录管理(可选)
    用于大型项目,将多个模块分割到不同的子目录。
add_subdirectory(src/module1)
  • 对于大型项目,将代码分割到子目录中,通过 add_subdirectory() 引入。

子模块的 CMakeLists.txt

add_library(Module1 STATIC module1.cpp)
target_include_directories(Module1 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
  1. 添加自定义命令和目标(可选)
  • 添加自定义命令
add_custom_command(OUTPUT generated.cppCOMMAND python generate.py > generated.cppDEPENDS generate.py
)
  • 添加自定义目标
add_custom_target(GenerateCode ALL DEPENDS generated.cpp)
  1. 使用变量和条件(动态配置)
  • 条件语句
if(CMAKE_BUILD_TYPE STREQUAL "Debug")message("Debug build")
endif()
  • 变量替换
set(VERSION "1.0.0")
message("Project version: ${VERSION}")

示例1:单模块(c++)

项目结构

MyProject/
├── CMakeLists.txt
├── src/
│   ├── main.cpp
│   ├── foo.cpp
├── include/
│   └── foo.h
└── config/└── settings.conf

代码文件

  • src/main.cpp:
#include <iostream>
#include "foo.h"int main() {std::cout << "Sum of 3 and 5 is: " << add(3, 5) << std::endl;return 0;
}
  • src/foo.cpp:
#include "foo.h"int add(int a, int b) {return a + b;
}
  • include/foo.h:
#ifndef FOO_H
#define FOO_Hint add(int a, int b);#endif
  • config/settings.conf:
# This is a placeholder configuration file

CMakelist.txt

# 设置 CMake 最低版本
cmake_minimum_required(VERSION 3.10)# 定义项目名称和语言
project(MyProject LANGUAGES CXX)# 设置编译选项
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)# 定义源文件和头文件目录
set(SOURCESsrc/main.cppsrc/foo.cpp
)set(INCLUDESinclude/
)# 添加可执行目标
add_executable(MyApp ${SOURCES})# 配置头文件路径
target_include_directories(MyApp PRIVATE ${INCLUDES})# 安装规则
install(TARGETS MyApp DESTINATION bin)
install(FILES config/settings.conf DESTINATION etc)# 启用测试支持
enable_testing()
add_test(NAME RunTests COMMAND MyApp)

构建和运行

1. 创建构建目录

为了保持源文件清晰,推荐在源代码目录外创建构建目录:

mkdir build
cd build

2. 运行 CMake

使用 CMake 生成构建文件:

cmake ..

3. 编译项目

使用 CMake 的构建命令:

cmake --build .

4. 运行程序

./MyApp

5. 安装程序

将可执行文件和配置文件安装到指定目录:

cmake --install .

示例2:多模块(c++)

项目结构

MyProject/
├── CMakeLists.txt         # 顶层 CMakeLists.txt
├── module1/               # 模块1
│   ├── CMakeLists.txt     # 模块1的 CMakeLists.txt
│   ├── module1.cpp
│   └── module1.h
├── module2/               # 模块2
│   ├── CMakeLists.txt     # 模块2的 CMakeLists.txt
│   ├── module2.cpp
│   └── module2.h
├── app/                   # 主程序
│   ├── CMakeLists.txt     # 主程序的 CMakeLists.txt
│   ├── main.cpp
└── build/                 # 构建目录

顶层 CMakeLists.txt

顶层的 CMakeLists.txt 文件负责整体项目的配置,包括引入各个模块、设置编译选项以及定义最终的构建目标。

# 设置最低 CMake 版本
cmake_minimum_required(VERSION 3.10)# 定义项目名称和语言
project(MyProject LANGUAGES CXX)# 设置编译选项
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)# 添加子模块目录
add_subdirectory(module1)
add_subdirectory(module2)
add_subdirectory(app)

模块1的 CMakeLists.txt

模块1构建为一个静态库,提供对其他模块的功能支持。

# 定义模块1的库
add_library(Module1 STATIC module1.cpp)# 指定模块1的头文件路径
target_include_directories(Module1 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})# 可选:设置特定的编译选项(如果模块需要)
target_compile_options(Module1 PRIVATE -Wall -Wextra)

模块2的 CMakeLists.txt

模块2构建为一个动态库,并依赖模块1。

# 定义模块2的库
add_library(Module2 SHARED module2.cpp)# 指定模块2的头文件路径
target_include_directories(Module2 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})# 链接模块1
target_link_libraries(Module2 PUBLIC Module1)

主程序的 CMakeLists.txt

主程序依赖模块1和模块2,并最终生成可执行文件。

# 定义主程序的可执行目标
add_executable(MyApp main.cpp)# 链接模块1和模块2
target_link_libraries(MyApp PRIVATE Module1 Module2)# 指定主程序的头文件路径(如果需要)
target_include_directories(MyApp PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})

示例代码

  • module1/module1.h
#ifndef MODULE1_H
#define MODULE1_Hint add(int a, int b);#endif
  • module1/module1.cpp
#include "module1.h"int add(int a, int b) {return a + b;
}
  • module2/module2.h
#ifndef MODULE2_H
#define MODULE2_Hint multiply(int a, int b);#endif
  • module2/module2.cpp
#include "module2.h"
#include "module1.h"int multiply(int a, int b) {return a * add(a, b);  // 使用模块1的功能
}
  • app/main.cpp
#include <iostream>
#include "module1.h"
#include "module2.h"int main() {int a = 3, b = 5;std::cout << "Add: " << add(a, b) << std::endl;std::cout << "Multiply: " << multiply(a, b) << std::endl;return 0;
}

功能扩展

  • 模块化管理: 将子模块组织到不同目录,并通过 add_subdirectory() 引入。

  • 外部库集成: 使用 find_package()target_link_libraries() 管理外部库。

  • 生成静态库: 使用 add_library() 定义静态库目标,并链接到其他可执行文件。

  • 跨平台支持: CMake 支持跨平台构建(如 Makefile、Visual Studio 项目文件等)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/63681.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【友加畅捷】软件保存/激活云加密/授权码的时候失败。

【问题现象】 畅捷通T1飞跃专业版&#xff0c;在保存云加密的时候提示&#xff1a; 获取加密失败&#xff0c;请检查数据库是否正确连接。 【解决方法】 服务器目录FYDogServer.ini文件&#xff0c;将DogCloud0改成DogCloud1&#xff0c; 然后重新保存。 【问题现象】 U通用…

单链表(数组模拟)

单链表的结构 用数组来模拟的话&#xff0c;需要两个数组&#xff0c;通过下标关联起来 例如&#xff1a; #include <bits/stdc.h>using namespace std;const int N 100010;int e[N]; //储存第i个插入的数的值 int ne[N]; //储存下标为i的next指针 int n; int idx1; int…

docker compose容器编排工具

华子目录 docker compose概述主要功能工作原理docker compose中的管理层docker compose的常用命令参数构建和重新构建服务docker compose的yaml文件一、服务&#xff08;services&#xff09;二、数据卷&#xff08;volumes&#xff09;三、网络&#xff08;networks&#xff0…

科普时刻 | 无线充电热管理:挑战与解决方案

无线充电器可通过电磁感应&#xff0c;在不直接进行电接触的情况下执行电能传输&#xff0c;因此无需繁杂的电缆电线连接&#xff0c;便可为我们的手机、手表、平板电脑以及耳机等设备供电。然而&#xff0c;随着对电子设备更快充电的需求不断增加&#xff0c;热管理对于防止过…

用ChatGPT-o1进行论文内容润色效果怎么样?

目录 1.引导问题发现 2.角色设定 3.整理常问修改 4.提供样例 5.小细节 小编在这篇文章中分享如何充分利用ChatGPT-o1-preview来提升论文润色的技巧。小编将持续跟进最新资源和最新的调研尝试结果&#xff0c;为宝子们补充更多实用的写作技巧。这些技巧将有助于您更有效地利…

数据可视化大屏UI组件库:B端科技感素材PSD

在数据可视化领域&#xff0c;一个出色的大屏UI设计不仅能够准确传达数据背后的信息&#xff0c;更能提升用户的视觉体验。然而&#xff0c;对于UI设计师而言&#xff0c;设计这样一款界面往往面临着寻找合适设计素材的挑战。为了应对这一难题&#xff0c;我们推出了这款数据可…

使用elasticsearch-java客户端API生成DSL语句

在Elasticsearch7.15.0之后&#xff0c;官方提供了elasticsearch-java包作为java客户端工具包&#xff0c;用于取代elasticsearch-rest-high-level-client&#xff0c;其底层依然依赖Elasticsearch Low Level REST 客户端&#xff0c;即elasticsearch-rest-client。 elasticsea…

Python OpenCV按照像素点图片切割

图像分割是从图像处理到图像分析的关键步骤&#xff0c;在目标检测、特征提取、图像识别等领域具有广泛应用。OpenCV是一个强大的计算机视觉库&#xff0c;提供了多种图像分割方法。本文将详细介绍如何使用Python和OpenCV进行基于像素点的图像分割&#xff0c;包括阈值分割、自…

selenium:新窗口切换、关闭

背景 当前页面A&#xff0c;点击跳转到页面B 句柄就是你点击一个页面,跳转了一个新的窗口。你要操作的元素可能在原窗口上,也有可能在新窗口上。 通过索引定位 window_handles driver.window_handlesdriver.switch_to.window(window_handles[1])#定位到第二个通过当前页面的…

Kubernetes和ZStack分配CPU的机制

在 Kubernetes (k8s) 环境中限制 CPU 资源与在 ZStack 虚拟机中分配 CPU 资源的机制存在一些关键差异。以下是这两种环境下 CPU 分配机制的详细对比&#xff1a; Kubernetes 中的 CPU 管理 资源请求与限制&#xff1a;Kubernetes 允许你为每个容器指定 CPU 请求&#xff08;re…

深度学习中的损失函数

损失函数是深度学习模型训练过程中不可或缺的一部分&#xff0c;是模型预测值与真实值之间差异的客观衡量标准。它们是模型训练的基础&#xff0c;指导算法调整模型参数&#xff0c;以最小化损失并提高预测准确性。它们衡量了模型预测值与真实值的吻合程度。通过最小化这种损失…

#自定义数据类型-简单模拟进程执行

#include <iostream> #include <string> #include <iomanip> using namespace std;//定义一个名为process的结构体&#xff0c;用于表示进程相关信息 //包含进程名、进程ID、进程优先级、进程状态、进程所需CPU时间、进程描述等成员 struct process {string …

KNN算法做预测的几个例子

准备工作 # 安装机器学习算法所用到的第三方库 pip install numpy pip install pandas pip install scikit-learn pip install matplotlibKNN算法 示例一&#xff1a; 鸢尾花数据集分类 Iris也称鸢尾花卉数据集&#xff0c;是一类多重变量分析的数据集。数据集包含150个数据…

【论文阅读】处理器芯片敏捷设计方法:问题与挑战

作者&#xff1a;包云岗老师 包云岗老师是计算机体系结构方向的大牛&#xff0c;推动了体系结构方面的开源事业! 欢迎对本栏目感兴趣的人学习"一生一芯"~ 学习体会&#xff1a; 已有的软硬件生态系统和开发成本制约了对新结构的探索。但目前仍在几种路线上做尝试~ 1…

20. 内置模块

一、random模块 random 模块用来创建随机数的模块。 random.random() # 随机生成一个大于0且小于1之间的小数 random.randint(a, b) # 随机生成一个大于等于a小于等于b的随机整数 random.uniform(a, b) …

嵌入式的软实时和硬实时系统

我觉得嵌入式的软实时和硬实时系统&#xff0c;一定要在应用场景里面去判断。假如你的需求是一个任务的执行时间&#xff0c;必须在2ms内响应&#xff0c;那么你选择的一个系统&#xff0c;系统的设计最晚响应时间是10us&#xff0c;那么这个系统对你来说就是硬实时的。 而且这…

Redis原理—4.核心原理摘要

大纲(9870字) 1.Redis服务器的Socket网络连接建立 2.Redis多路复用监听与文件事件模型 3.基于队列串行化的文件事件处理机制 4.完整的Redis Server网络通信流程 5.Redis串行化单线程模型为什么能高并发 6.Redis内核级请求处理流程与原理 7.Redis通信协议与内核级请求数据…

【UE5】制作插件 并调试【vs2022】

视频教程&#xff1a;好看视频-轻松有收获 https://www.youtube.com/watch?vIjpa9mI2b5I 官方&#xff1a;https://dev.epicgames.com/documentation/zh-cn/unreal-engine/plugins-in-unreal-engine 原文&#xff1a;【UE】制作插件_ue插件-CSDN博客 C制作插件 1. 我们可…

cocos creator 的 widget组件的使用及踩坑

以下的内容基于cocos creator 3.8版本&#xff0c;如有错误&#xff0c;恳请指出。 &#x1f449;官方文档的指引 应用&#xff1a;以上官方指引有非常清晰的使用方式&#xff0c;接下来说明一些注意事项&#xff1a; 1、与canvas搭配的使用&#xff0c;解决多分别率适配问题。…

十五、K8s计划任务JobCronJob

K8s计划任务CronJob&Job 一、Job可以干什么 Job 控制器用于管理 Pod 对象运行一次性任务,比方说我们对数据库备份,可以直接在 k8s 上启动一个 mysqldump 备份程序,也可以启动一个 pod,这个 pod 专门用来备份用的,备份结束 pod 就可以终止了,不需要重启,而是将 Pod…