CMake简单使用(二)

目录

  • 五、scope 作用域
    • 5.1 作用域的类型
      • 5.1.1 全局作用域
      • 5.1.2 目录作用域
      • 5.1.3 函数作用域
  • 六、宏
    • 6.1 基本语法
    • 6.2 演示代码
  • 七、CMake构建项目
    • 7.1 全局变量
    • 7.2 写入源码路径
    • 7.3 调用子目录cmake脚本
    • 7.4 CMakeLists 嵌套(最常用)
  • 八、CMake 与库
    • 8.1 CMake生成动静态库
      • 8.1.1 动静态库
      • 8.1.2 常见命令
      • 8.1.3 生成静态库
        • 8.1.3.1 示例
        • 8.1.3.2 总结
      • 8.1.4 生成动态库
    • 8.2 CMake调用动静态库
    • 8.2.1 静态库调用流程:
    • 8.2.2 动态库调用流程:

五、scope 作用域

5.1 作用域的类型

5.1.1 全局作用域

  • 从CMake脚本开始运行到结束。
  • 所有CMakeLists.txt文件共享全局作用域
  • 通过set()定义的变量默认是全局变量(除非明确在函数或宏中设置为局部变量)
set(GLOBAL_VAR "I am global")
message(${GLOBAL_VAR}) # 输出: I am global

5.1.2 目录作用域

  • 每个目录中的CMakeLists.txt文件有独立的作用域
  • 子目录可以继承父目录的变量,但子目录中对变量的更改不会影响父目录,只在子目录下生效
    下面是一个demo,理解即可,暂时不尝试自己编译:
# 顶层 CMakeLists.txt
set(DIR_VAR "Parent Directory")
# 添加子目录
add_subdirectory(subdir)
# 子目录 subdir/CMakeLists.txt
message(${DIR_VAR}) # 输出: Parent Directory
set(DIR_VAR "Child Directory")

子目录进行set操作后,顶层的 DIR_VAR 不会被子目录的更改影响。

5.1.3 函数作用域

  • 在函数中定义的变量是局部变量,只在函数内有效
  • 使用set()定义变量时,作用域局限于当前函数,除非指定PARENT_SCOPE
function(set_local_var)set(LOCAL_VAR "Local Scope")message(${LOCAL_VAR}) # 输出: Local Scope
endfunction()set_local_var()
message(${LOCAL_VAR}) # 输出: (空,因为超出函数作用域)

六、宏

6.1 基本语法

macro(<name> [arg1 [arg2 ...]])# 宏体
endmacro()
  • <name> 是宏的名称。
  • [arg1, arg2…] 是参数列表(可选)。
  • 宏没有返回值,但可以通过变量或 CACHE 修改全局状态。

6.2 演示代码

cmake_minimum_required(VERSION 3.20.0)macro(Test myVar)set(myVar "new value")message ("2. argument: ${myVar}")
endmacro()set(myVar "First value")
message ("1. myVar: ${myVar}")
Test("value")
message("3. myVar: ${myVar}")

在这里插入图片描述
在这里插入图片描述

七、CMake构建项目

7.1 全局变量

在[[#1.2 初体验]]中,我们使用了以下代码:

project(hello CXX)
  • 声明项目名称为 hello,并设置主要语言为 C++(CXX)。
  • 生成项目相关的全局变量,例如:
    • ${PROJECT_NAME}:值为 hello
    • ${PROJECT_SOURCE_DIR}:项目的根目录路径。
    • ${PROJECT_BINARY_DIR}:构建目录路径。

7.2 写入源码路径

特点

  • 最简单的构建方式。
  • 适用于只有一个 CMakeLists.txt 文件的小型项目。
    目录结构
MyProject/
├── CMakeLists.txt
├── main.cpp
├──Transportation├──train.h├──tarin.cpp

CMakeLists.txt

cmake_minimum_required(VERSION 3.20.0)project(MyProject CXX)
add_executable(MyProject main.cpp 需要链接的文件路径)
  • CXX 表示语言是 cpp
  • 在原文件中,要写对应的.h文件,main.cpp:#include "Transportation/train.h",在这里就不需要再包含,但是要包含.cpp文件的路径
    构建方法
cmake -B build
cmake --build build
build/项目名称

![[IMG-20241212140631676.png]]

7.3 调用子目录cmake脚本

  • include方法可以引入子目录中的cmake后缀的配置文件
  • 将配置加入 add_executable
    目录结构:
.
├── CMakeLists.txt
├── main.cpp
└── Transportation├── car.cpp├── car.h├── train.cpp├── train.h└── transportation.cmake

transportation.cmake使用set将变量设置成需要链接的文件:

set(trans_sources Transportation/car.cpp Transportation/train.cpp)

然后在CMakeLists.txt中就可以直接使用该变量:

cmake_minimum_required(VERSION 3.20.0)
project(MyProject CXX)
include(Transportation/transportation.cmake)
add_executable(MyProject main.cpp ${trans_sources})

❗️注意:要使用include引入子目录下的cmake文件,使用变量要用${}
构建方法同上。

7.4 CMakeLists 嵌套(最常用)

  • target_include_directories 头文件目录的声明
  • target_link_libraries 连接库文件
  • add_subdirectory 添加子目录
  • add_ library 生成库文件(默认静态库)
    目录结构:
.
├── CMakeLists.txt
├── main.cpp
└── Transportation├── car.cpp├── car.h├── CMakeLists.txt├── train.cpp└── train.h

在子目录的CMakeLists.txt中,add_library 命令创建一个名为 Translib 的库,该库包含 train.cpp 和 car.cpp 两个源文件的编译结果。

add_library(Translib train.cpp car.cpp)

在父目录的CMakeLists.txt中,

cmake_minimum_required(VERSION 3.20.0)
project(MyProject CXX)add_subdirectory(Transportation)add_executable(MyApp main.cpp)target_link_libraries(MyApp PUBLIC Translib)target_include_directories(MyApp PUBLIC "${PROJECT_SOURCE_DIR}/Transportation")
  1. 定义项目
  • project(MyProject CXX) 声明项目的名称为 MyProject,并设置其主要语言为 C++。
  1. 添加子目录
  • add_subdirectory(Transportation) 将 Transportation 子目录的构建逻辑纳入父目录中。
  • 这会递归执行 Transportation 目录中的 CMakeLists.txt,构建 Translib 库。
  1. 添加可执行文件
  • add_executable(MyApp main.cpp) 声明一个名为 MyApp 的可执行目标,其源文件为 main.cpp。
  1. 链接库
  • target_link_libraries(MyApp PUBLIC Translib) 将 Translib 库链接到可执行文件 MyApp。
  • PUBLIC:表示 Translib 的头文件路径和链接库信息都对 MyProject 和其使用者可见。
  1. 包含头文件路径
  • target_include_directories(MyApp PUBLIC "${PROJECT_SOURCE_DIR}/Transportation") 明确告诉 CMake,MyProject 需要包含 Transportation 目录中的头文件(如 car.h 和 train.h),这样在main.cpp中包含头文件时就不需要再次包含路径。
    构建顺序总结
  1. 进入父目录的构建流程
  • cmake 检测到 add_subdirectory(Transportation),递归构建子目录。
  • 子目录生成 Translib 库。
  1. 构建父目录目标
  • 构建 main.cpp 并将其链接到已生成的 Translib。

八、CMake 与库

8.1 CMake生成动静态库

8.1.1 动静态库

静态库
常见命名:.a(Linux/Unix),.lib(Windows)。

在链接阶段,将汇编生成的目标文件.o与引用到的库一起链接打包到可执行文件中。
对函数库的链接是编译器的链接器在编译阶段完成静态链接的过程

动态库
常见命名:.so(Linux/Unix),.dll(Windows),.dylib(macOS

动态库是在程序运行时才会被载入到内存,当执行到库中代码时就会跳转到目标库。
动态库需要依赖操作系统的动态链接机制

8.1.2 常见命令

  • file(GLOB ...) 常用于搜索源文件
  • add_library(animal STATIC ${SRC}) 生成静态库
  • add_library(animal SHARED ${SRC}) 生成动态库
  • ${LIBRARY_OUTER_PATH} 导出目录

8.1.3 生成静态库

8.1.3.1 示例

当前目录结构如下:

.
├── CMakeLists.txt
├── include
│   ├── car.h
│   └── train.h
└── src├── car.cpp└── train.cpp

CMakeLists.txt:

cmake_minimum_required(VERSION 3.20.0)
project(MyProject CXX)file(GLOB SRC &${PROJECT_SOURCE_DIR}/src/*.cpp)
include_directories(${PROJECT_SOURCE_DIR}/include) set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/a)
add_library(trans STATIC ${SRC})

下面来解释一下上面的代码:

project(MyProject CXX)

在[[#7.1 全局变量]]中,我们了解到使用project时,除声明项目名称外,还会生成项目相关的全局变量,例如:

  • ${PROJECT_NAME}:值为 MyProject。
  • ${PROJECT_SOURCE_DIR}:项目的根目录路径。
  • ${PROJECT_BINARY_DIR}:构建目录路径。

file(GLOB SRC ${PROJECT_SOURCE_DIR}/src/*.cpp)

作用

  • 使用 file(GLOB ...) 命令,搜索 src 目录下所有以 .cpp 结尾的文件,并将它们的路径存入变量 SRC
  • GLOB 是 CMake 提供的文件搜索命令,用于匹配文件路径。
  • 示例:如果 src 目录下有 car.cpp 和 train.cpp,那么 SRC 的值将是:
/path/to/src/car.cpp
/path/to/src/train.cpp

include_directories(${PROJECT_SOURCE_DIR}/include) 

作用

  • 将 include 目录(即 car.h 和 train.h 所在目录)添加到项目的头文件搜索路径中。
  • 等效于将 -I/path/to/include 传递给编译器。
  • 这样,源文件中可以直接使用,而无需写完整路径:
#include "car.h"
#include "train.h"

set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/a)

作用

  • 指定生成的库文件的输出目录为项目根目录下的 a 子目录。
  • 如果没有这一行,CMake 默认将库文件输出到构建目录中。

add_library(trans STATIC ${SRC})

作用

  • 定义一个名为 trans 的静态库(STATIC)。
  • SRC 中列出的源文件(如 car.cpp 和 train.cpp)将被编译,并打包成静态库。
8.1.3.2 总结

生成静态库的基本步骤:

# 1. 设置 CMake 最低版本
cmake_minimum_required(VERSION 3.20)
# 2. 定义项目名称和语言
project(MyStaticLibrary LANGUAGES CXX)# 3. 添加头文件路径
include_directories(${PROJECT_SOURCE_DIR}/include)
# 4. 查找源文件
file(GLOB SRC_FILES ${PROJECT_SOURCE_DIR}/src/*.cpp)# 5. 设置库文件的输出路径
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/a)# 6. 添加静态库 声明一个静态库目标(STATIC 表示静态库),指定构成静态库的源文件。
add_library(MyStaticLib STATIC ${SRC_FILES})

8.1.4 生成动态库

生成动态库与生成静态库的步骤类似,只需要将添加静态库的STATIC改为SHARED(动态库也叫共享库)

set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/so)
add_library(trans SHARED ${SRC})

8.2 CMake调用动静态库

8.2.1 静态库调用流程:

  1. 指定静态库的路径
  2. 添加可执行文件
  3. 链接静态库
  4. 添加库的头文件路径
    假设当前目录如下:
flash@VM-12-10-ubuntu:~/2024/12/14_cmake/useLib$ tree -L 2
.
├── CMakeLists.txt
├── include
│   ├── car.h
│   └── train.h
├── Lib
│   ├── libtrans.a
│   └── libtrans.so
└── main.cpp

如果已经生成了动静态库,可以直接删除src目录,但是建议保留include目录,下面来看CMakeLists.txt的具体编写:

cmake_minimum_required(VERSION 3.20.0)
project(MyProject CXX)# 指定静态库的路径
set(STATIC_LIB_PATH ${PROJECT_SOURCE_DIR}/Lib/libtrans.a)
# 添加可执行文件
add_executable(MyExecutable main.cpp)
# 链接静态库(仅作用于 MyExecutable)
target_link_libraries(MyExecutable PRIVATE ${STATIC_LIB_PATH})
# 添加库的头文件路径(仅作用于 MyExecutable)
target_include_directories(MyExecutable PRIVATE ${PROJECT_SOURCE_DIR}/include)

8.2.2 动态库调用流程:

  1. 指定动态库的路径
  2. 添加可执行文件
  3. 链接静态库
  4. 添加库的头文件路径
cmake_minimum_required(VERSION 3.20.0)
project(MyProject CXX)# 指定动态库的路径
set(DYNAMIC_LIB_PATH ${PROJECT_SOURCE_DIR}/Lib/libtrans.so)
# 添加可执行文件
add_executable(MyExecutable main.cpp)
# 链接动态库(仅作用于 MyExecutable)
target_link_libraries(MyExecutable PRIVATE ${DYNAMIC_LIB_PATH})
# 添加库的头文件路径(仅作用于 MyExecutable)
target_include_directories(MyExecutable PRIVATE ${PROJECT_SOURCE_DIR}/include)

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

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

相关文章

ASP.NET |日常开发中读写XML详解

ASP.NET &#xff5c;日常开发中读写XML详解 前言一、XML 概述1.1 定义和结构1.2 应用场景 二、读取 XML 文件2.1 使用XmlDocument类&#xff08;DOM 方式&#xff09;2.2 使用XmlReader类&#xff08;流方式&#xff09; 三、写入 XML 文件3.1 使用XmlDocument类3.2 使用XmlWr…

自动化测试之单元测试框架

单元测试框架 一、单元测试的定义 1&#xff1a;什么是单元测试&#xff1f; 还记不记得我们软件测试学习的时候&#xff0c;按照定义&#xff1a;单元测试就是对单个模块或者是单个函数进行测试&#xff0c;一般是开发做的&#xff0c;按照阶段来分&#xff0c;一般就是单元…

JAVA爬虫获取1688关键词接口

以下是使用Java爬虫获取1688关键词接口的详细步骤和示例代码&#xff1a; 一、获取API接口访问权限 要使用1688关键词接口&#xff0c;首先需要获取API的使用权限&#xff0c;并了解接口规范。以下是获取API接口的详细步骤&#xff1a; 注册账号&#xff1a;在1688平台注册一…

【游戏设计原理】8 - 霍华德的隐匿性游戏设计法则

1. 霍华德的隐匿性游戏设计法则 霍华德的隐匿性游戏设计法则的核心思想是&#xff1a;“秘密的重要性与其表面上的无辜性和完整度成正比”。这意味着&#xff0c;当游戏开始时&#xff0c;设计上越是简洁、无害、直观的元素&#xff0c;隐藏的深层意义和转折就会显得更加震撼和…

k8s中用filebeat文件如何收集不同service的日志

以下是一个详细的从在 Kubernetes 集群中部署 Filebeat&#xff0c;到实现按web-oper、web-api微服务分离日志并存储到不同索引的完整方案&#xff1a; 理解需求&#xff1a;按服务分离日志索引 在 Kubernetes 集群中&#xff0c;有web-oper和web-api两种微服务&#xff0c;希…

前端退出对话框也就是点击右上角的叉,显示灰色界面,已经解决

文章目录 遇到一个前端bug&#xff0c;点击生成邀请码 打开对话框 然后我再点击叉号&#xff0c;退出对话框&#xff0c;虽然退出了对话框&#xff0c;但是显示灰色界面。如下图&#xff1a; 导致界面就会失效&#xff0c;点击任何地方都没有反应。 发现是如下代码的问题&am…

一区向量加权算法优化INFO-CNN-SVM卷积神经网络结合支持向量机多特征分类预测

一区向量加权算法优化INFO-CNN-SVM卷积神经网络结合支持向量机多特征分类预测 目录 一区向量加权算法优化INFO-CNN-SVM卷积神经网络结合支持向量机多特征分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.Matlab实现INFO-CNN-SVM向量加权算法优化卷积神经网络结…

【Stable Diffusion】SD安装、常用模型(checkpoint、embedding、LORA)、提示词具、常用插件

Stable Diffusion&#xff0c;一款强大的AI模型&#xff0c;让我们能够创造出惊人的艺术作品。本文将为您介绍如何安装Stable Diffusion以及深入使用的学习教程。 1. 安装Stable Diffusion (需要的小伙伴可以文末自行扫描获取) Stable Diffusion的安装可能是第一步&#xff0…

【工具变量】上市公司企业资本支出数据(1990-2022年)

一、计算方式&#xff1a;资本支出的公式为:经营租赁所支付的现金购建固定资产、无影资产和其他长期资产所支付的现金-处置固定资产、无形资产和其它长期资产而收回的现金净额。 二、数据范围&#xff1a;包括原始数据详细来源和最终数据结果 三、参考文献&#xff1a;[1]杨兴…

洛谷 P10483 小猫爬山 完整题解

一、题目查看 P10483 小猫爬山 - 洛谷 二、解题思路 我们将采取递归 剪枝的思想&#xff1a; sum数组存放每辆车当前载重。 每次新考虑一只小猫时&#xff0c;我们尝试把它放进每个可以放进的缆车中&#xff08;需要回溯&#xff09; for (int i 0; i < k; i) {if (sum[i]…

Leetcode二叉树部分笔记

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 Leetcode二叉树部分笔记 1.二叉树的最大深度2.同样的树3.翻转二叉树4.对称二叉树**5. **填充每个节点的下一个右侧节点指针 II**6. 二叉树展开为链表7. 路经总和8.完全二叉树…

如何用状态图进行设计06

独立的控制线程 扩展状态图也提供了获取无序的输入事件的方法。这意味着一个状态开始时&#xff0c;它可能位于一个或多个控制线程的交叉点。控制行为的每个独立线程都类似一个状态机&#xff0c;独自运行&#xff0c;互不干扰。因此&#xff0c;这些控制线程可能会同时发生状…

【多模态】MiniCPM-V多模态大模型使用学习

MiniCPM-V模型使用 前言1. 模型文件下载和选择2. 环境安装配置3. 模型微调3.1 qlora微调minicpm-v-int43.2 lora微调minicpm-v3.3 merge_lora3.4 lora微调后量化int4 4. 模型推理4.1 huggingface API4.2 swift API(A) swift&#xff08;不支持batch inference&#xff09;(B) s…

快速上手Neo4j图关系数据库

参考视频&#xff1a; 【IT老齐589】快速上手Neo4j网状关系图库 1 Neo4j简介 Neo4j是一个图数据库&#xff0c;是知识图谱的基础 在Neo4j中&#xff0c;数据的基本构建块包括&#xff1a; 节点(Nodes)关系(Relationships)属性(Properties)标签(Labels) 1.1 节点(Nodes) 节点…

Transformer: Attention Is All You Need (2017) 翻译

论文&#xff1a;Attention Is All You Need 下载地址如下: download: Transformer Attention Is All you need Attention Is All You Need 中文 《Attention Is All You Need》是《Transformer》模型的开创性论文&#xff0c;提出了一种全新的基于注意力机制的架构&#xf…

可视化报表如何制作?一文详解如何用报表工具开发可视化报表

在如今这个数据驱动的商业时代&#xff0c;众多企业正如火如荼地推进数字化转型&#xff0c;力求在激烈的市场竞争中占据先机。然而&#xff0c;随着业务规模的扩大和运营复杂度的提升&#xff0c;企业的数据量爆炸式增长&#xff0c;传统报表格式单一、信息呈现密集且不易解读…

Angular由一个bug说起之十二:网页页面持续占用CPU过高

随着网络日益发达&#xff0c;网页的内容也更加丰富&#xff0c;形式也更加多样化。而随之而来的性能问题也不容小觑。这篇文章我会根据我在实践中遇到的一个问题来总结&#xff0c;我在面对性能问题的一些解决步骤&#xff0c;希望能对大家有所启发。 查找问题原因 我接触的…

MATLAB图卷积神经网络GCN处理分子数据集节点分类研究

全文链接&#xff1a;https://tecdat.cn/?p38570 本文主要探讨了如何利用图卷积网络&#xff08;GCN&#xff09;对图中的节点进行分类。介绍了相关的数据处理、模型构建、训练及测试等环节&#xff0c;通过对分子数据集的操作实践&#xff0c;展示了完整的节点分类流程&#…

uniapp中vuex(全局共享)的应用

一、Vuex概述 1.1 官方解释 Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。 它采用集中式存储管理 应用的所有组件的状态&#xff0c;并以相应的规则保证状态以一种可预测的方式发生变化 - Vuex 也集成到 Vue 的官方调试工具 devtools extension&#xff0c;提供了诸…

华为云服务器搭建基于LNMP部署wordpress

Ubuntu系统搭建过程目录 一、检查环境1.1 检查是否安装Nginx1.2 检查是否安装Mysql1.3 检查是否安装PHP二、更新软件包以及安装所需要的依赖 三、安装Nginx3.1 下载并解压nginx3.2. 编译安装3.3 启动和停止和测试3.4 创建服务脚本3.5 Nginx目录 四、安装Mysql4.1 安全安装配置4…