CMakeList.txt文件详解

1 整体结构

    CMakeList.txt文件必须遵循以下的格式:

        所需的CMake版本(cmake_minimum_required)

        软件包的名称(project())

        查找构建所需要的其他CMake/Catkin软件包(find_package())

        消息/服务/运动生成器(add_message_files()    add_service_files()    add_action_files())

        调用消息/服务/动作生成(generate_message())

        制定package build info export(catkin_package())

        需要建立的库/可执行文件(add_library()    add_executable()    target_link_libraries())

        安装规则(install())


1.1 CMake版本

    每个catkin CMakeList.txt文件都必须以需要的CMake版本。

        cmake_minimum_required(VERSION 2.8.3)

1.2 软件包名称

    由CMake项目功能指定的包的名称。这里我们制作一个名为robot_brain的软件包。

        project(robot_brain)

1.3 查找相关的CMake包

    我们需要使用find_package函数来制定需要找到哪些其他的CMake包来构建我们的项目

        find_package(catkin REQUIRED)

    对于find_package来说,有两种不同的表达方式分别为:

        find_package(catkin REQUIRE COMPONENTS nodelet)

    或者

        find_package(catkin REQUIRE)

        find_package(nodelet REQUIRE)

    对于两者的区别。如果通过了find_package找到了一个包,会创建几个提供有关找到的包的消息的Cmake环境变量。

    这些环境变量导出了头文件的位置,源文件的位置,包所依赖的库以及这些库的地址。

    <NAME>_FOUND-如果找到库,则设置为true,否则为false

    <NAME>_INCLUDE_DIR/_INCLUDE-包导出的路径

    <NAME>_LIBRARIES/_LIBS-包导出的库

    如果find_package作为catkin的组件(例如第一种方式),这是有好处的。

        find_package(catkin REQUIRE COMPONENTS nodelet)   

    这意味着由nodelet导出的include路径,库等也附加到了catkin_变量,这里的变量是上面指示的<NAME>_,反之使用方式二,则路径,库等不会被添加到catkin_变量中。

1.4 Boost

    如果想使用Boost,并制定用作组件的Boost的哪些方面,如你想要使用Boost线程,则

        find_package(Boost REQUIRE COMPONENTS thread) 

1.5 catkin_package()

   catkin_package()是一个catkin提供的CMake宏。这是为构建系统指定catkin特定消息所必须的。后者又用于生成pkg_config和CMake文件。

    在使用add_library()或者add_executable()声明任何目标之前,必须调用此函数

    举例:

    

catkin_package(
   INCLUDE_DIRS include
   LIBRARIES ${PROJECT_NAME}
   CATKIN_DEPENDS roscpp nodelet
   DEPENDS eigen opencv)

    这表示,包文件夹中的文件夹"include"是导出标题的地方。CMake环境变量${PROJECT_NAME}评估到之前传给pro

<think>我们无法直接从CMakeLists.txt中读取Makefile中定义的宏。因为CMake和Make是两个独立的构建系统,CMakeLists.txt是CMake的输入文件,而Makefile是Make的输入文件,它们之间没有直接的交互机制。 但是,我们可以通过一些间接的方法将Makefile中的宏传递给CMake: 方法1:在运行cmake命令时通过命令行参数传递 - 在Makefile中,我们可以将宏的值提取出来,然后在调用cmake命令时通过`-D`选项传递给CMake。 - 例如,假设Makefile中有一个宏`CC = gcc`,我们可以在调用cmake时传递: cmake -DCMAKE_C_COMPILER=$(CC) ... 方法2:将Makefile中的宏写入一个配置文件(如config.h.in或config.cmake),然后在CMake中读取该文件 - 步骤: 1. 编写一个脚本(可以是shell脚本)从Makefile中解析出宏的值,并生成一个CMake可以读取的文件(例如,一个包含set命令的CMake脚本文件,或者一个C/C++头文件)。 2.CMakeLists.txt中,使用`include()`命令来包含生成的CMake脚本文件,或者使用`configure_file()`来生成一个头文件,然后在C/C++代码中包含该头文件。 方法3:在CMakeLists.txt中调用外部命令解析Makefile(不推荐,因为Makefile语法复杂,解析困难) - 使用`execute_process`命令调用一个脚本(如awk、sed或python)来解析Makefile,并将解析结果赋值给CMake变量。 - 示例: ```cmake # 使用awk提取Makefile中的CC宏 execute_process( COMMAND awk -F= '/^CC[[:space:]]*=/{gsub(/[[:space:]]/,"",$2); print $2}' Makefile OUTPUT_VARIABLE CC_FROM_MAKEFILE OUTPUT_STRIP_TRAILING_WHITESPACE ) message(STATUS "CC from Makefile: ${CC_FROM_MAKEFILE}") set(CMAKE_C_COMPILER ${CC_FROM_MAKEFILE}) ``` 注意:这种方法非常脆弱,因为Makefile的语法多样,且可能包含复杂的变量展开。因此,除非你完全控制Makefile的格式,否则不推荐。 鉴于以上,最可靠且常用的方法是方法1:在调用cmake时通过命令行传递。 下面我们详细说明方法1: 步骤: 1. 在Makefile中,我们定义了一些宏,例如: CC = gcc CFLAGS = -O2 -Wall 2. 在调用cmake命令时,将这些宏的值作为参数传递给CMake: cmake -DCMAKE_C_COMPILER=$(CC) -DEXTRA_CFLAGS="$(CFLAGS)" ... 3.CMakeLists.txt中,我们可以使用这些变量: set(CMAKE_C_COMPILER ${CMAKE_C_COMPILER}) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}") 注意:CMake有一些内置变量(如CMAKE_C_COMPILER)用于指定编译器,而自定义的变量(如EXTRA_CFLAGS)可以用于设置编译选项。 方法2的详细步骤(使用配置文件): 1. 编写一个脚本(例如:parse_makefile.sh),从Makefile中提取宏并生成一个CMake脚本文件(比如:makefile_vars.cmake): #!/bin/bash CC=$(grep -e '^CC[[:space:]]*=' Makefile | cut -d= -f2 | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') CFLAGS=$(grep -e '^CFLAGS[[:space:]]*=' Makefile | cut -d= -f2 | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') echo "set(CC $CC)" > makefile_vars.cmake echo "set(CFLAGS $CFLAGS)" >> makefile_vars.cmake 2. 在运行cmake之前,先运行这个脚本: ./parse_makefile.sh 3.CMakeLists.txt中,包含这个生成的CMake脚本文件: include(makefile_vars.cmake) set(CMAKE_C_COMPILER ${CC}) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${CFLAGS}") 方法2的变体:生成一个头文件(如config.h),然后在代码中使用: # 在parse_makefile.sh中生成config.h echo "#define CC \"$CC\"" > config.h echo "#define CFLAGS \"$CFLAGS\"" >> config.h 然后在CMakeLists.txt中,使用`configure_file`命令(如果头文件需要根据CMake变量生成,则通常用`configure_file`,但这里我们已经在外部生成,所以可以直接使用): # 将头文件目录添加到包含路径 include_directories(${CMAKE_CURRENT_BINARY_DIR}) 注意:这种方法需要每次Makefile修改后重新运行parse_makefile.sh。 总结:由于CMake和Makefile是两个独立的系统,没有直接读取的方式。推荐使用方法1(在调用cmake时通过命令行传递)或方法2(通过中间脚本解析Makefile并生成CMake可读的文件)。 根据你的实际需求选择合适的方法。如果只是希望将Makefile中的一些设置传递给CMake,方法1更简单直接。如果希望自动化地从Makefile中提取多个宏,方法2更合适。 注意:在CMake项目中,通常我们直接使用CMakeLists.txt来管理整个构建过程,而不需要Makefile。因此,如果可能,建议将整个构建迁移到CMake,避免混合使用。 引用说明: [^1]: CMakeLists.txt 文件详解。在命令行中使用 cmake 命令时,指定 CMakeLists.txt 文件的路径,CMake 会读取该文件并根据其中的命令和配置生成相应的构建系统文件(如 Makefile、Visual Studio 解决方案等)。 [^2]: CMakeLists.txt基本结构。 [^3]: CMakeLists.txt 的阅读。 [^4]: CMake常用命令记录(CMakeLists.txt)。 相关问题: 1. 如何在CMake中设置编译器选项? 2. CMake中如何包含其他目录的头文件? 3. 如何将CMake变量传递给C/C++代码?</think>在 CMakeLists.txt 中直接读取 Makefile 定义的宏是不可行的,因为两者属于不同的构建系统层级(CMake 生成 Makefile,而非反向读取)。但可通过以下方法间接实现 Makefile 宏在 CMake 中的复用: --- ### 方法 1:通过 CMake 命令行传递宏值(推荐) 在调用 `cmake` 时,使用 `-D` 参数将 Makefile 宏值注入 CMake 变量: ```bash # 从 Makefile 提取宏值(示例) CC_VALUE := $(shell grep '^CC' Makefile | cut -d= -f2) CFLAGS_VALUE := $(shell grep '^CFLAGS' Makefile | cut -d= -f2) # 传递给 CMake cmake -DCMAKE_C_COMPILER=${CC_VALUE} -DEXTRA_CFLAGS="${CFLAGS_VALUE}" .. ``` 在 CMakeLists.txt 中使用这些变量: ```cmake set(CMAKE_C_COMPILER ${CMAKE_C_COMPILER}) # 编译器 target_compile_options(my_app PRIVATE ${EXTRA_CFLAGS}) # 编译选项 ``` --- ### 方法 2:生成 CMake 兼容的配置文件 通过脚本将 Makefile 宏转换为 CMake 可读的格式: ```bash # 生成 config.cmake 文件 grep -E '^(CC|CFLAGS)' Makefile | \ sed 's/=/ /; s/^/set(/; s/$$/ CACHE STRING "")/' > config.cmake ``` 生成的 `config.cmake` 内容示例: ```cmake set(CC gcc CACHE STRING "") # [^2] set(CFLAGS -O2 -Wall CACHE STRING "") ``` 在 CMakeLists.txt 中包含此文件: ```cmake include(config.cmake) # 导入宏定义 set(CMAKE_C_COMPILER ${CC}) add_compile_options(${CFLAGS}) ``` --- ### 方法 3:使用 `execute_process` 解析 Makefile(复杂场景) 在 CMakeLists.txt 中直接解析 Makefile: ```cmake # 提取 Makefile 中的 CC 宏 execute_process( COMMAND bash -c "grep '^CC' Makefile | cut -d= -f2 | tr -d ' '" OUTPUT_VARIABLE CC_FROM_MAKEFILE OUTPUT_STRIP_TRAILING_WHITESPACE ) # 使用提取的值 set(CMAKE_C_COMPILER ${CC_FROM_MAKEFILE}) message("Using compiler: ${CC_FROM_MAKEFILE}") # [^4] ``` --- ### 关键注意事项 1. **作用域分离** CMake 是元构建系统,负责生成 Makefile,因此反向读取需额外步骤[^1][^3]。 2. **变量类型匹配** Makefile 宏通常是字符串,而 CMake 变量需明确类型(如 `CACHE STRING`)。 3. **健壮性处理** Makefile 语法复杂,解析时需处理空格、注释等特殊情况(如 `sed`/`grep` 命令需调整)。 4. **替代方案建议** ```cmake # 完全迁移到 CMake 变量管理 set(CC "gcc" CACHE STRING "C compiler") set(CFLAGS "-O2 -Wall" CACHE STRING "Compilation flags") ``` > ⚠️ 优先考虑将构建逻辑统一迁移到 CMake,避免混合系统带来的维护复杂性[^2][^3]。 --- ### 完整示例流程 **Makefile 内容:** ```makefile CC = gcc CFLAGS = -O2 -Wall ``` **迁移步骤:** ```bash # 生成 CMake 变量文件 echo "set(CC \"$(grep '^CC' Makefile | cut -d= -f2)\")" > makefile_vars.cmake echo "set(CFLAGS \"$(grep '^CFLAGS' Makefile | cut -d= -f2)\")" >> makefile_vars.cmake # 配置 CMake cmake -DIMPORT_MAKEFILE_VARS=ON .. ``` **CMakeLists.txt 内容:** ```cmake if(IMPORT_MAKEFILE_VARS) include(makefile_vars.cmake) # 导入宏 [^4] endif() project(MyProject) set(CMAKE_C_COMPILER ${CC}) # 应用编译器 add_executable(app main.c) target_compile_options(app PRIVATE ${CFLAGS}) # 应用编译选项 ``` --- ### 各方法适用场景 | **方法** | **优点** | **缺点** | **推荐场景** | |--------------------|------------------------------|------------------------------|---------------------------| | 命令行传递 (`-D`) | 简单直接,无需中间文件 | 需修改构建脚本 | 少量宏传递 | | 配置文件生成 | 一次生成,多次使用 | 依赖外部脚本 | Makefile 宏较多时 | | `execute_process` | CMake 内部完成 | 语法复杂,调试困难 | 需要动态读取 | | 完全迁移到 CMake | 统一维护,无兼容问题 | 需重构构建系统 | 新项目或深度重构 | [^1]: CMakeLists.txt 是 CMake 的配置文件,在命令行中指定其路径后,CMake 会读取该文件并生成构建系统文件(如 Makefile),两者属于单向生成关系。 [^2]: CMake 根据 CMakeLists.txt 生成编译规则(Makefile 文件),但反向读取需额外处理。 [^3]: CMakeLists.txt 描述构建过程,最终生成 Makefile 或其他构建系统的文件,因此直接读取 Makefile 不是标准流程。 [^4]: 可通过 `add_definitions()` 或 `message()` 命令验证宏是否成功传递。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值