cmake操作目录

目录

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就不会自动的去构建依赖项.

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

java环境搭建2-idea安装激活

windows环境装Java开发环境与idea安装激活 安装jdk安装idea激活idea新建项目开启Java学习 java环境搭建2-idea安装激活 之前安装了wslLinux子环境的Java开发环境,但是再许多地方没有人使用vscode进行Java开发,因为环境配置很麻烦,还有各种插件. windows环境装Java开发环境与ide…

django-vue-admin curd_demo 快速crud教程

django-vue-admin curd_demo 快速crud教程 快速CRUD开发教程:https://bbs.django-vue-admin.com/article/9.html 如何在 env.py 文件配置Mysql数据库:https://bbs.django-vue-admin.com/question/4.html 导入导出配置教程:https://bbs.djang…

机器学习总览

机器学习 1.什么是机器学习? 机器学习是使计算机像人类一样学习与行动的科学,并通过观察与现实世界交互的形式向计算机提供数据和信息,从而随着时间的推移以自主的方式改善其学习。 通过经验提高某些任务性能的计算机程序。 人工智能>机器…

人工智能与Chat GPT

一本书全面掌握ChatGPT,既有向ChatGPT提问的技巧, 也有构建自己的ChatGPT模型的方法,涵盖开发背景、关联技术、使用方法、应用形式、实用案例等 人工智能是我们这个时代最热门的话题,人们既希望它能代替我们做一些工作&#xff0c…

tecplot360 只显示指定phase的设定体积分数的区域

tecplot360 只显示指定phase的设定体积分数的区域 到数入据抽取切面设定显示体积分数范围 参考1: Tecplot中如何提取水线面(自由表面)并绘图 参考2: 两相流计算中,如何用Tecplot提取水相断面平均物理量? …

HTTP 协议的基本格式

目录 1.基本格式 首行 请求报头 关于cookie 关于Referer 响应的报文 首行 关于状态码 1.基本格式 让我们来看看fiddler抓包的下的实际报文情况 首行 在http1.1中,有如下方法 POST、GET、HEAD、PUT、OPTIONS、DELETE、TRACE、CONNECT 在我们抓包遇到的环境中&…

【花雕】全国青少年机器人技术一级考试备考实操搭建手册8

随着科技的不断进步,机器人技术已经成为了一个重要的领域。在这个领域中,机械结构是机器人设计中至关重要的一部分,它决定了机器人的形态、运动方式和工作效率。对于青少年机器人爱好者来说,了解机械结构的基础知识,掌…

Stable Diffusion WebUI Ubuntu 22.04 LTS RTX2060 6G 极限显存出图

模型 默认选中 chilloutmix_Ni.safetensors&#xff0c;重启webui.sh进程 正向词 best quality, ultra high res, (photorealistic:1.4), 1girl, <lora:koreanDollLikeness_v15:1> ,<lora:yaeMikoRealistic_yaemikoMixed:1>, 反向词 paintings, sketches, (…

基于simulink使用光流法跟踪汽车(附源码)

一、前言 此示例演示如何使用光流估计在视频序列中检测和跟踪汽车。 二、模型 下图显示了使用光流跟踪汽车模型&#xff1a; 三、用光流结果跟踪汽车 该模型使用光流估计技术来估计视频序列的每一帧中的运动矢量。通过阈值化运动矢量&#xff0c;该模型创建包含移动对象斑点…

K8S安全管理

1 安全管理 1.1 安全框架 1.1.1 认证框架 学习目标 这一节&#xff0c;我们从 基础知识、认证流程、小结 三个方面来学习。 基础知识 资源操作 用户访问k8s业务应用的流程&#xff1a;方法一&#xff1a;无需api_server认证用户 -- ingress|service -- pod方法二&#xf…

什么事RPC并实现一个简单的RPC

1. 基本的RPC模型 主要介绍RPC是什么&#xff0c;基本的RPC代码&#xff0c;RPC与REST的区别&#xff0c;gRPC的使用 1.1 基本概念 RPC&#xff08;Remote Procedure Call&#xff09;远程过程调用&#xff0c;简单的理解是一个节点请求另一个节点提供的服务本地过程调用&am…

K8S的概念和基本应用

学习视频&#xff1a;Kubernetes基本概念和应用_哔哩哔哩_bilibili 零 . 架构概览 master节点&#xff1a;管理调度集群资源&#xff0c;一般为多节点构成&#xff0c;可以是物理机&#xff0c;也可以是虚拟机。worker节点&#xff1a;资源的提供者&#xff0c;一般为多节点构…

day03 重新学python——python函数

文章目录 一、python函数1.函数介绍2.函数的定义3.函数的参数4.函数的返回值5.函数的说明文档6.函数的嵌套调用7.变量的作用域8.综合案例 一、python函数 1.函数介绍 函数&#xff1a;即组织好的、课重复利用&#xff0c;用来实现特殊功能的代码段&#xff0c;这样可以提高代码…

揭秘python函数:编程艺术的核心力量(3)

文章目录 前言递归lambda表达式lambda 的参数形式无参数位置参数关键字参数缺省参数可变参数1.包裹位置传递2.包裹关键字传递 带判断条件的lambda表达式列表数据按照字典key的值进行排序 高阶函数的使用内置高阶函数1.map()2.reduce()3.filter() 前言 前面我们已经学习了 pyth…

uniapp 小程序 vue TypeError: Cannot read property ‘toString‘ of undefined

是因为对字符串使用toString的时候页面中的数据还没有加载 。错误代码&#xff1a; 可以使用 v-if 修改为&#xff1a;

matlab解微分方程

1.匿名函数 1.1创建 f(变量) 表达式; f(x1,x2) x1.^2x2;1.2 求解 x1为2 3 4 5&#xff1b;x2为3 4 5 6的情况下求解函数f的值 f(x1,x2) x1.^2x2; yf(2:5,3:6); subplot(121);%选择子图位置 plot(y)%画图2.一阶微分方程 用“dsolve” 2.1例 y.-y0 step1: 申明自变量和因…

ElasticSearch基础学习(SpringBoot集成ES)

一、概述 什么是ElasticSearch&#xff1f; ElasticSearch&#xff0c;简称为ES&#xff0c; ES是一个开源的高扩展的分布式全文搜索引擎。 它可以近乎实时的存储、检索数据&#xff1b;本身扩展性很好&#xff0c;可以扩展到上百台服务器&#xff0c;处理PB级别的数据。 ES也…

最新版Flink CDC MySQL同步MySQL(一)

1.概述 Flink CDC 是Apache Flink 的一组源连接器&#xff0c;使用变更数据捕获 (CDC) 从不同数据库中获取变更。Apache Flink 的 CDC Connectors集成 Debezium 作为捕获数据更改的引擎。所以它可以充分发挥 Debezium 的能力。 2.支持的连接器 连接器数据库驱动mongodb-cdc…

支持跨语言、人声狗吠互换,仅利用最近邻的简单语音转换模型有多神奇

AI 语音转换真的越复杂越好吗&#xff1f;本文就提出了一个方法简单但同样强大的语言转换模型&#xff0c;与基线方法相比自然度和清晰度毫不逊色&#xff0c;相似度更是大大提升。 AI 参与的语音世界真神奇&#xff0c;既可以将一个人的语音换成任何其他人的语音&#xff0c;…

【VsCode远程开发】Windows SSH远程连接Linux服务器 - 无公网IP内网穿透

文章目录 前言视频教程1、安装OpenSSH2、vscode配置ssh3. 局域网测试连接远程服务器4. 公网远程连接4.1 ubuntu安装cpolar内网穿透4.2 创建隧道映射4.3 测试公网远程连接 5. 配置固定TCP端口地址5.1 保留一个固定TCP端口地址5.2 配置固定TCP端口地址5.3 测试固定公网地址远程 转…