cmake操作目录

news2024/9/22 9:37:32

目录

cmake如何使用子目录

demo

cmake生成build目录结构 

如果指定子目录编译文件名字(binaryDir)

 如果指定子目录编译的路径(binaryDir)

子目录相关的作用域

demo

子目录中定义project


cmake如何使用子目录

如果项目比较小的话,我们将所有源码文件放到一个目录里面是没问题的.但是当项目越复杂的时候,如果把所有的源文件都放在一个目录里面就不太现实.

大多数真实的项目往往都不是demo级别的,都需要使用目录结构来管理项目的源码.将项目文件放在不同的目录中,这就会影响到cmake管理的构建系统.

cmake提供了两个命令来解决多级目录的问题,它们分别是add_subdirectory()和include().

add_subdirectory()将另一个目录引入构建系统,通过add_subdirectory()引入一个新的目录,这个新的目录必须有它自己的CMakeLists.txt文件.

add_subdirectory()格式如下:

add_subdirectory(sourceDir [binaryDir] [EXCLUDE_FROM_ALL] [SYSTEM])
# [SYSTEM] 需要cmake >= 3.25

sourceDir通常是当前CMakeLists.txt所在的目录的子目录,但是它也可以是其它路径下的目录.可以指定绝对路径或者相对路径,如果是相对路径的话,是相当于当前目录的.

通常binaryDir不需要指定,不指定的情况下,cmake在构建目录中对应的位置创建和源码目录对应的目录,用于存放构建输出,但是如果sourceDir是源外路径的话,binaryDir需要明确指定.

cmake管理的项目默认会生成一个ALL的目标,当使用cmake --build build 命令进行构建的时候,默认构建的这个目标,通常这个目标会依赖其它所有cmake命令定义的目标,但是使用add_subdirectory()命令引入新的目标的时候,我们可以使用EXCLUDE_FROM_ALL 关键字,将整个目录从ALL目标中排除,这样这个目录中定义的目标就不会是ALL目标的依赖,构建ALL目标的时候就不会构建这个目录中定义的目标.

但是非常不幸的是,对于某些cmake版本和生成器,EXCLUDE_FROM_ALL 的行为并不符合预期,所以建议在add_subdirectory()命令引入新目录的时候不要使用EXCLUDE_FROM_ALL关键字.

有时候开发人员需要知道与当前源代码目录对应的构建目录的位置,例如在复制运行时需要的文件或者执行自定义构建任务时.通过add_subdirectory()命令,源代码和构建树的目录结构都可以任意复杂.

甚至可能有多个使用相同源代码树的构建树.因此开发人员需要一些cmake的帮助来确定感兴趣的目录.为此,cmake提供了一些变量来跟踪当前正在处理的CMakeLists.txt文件的二进制目录.以下是一些只读变量,随着每个文件被cmake处理,这些变量会自动更新.他们始终包含绝对路径/

  • CMAKE_SOURCE_DIR
    • 源代码的最顶级目录(即最顶级的CMakeLists.txt文件所在位置).这个变量值永远不会改变.
  • CMAKE_BINARY_DIR
    • 构建目录的最顶级目录.这个变量的值永远不会改变.
  • CMAKE_CURRENT_SOURCE_DIR
    • 当前正在被cmake处理的CMakeLists.txt文件所在的目录.每当由add_subdirectory()调用处理新文件时,它就会更新,当处理该目录完成时,它会被返回原来的值.
  • CMAKE_CURRENT_BINARY_DIR
    • 由cmake处理的当前CMakeLists.txt文件对应的构建目录.每次调用add_subdirectory()时都会更改该目录.当add_subdirectory()返回时将其恢复.

demo

目录结构:016目录下由一个顶级CMakeLists.txt和一个subDir子目录.子目录下有一个CMakeLists.txt 那个build是我cmake自己生成的 

top CMakeLists.txt

cmake_minimum_required(VERSION 3.26 FATAL_ERROR)

project(project016
    VERSION 0.0.1
    LANGUAGES CXX)


message("top: CMAKE_SOURCE_DIR           = ${CMAKE_SOURCE_DIR}")
message("top: CMAKE_BINARY_DIR           = ${CMAKE_BINARY_DIR}")
message("top: CMAKE_CURRENT_SOURCE_DIR   = ${CMAKE_CURRENT_SOURCE_DIR}")
message("top: CMAKE_CURRENT_BINARY_DIR   = ${CMAKE_CURRENT_BINARY_DIR}")

add_subdirectory(subDir)

message("top: CMAKE_CURRENT_SOURCE_DIR   = ${CMAKE_CURRENT_SOURCE_DIR}")
message("top: CMAKE_CURRENT_BINARY_DIR   = ${CMAKE_CURRENT_BINARY_DIR}")

subDir CMakeLists.txt

cmake_minimum_required(VERSION 3.26 FATAL_ERROR)

message("mysub: CMAKE_SOURCE_DIR           = ${CMAKE_SOURCE_DIR}")
message("mysub: CMAKE_BINARY_DIR           = ${CMAKE_BINARY_DIR}")
message("mysub: CMAKE_CURRENT_SOURCE_DIR   = ${CMAKE_CURRENT_SOURCE_DIR}")
message("mysub: CMAKE_CURRENT_BINARY_DIR   = ${CMAKE_CURRENT_BINARY_DIR}")

cmake生成build目录结构 

 一个顶层结构和一个subDir目录.

如果指定子目录编译文件名字(binaryDir)

add_subdirectory(subDir subDir_build)

 

 如果指定子目录编译的路径(binaryDir)

add_subdirectory(subDir ../subbuild/subDir_build)

需要注意的是默认的编译路径是cmake  -S . -B build 这个指定的路径上面我该了相对位置,在build的上一级目录subbuild,名字是subDir_build

 

 不建议随便修改子模块编译目录,让cmake自己决定.

子目录相关的作用域

add_subdirectory()命令引入一个新的子目录的同时,也引入了新的作用域,相对与调用add_subdirectory()命令的CMakeLists.txt所在的作用域来说,通过add_subdirectory()命令引入的新的作用域叫做子作用域.其行为类似于C++语言中调用一个新的函数.

  • 调用add_subdirectory()命令的时候,当前作用域内的变量均会复制一份到子作用域.子作用域中对那些复制的变量进行操作不会影响到父作用域中这些变量的值.
  • 在子作用域中定义的新的变量对父作用域是不可见的.

demo

top CMakeLists.txt

cmake_minimum_required(VERSION 3.26 FATAL_ERROR)

project(project016
    VERSION 0.0.1
    LANGUAGES CXX)

set(myVar foo)
message("Parent (before): myVar = ${myVar}")
message("Parent (before): childVar = ${childVar}")
add_subdirectory(subDir)
message("Parent (after): myVar = ${myVar}")
message("Parent (after): childVar = ${childVar}")

subDir CMakeLists.txt

cmake_minimum_required(VERSION 3.26 FATAL_ERROR)

message("Child (before): myVar = ${myVar}")
message("Child (before): childVar = ${childVar}")
set(myVar bar)
set(childVar fuzz)
message("Child (after): myVar = ${myVar}")
message("Child (after): childVar = ${childVar}")

set命令有个关键字PARENT_SCOPE,这个关键字可以变量传递给上一级不在本级作用.上一级不一定是子目录传递给父目录,也可以是block传递出去.

只需要在subDir添加

set(myVar bar PARENT_SCOPE)
set(childVar fuzz PARENT_SCOPE)

子目录中定义project

project()命令对于一个项目是必须的,如果开发人员没有显示的调用project()命令,在运行cmake进行项目配置的时候会收到警告信息.同时,cmake会隐式的添加project()命令的调用.强烈建议在顶层CMakeList.txt中适当的位置显示的调用project()命令.

虽然我们可以通过函数或者cmake脚本对project()命令进行封装,然后通过调用函数或者include() camke 脚本的方式间接的调用project()命令,但是这些都是强烈不建议的,最好的方式是在CMakeList.txt中适当的位置显示的调用project()命令.

其次,project()命令可不可以多次调用?答案是可以的,但是需要由add_subdirectory()命令调用才可以.也就是说,我们不能在同一个CMakeLists.txt中调用多次project()命令,多次调用会以最后一次调用为准. 但是可以在add_subdirectory()命令调用时引入子目录中的CMakeLists.txt中再次调用project()命令通常这样做没什么坏处,但是会导致cmake生成更多的项目文件.

大多数时候,我们没有必要在每个add_subdirectory()命令引入子目录中的CMakeLists.txt中都调用project()命令.但是有的时候这会很有用.一般我们会把相对独立的模块放到一个单独的目录中,然后通过add_subdirectory()命令引入这个目录中.这种功能相对独立的模块,我们就可以给他调用一次project()命令,让它成为一个单独的项目.

虽然在子目录中调用project()命令可以让其成为一个独立的项目,但是依然在顶级或者上级项目管理下,像Visual Studio这种IDE,cmake生成的解决方案打开就可以看到每个project()命令都有一个解决方案,子目录的解决方案可以单独打开.如果打开最顶层目录的解决方案文件,所有的解决方案都可以看到.

Visual Studio如果打开子目录的解决方案,在构建的时候会自动的去构建其依赖项,但是像xcode就不会自动的去构建依赖项.

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

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

相关文章

wpf border控件和Effect学习

Border(边框)控件绘制一个边框、一个背景。 常用的属性, Background:填充 Border 边界之间的区域或者说是绘制该区域的背景,是一个Brush对象。 BorderBrush:用于绘制外部边框颜色,是Bru…

Vue 和 React 前端框架的比较

Vue 和 React 前端框架的比较 本文研究了流行的前端框架 Vue 和 React 之间的区别。通过对它们的学习曲线、视图层处理方式、组件化开发、响应式数据处理方式和生态系统及社区支持进行比较分析,得出了它们在不同方面的优劣和特点。该研究对于开发者在选择合适的前端…

QC51XX---I2c使用

QCC51XX---系统学习目录_嵌入式学习_force的博客-CSDN博客 今天我们聊聊I2C的使用。在开发过程中多多少少会加入一些外围传感器可以给用户带来更好的使用体验。例如,利用接近传感器识别戴上耳机和取下耳机,从而去自动暂停播放音乐,或接听转移通话。又例如,用触摸或敲击替代…

【vant】打开vant表单的正确形式(基于vant表单的二次封装)

前言 最近在用vant做关于移动端的项目,由于表单字段太多,不想写直接写到template中,这样太繁琐了,所以我们以把表单弄成schema配置形式: // data.ts import type { ItemSchema } from /typing/helper; import { StudentField } from /components; import { getDictTextByCode…

在tplink路由器xdr6088中运行Docker潘多拉(pengzhile/pandora)遇到无法访问的问题

在xdr6088中搜索安装pengzhile/pandora一切正常,但是按照常规运行docker后,直接访问8899端口无法打开页面,进入终端 运行如下命令 /usr/local/bin/python /usr/local/bin/pandora-cloud -s 0.0.0.0:8899 即可成功运行,然后客户端…

RabbitMQ在SpringBoot中的高级应用(2)

过期时间 1.单独的设置队列的存活时间,队列中的所有消息的过期时间一样 Bean//创建交换机public DirectExchange ttlQueueExchange(){// 交换机名称 是否持久化 是否自动删除return new DirectExchange("ttl_queue_log",true,false);}Bean//创建队列publ…

Swagger3学习笔记

参考https://blog.csdn.net/YXXXYX/article/details/124952856 https://blog.csdn.net/m0_53157173/article/details/119454044 引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifact…

云之道知识付费V2小程序V3.1.1独立平台版安装使用教程

据播播资源了解&#xff0c;云之道知识付费小程序是一款专注于知识付费的小程序源码&#xff0c;为内容创业者、自媒体和教育培训机构提供全方位的互联网解决方案。 由播播资源小编全套安装云之道知识付费V2独立版系统&#xff0c;系统支持无限多开&#xff0c;相比上几版出现…

如何创建电子商务平台

创建一个电商平台已经变得简单而又高效&#xff0c;其中乔拓云作为一家专业的第三方平台&#xff0c;提供了丰富的模板和工具&#xff0c;帮助商家快速搭建自己的电商平台。本文将介绍如何通过乔拓云平台创建电商平台&#xff0c;并提供一些建议和注意事项。 首先&#xff0c;商…

wincc项目中VBS脚本密码的研究

文章目录 前言一、分析二、验证及使用 前言 很多时候我们在wincc中写全局脚本时会为自己的脚本添加密码&#xff0c;但很久很久以后再想修改密码忘记了怎么办呢。 一、分析 经过分析v7.0,v7.3,v7.5密码稍有不同&#xff0c;但同样最多可以设置21位的密码。 二、验证及使用

支持向量机(SVM)

目录 1 引言 2 支持向量机的理论基础 1. 什么是支持向量&#xff0c;它们在模型中的作用是什么&#xff1f; 2. 线性支持向量机的数学原理 3. 解释如何通过核技巧来处理非线性问题 4. 支持向量机的优点和局限 3 支持向量机的实践 1. 如何使用Python的sklearn库创建和训练…

【计算机组成与体系结构Ⅰ】实验4 存储器原理实验

一、实验目的 1&#xff1a;了解双端口静态存储器IDT7132的工作特性及使用方法。 2&#xff1a;了解半导体存储器如何读写。 二、实验总结 0&#xff1a;实验内容 双端口存储器RAM&#xff1a; 左端口的数据部分与数据总线DBUS7-DBUS0相联&#xff1b;右端口的数据引脚与指…

【云原生】在DACS沙箱内配置Telepresence工具(社区版限制5人连接)

使用 Telepresence 映射 Kubernetes 服务到 DACS 沙箱内 Telepresence 属于沙箱工具,它可以把我们在AWS云平台的EKS(Kubernetes)上部署的服务映射到本地,这样大家就可以在本地访问EKS(Kubernetes)上的资源了,如注册中心Nacos、Redis、Kafka等服务 安装 Telepresence 安装…

使用最小二乘进行多项式曲线拟合

目录 写在前面曲线拟合方法pcl实现的b样条曲线拟合最小二乘曲线拟合原理代码注&#xff1a;结果 参考完 写在前面 1、本文内容 使用Eigen进行最小二乘拟合曲线 2、平台/环境 Eigen(open3d), cmake, pcl 3、转载请注明出处&#xff1a; https://blog.csdn.net/qq_41102371/ar…

【Git】Github 上传文件到远程仓库时,经常发生网络错误,一个比较稳定的连接方法及我的示例

文章目录 一、问题导读二、完整的一个流程2.1 初始化2.2 从远程仓库拉取最新的更改并合并到当前分支2.3 远程仓库的 SSH URL2.4 添加到暂存区2.5 提交操作2.6 将一个远程仓库添加为 Git 仓库的远程别名2.7 推送到远程仓库2.8 最后的结果 三、HTTP和SSH的理解3.1 两者的区别3.1.…

【网络系统集成】网络认证实验

1.实验名称 网络认证实验 2.实验目的 学习网络认证配置 3.实验内容 3.1拓扑结构图 3.2地址分配 <

OpenCV实战(28)——光流估计

OpenCV实战&#xff08;28&#xff09;——光流估计 0. 前言1. 光流估计原理2. 光流算法实现3. 完整代码小结系列链接 0. 前言 当相机进行拍摄时&#xff0c;拍摄到的亮度图案会投射到图像传感器上&#xff0c;从而形成图像。在视频序列中&#xff0c;我们通常需要捕捉运动模式…

HCIP--OSPF实验1

1、合理规划IP地址&#xff0c;启用ospf单区域 2、R1-R2之间启用ppp的单向认证 3、R2-R3之间启用ppp的chap认证 4、R3-R5-F6之间使用MGRE&#xff0c;R3为hub端&#xff0c;R5,R6为spoke端&#xff1b; 要求MGRE接口网络型为BMA&#xff0c;spoke之间通信必须经过hub端 5、全…

Linux--进程

什么叫做进程&#xff1f; 程序加载到内存就叫进程&#xff08;看不懂是吧&#xff0c;看下面更详细一些&#xff09; 进程对应的代码和数据进程对应的PCB结构体

MySQL索引原理和优化

目录 1 什么是索引&#xff1f;1.1 引言1.2 索引原理1.3 索引分类1.3.1 主键索引1.3.2 普通索引&#xff08;单列索引&#xff09;1.3.3 复合索引&#xff08;组合索引&#xff09;1.3.4 唯一索引1.3.5 全文索引1.3.6 索引的查询和删除 1.4 索引的优缺点 2 索引数据结构2.1 Has…