cmake-自动识别新增子模块

2023-05-16

实际的项目中可能会有这种需求,随着项目的进行,会有新增的子模块,如果每新增一个子模块,顶层CMakeLists.txt都要同步修改一次,一般工程代码加入了版本控制,那么顶层CMakeList.txt每次都要提交,这种低效的重复性动作就要坚决干掉。要怎么干呢?就是本文要介绍的方法。同时也会详细介绍涉及的小知识点。

目录结构

|-- build
|-- CMakeLists.txt
`-- src
    |-- inc
    |-- main.c
    |-- module1
    |   `-- CMakeLists.txt
    `-- module2
        `-- CMakeLists.txt

CMakeLists.txt

顶层CMakeLists.txt

cmake_minimum_required(VERSION 3.12)
project(test08)

# 获取子模块目录
execute_process(
    COMMAND ls ${PROJECT_SOURCE_DIR}/src
    OUTPUT_VARIABLE mydirs
    )
message("mydirs: ${mydirs}") # 打印文件名和目录名
string(REPLACE "\n" ";" dirs_list ${mydirs})

# 编译下一级所有子模块
foreach(item ${dirs_list})
    if(IS_DIRECTORY ${PROJECT_SOURCE_DIR}/src/${item} AND (NOT (${item} STREQUAL "inc")))
        message("item:${item}") # 打印过滤后的模块名
        add_subdirectory(${PROJECT_SOURCE_DIR}/src/${item})
    endif()
endforeach()

aux_source_directory(${PROJECT_SOURCE_DIR}/src src_dirs)
add_executable(test ${src_dirs})

第5-10行 获取src目录下的 文件名和目录名列表;

第13-18行 剔除文件名和需要排除的目录名,剩下的目录名即为模块名,然后通过add_subdirectory()编译子模块。

如此,即可实现,新增目录名,而不同修改顶层CMakeLists.txt,能自动"识别"新增模块并编译。

简单起见,modulex下的CMakeLists.txt仅使用message打印一下,表示有被执行到。

module1/CMakeLists.txt

message("111-module1")

module2/CMakeLists.txt

message("222-module2")

接下来,我们先cmake一下,看看整体的效果:
在这里插入图片描述

假设现在需要新增一个module3,我们只需要将新增的module3加入src目录下即可,而其它部分不需要修改。
在这里插入图片描述

ok,到这一步相信你已经会使用了,但是这背后的原理是怎样的呢?继续前进。。。

execute_process()

execute_process(COMMAND <cmd1> [<arguments>]
                [COMMAND <cmd2> [<arguments>]]...
                [WORKING_DIRECTORY <directory>]
                [TIMEOUT <seconds>]
                [RESULT_VARIABLE <variable>]
                [RESULTS_VARIABLE <variable>]
                [OUTPUT_VARIABLE <variable>]
                [ERROR_VARIABLE <variable>]
                [INPUT_FILE <file>]
                [OUTPUT_FILE <file>]
                [ERROR_FILE <file>]
                [OUTPUT_QUIET]
                [ERROR_QUIET]
                [COMMAND_ECHO <where>]
                [OUTPUT_STRIP_TRAILING_WHITESPACE]
                [ERROR_STRIP_TRAILING_WHITESPACE]
                [ENCODING <name>]
                [ECHO_OUTPUT_VARIABLE]
                [ECHO_ERROR_VARIABLE])

execute_process命令的语法要素非常多,这里不一一介绍,仅介绍和主题相关的内容。execute_process的作用简单说就是启动一个子进程执行COMMAND命令,并能获取COMMAND命令的执行结果及输出信息。

COMMAND <cmd1> [<arguments>]

CMake executes the child process using operating system APIs directly. All arguments are passed VERBATIM to the child process. No intermediate shell is used, so shell operators such as > are treated as normal arguments. (Use the INPUT_*, OUTPUT_*, and ERROR_* options to redirect stdin, stdout, and stderr.)

cmd1可以是linux命令,COMMAND需要注意的是不支持命令行交互,需要用INPUT_*, OUTPUT_*, and ERROR_*来重定向stdin, stdout, and stderr。

OUTPUT_VARIABLE <variable>, ERROR_VARIABLE <variable>

The variable named will be set with the contents of the standard output and standard error pipes, respectively. If the same variable is named for both pipes their output will be merged in the order produced.

OUTPUT_VARIABLE 对应的变量用来接收cmd的标准输出。如果OUTPUT_VARIABLE 和ERROR_VARIABLE的变量名相同,那么,标准输出和标准错误输出的内容会按产生顺序 保存到该变量中。

如顶层CMakeLists.txt中的

execute_process(
    COMMAND ls ${PROJECT_SOURCE_DIR}/src
    OUTPUT_VARIABLE mydirs
    )

ls ${PROJECT_SOURCE_DIR}/src 命令的标准输出结果 就保存在 mydirs变量中。

由于mydirs变量的值是’inc\nmain.c\nmodule1\nmodule2\nmodule3\n’,而期望得到的是一个列表,所以还需要对mydirs进行处理。因为mydirs的值是字符串,所以要用到string命令。

string()

cmake的字符串(string)操作也比较多,这里仅介绍替换操作。

string(REPLACE <match-string> <replace-string> <out-var> <input>...)

<input>中的所有和<match-string>匹配的字符(串)替换为<replace-string>的字符(串),然后将替换后的字符串保存到<out-var>中。

举个栗子:

string(REPLACE "\n" ";" dirs_list ${mydirs})

已知mydirs变量的值是’inc\nmain.c\nmodule1\nmodule2\nmodule3\n’,就是将其中的’\n’替换为’;’,最后保存在dirs_list中,其值为"inc;main.c;module1;module2;module3;"。

得到dirs_list后,发现里面有我们不想要的内容(inc;main.c),接下来,就将这些内容过滤掉;显然,要过滤掉列表的部分元素,得遍历一遍该列表,那么cmake中可以通过foreach命令来实现。

foreach()

foreach(<loop_var> <items>)
  <commands>
endforeach()

<items>是一个列表,里面的元素可用分号或空格隔开。foreach和endforeach必须要成对。每一次循环,都将取出items列表中的一个元素存入loop_var中,直至遍历完成,这是正常的一般依次遍历控制流程。你也可以使用breakcontinue

举个栗子:

foreach(item ${dirs_list})
    if(IS_DIRECTORY ${PROJECT_SOURCE_DIR}/src/${item} AND (NOT (${item} STREQUAL "inc")))
        message("item:${item}") # 打印过滤后的模块名
        add_subdirectory(${PROJECT_SOURCE_DIR}/src/${item})
    endif()
endforeach()

已知dirs_list的值为"inc;main.c;module1;module2;module3;",IS_DIRECTORY 判断 ${PROJECT_SOURCE_DIR}/src/${item}是否为目录,同时(NOT (${item} STREQUAL "inc"))过滤inc目录;这样就完成了子模块的"识别",然后通过add_subdirectory完成子模块的编译。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

cmake-自动识别新增子模块 的相关文章

随机推荐

  • PX4开发说明

    本栏文档主要参考PX4的用户指导 xff1b 记录在px4开发过程中的心得体会和备忘 xff1b PX4 User Guide https docs px4 io master en dev setup dev env html
  • prometheus学习

    记录一下在阿木实验室 学习开源项目prometheus的过程
  • Error: No valid host was found.

    使用openstack创建虚拟机经常会遇到以下的这个错误 Error No valid host was found There are not enough hosts available 从字面意思就可以看出是无法找到可用的host的资
  • debian sid 安装 sopcast

    刚刚装了sopcast 由于是编译的 xff0c 所以记录一下以便以后删除干净 http sopcast com download linux html 上有详细说明 1 xff09 下载 sp auth tgz xff0c 把sp sc
  • 2.1 mavros发布位置指令控制px4

    1 说明 写一个节点给px4发送位置控制指令 xff0c 比如我想让飞机飞到10 xff0c 10 xff0c 10这个坐标 xff1b 2 发布和订阅的mavros主题 发布的主题 xff1a mavros setpoint positi
  • 2.2 mavros发布姿指令控制PX4

    说明 使用遥控飞行 px4在stablize模式下 xff0c 我们使用遥控器去控制px4飞行 xff1b 在飞行过程中 xff0c 通常我们用4个通道就可以控制飞机飞行 xff1b 其中roll pitch yaw打杆的量就是我们期望无人
  • 关于PX4上PID调参

    使用PX4 log view 工具 地址 setp response for roll rate 找到setp response for roll rate这个图片 从图片中可以看到 xff0c roll方向的角速度响应时间不够快 xff1
  • 【record】1、Prometheus-V2 初体验

    一 环境搭建 平时习惯使用虚拟机 xff0c 刚好阿木的公众号里面有送镜像 xff0c 于是在V1的时候就用这个镜像在run了 xff0c 这次V2出来 xff0c 直接pull就可以开始起飞了 xff1b xff08 感觉用虚拟机加镜像是
  • 【record】2、使用非官方遥控器适配prometheus的驱动修改

    0 前言 xff1a prometheus V2推荐使用阿木的遥控器 但是家里遥控器实在太多了 xff0c 所以就尝试修改一下prometheus里关于joystick的驱动 xff0c 使其适配prometheus的控制 xff1b 本篇
  • 【recode】3、地面站使用步骤与体验

    一 前言 从Prometheus的V1到V2 xff0c 无人机的状态显示是在终端中 xff0c 在一堆字符中寻找想要关注的信息 xff0c 确实硬核 xff1b 而今 xff0c 随着社会与科技的发展 xff0c Prometheus也开
  • 【recode】4、二维码自主降落与重复测试code修改

    0 前言 使用二维码辅助无人机降落 xff0c 模拟飞机先飞到二维码上空一定的高度 xff0c 然后切换到command control模式 xff1b 飞机会自动识别二维码的位置然后调整自身的X和Y位置信息 xff0c 同时控制高度进行下
  • 【code review】2、关于高度的估计过程

    0 前言 在定高模式中 xff0c 飞控需要有当前高度的信息 xff0c 也就是z的position信息 xff0c 进行Z轴的位置环控制 xff1b 那么这个Z轴的位置信息是怎么来的呢 xff1f 本文为在解读wukong FPV源码中Z
  • (开源)正点原子飞控+北醒tof+优象光流——室内定点(一)

    1 说明 xff1a 前几篇文章讲述了如何使用tof的数据实现飞机的定高 xff1b 接下来分享的是如何使用光流来定点 xff1b 主要分为以下几个步骤 xff1a 1 xff09 添加光流驱动 xff0c 获得x y轴方向的观测速度 xf
  • STM32的三种更新固件的方式

    说明 xff1a stm32有三种更新固件的方式 xff0c 分别为 xff08 1 xff09 DFU模式 xff08 Development Firmware Upgrade 即 开发固件升级 xff09 xff1b xff08 2 x
  • 有哪些比较好用的安卓模拟器(电脑端)

    模拟器帮助我们实现在电脑上玩手游的下载 目前市面上安卓模拟器软件看着种类繁多 xff0c 哪些模拟器比较好用呢 xff1f 但其实只有两大技术流派 xff1a Bluestacks和Virutalbox Bluestacks的历史可以追溯到
  • [icm42688]_readme

    记录一个使用icm42688的坑 xff1b 上图为42688的引脚连接图 xff1b 引脚说明处标注如果FSYNC不使用需要接地 xff1b 在实际测试驱动的过程中 xff0c 由于没有将该pin接地 xff0c 所以无法读取id 从机没
  • atbetaflight——指定commit号编译固件

    一 说明 在开发过程中 xff0c 比如成员A上传了一次code 而成员B需要测试本次提交的code xff0c 但是由于没有搭建ci 成员B就需要自己拉code编译 xff0c 本文将详细说明编译步骤 xff1b 二 步骤 1 使用vsc
  • atbf中imu数据的读取与处理方式

    一 说明 本文为作者在阅读atbf源码的过程中 xff0c 对atbf中imu数据的读取和处理方式的个人理解 xff0c 可能存在不对之处 xff0c 意在抛砖引玉 xff0c 请各位老师多多指正 xff1b 二 数据读取流程图 1 tar
  • atbf中imu数据读取逻辑分析仪抓取

    一 说明 使用逻辑分析仪抓区imu的spi和中断io的信号 xff0c 从而侧面描述atbf在imu上的数据读取方式 xff1b 二 硬件说明 1 硬件材料 1 mcu at32F437开发板 2 imu icm42688p 3 逻辑分析仪
  • cmake-自动识别新增子模块

    实际的项目中可能会有这种需求 xff0c 随着项目的进行 xff0c 会有新增的子模块 xff0c 如果每新增一个子模块 xff0c 顶层CMakeLists txt都要同步修改一次 xff0c 一般工程代码加入了版本控制 xff0c 那么