Advertisement

CMake常用语法详细解析1

阅读量:

CMakeLists核心语法解析及工程实践

  • CMake存在的必要性
    • 核心操作流程解析

    • CMakeLists.txt配置规范

      • 构建跨平台编译环境的关键环节
      • 实现项目依赖管理的基础机制
      • 支持多架构编译的核心配置逻辑
    • 核心要点归纳

构建工具CMake的重要性

上面我们提到,一套C++程序从源代码到最终可执行程序是要经历过预处理、编译、汇编、链接等多个过程,因此我们需要一套配置工具,在一个大项目运行的时候来代替上面的复杂过程,因此我们就有了Makefile,但是Makefile在大型项目、跨平台等多样化需求下显得力不从心了,因此就有了Cmake。定义如下:

CMake 是个一个开源的跨平台自动化建构系统,用来管理软件建置的程序,并不依赖于某特定编译器,并可支持多层目录、多个应用程序与多个函数库。
CMake 通过使用简单的配置文件 CMakeLists.txt,自动生成不同平台的构建文件(如 Makefile、Ninja 构建文件、Visual Studio 工程文件等),简化了项目的编译和构建过程。
CMake 本身不是构建工具,而是生成构建系统的工具,它生成的构建系统可以使用不同的编译器和工具链。

他有如下优势:

  1. 跨平台支持 :CMake支持多种操作系统和编译器,使得同一份构建配置可以在不同的环境中使用。
  2. 简化配置 : 通过 CMakeLists.txt 文件,用户可以定义项目结构、依赖项、编译选项等,无需手动编写复杂的构建脚本。
  3. 自动化构建 : CMake 能够自动检测系统上的库和工具,减少手动配置的工作量。
  4. 灵活性 : 支持多种构建类型和配置(如 Debug、Release),并允许用户自定义构建选项和模块。

基本工作流程

  1. 制定 CMakeLists.txt 配置文档 : 设定项目的编译规范及依赖项关联。
  2. 创建平台适配的构建系统脚本 : 通过 CMake 工具生成适用于当前操作系统的工程管理文件(如 Makefile、Visual Studio 解决方案文件)。
  3. 启动编译过程 : 借助所生成的工程管理工具(如 make、ninja、msbuild)完成代码编译工作。

其中,CmakeLists.txt 作为 CMake 的核心配置文档,主要承担着界定项目编译规范、处理依赖项关联以及编译选项等关键功能。在多数情况下,一个完整的 CMake 工程体系会包含若干个该配置文档。

CMakeLists.txt语法结构与配置规范

本文将以CMakeLists文件为切入点展开解析,并通过具体工程实例加深理解。所选取的工程实例为kf_gins_ros项目,该项目属于由武汉大学开源框架KF-GINS衍生开发的ROS适配版本。原始KF-GINS系统采用卡尔曼滤波算法对GPS导航信号与IMU传感器数据进行融合处理,旨在获取载体高频率的姿态参数估计值。然而由于原始系统依赖txt格式的数据输入来源,在仿真实验环境中存在明显局限性,因此有开发者将其重构为支持ROS平台的数据接口形式(详细资料可参考:链接: kf_gins_ros)。

复制代码
    cmake_minimum_required(VERSION 3.0 FATAL_ERROR)
    project(gins)
    
    set(CMAKE_BUILD_TYPE "Release")
    set(CMAKE_CXX_STANDARD 14)
    #-DEIGEN_USE_MKL_ALL")
    set(CMAKE_CXX_FLAGS_RELEASE "-O3 -Wall -g")
    
    find_package(Eigen3 REQUIRED)
    find_package(catkin REQUIRED COMPONENTS
      roscpp
      std_msgs
      cv_bridge
      image_transport
      sensor_msgs
    )
    
    find_package(OpenCV REQUIRED)
    find_package(Eigen3)
    include_directories(
      gins
      ${catkin_INCLUDE_DIRS}
      ${EIGEN3_INCLUDE_DIR}
    )
    
    catkin_package()
    
    add_library(gins_lib
      gins/gins_engine.cpp
      gins/INSMechan.cpp
      gins/parameters.cpp
      gins/visualization.cpp
    )
    target_link_libraries(gins_lib ${catkin_LIBRARIES} ${OpenCV_LIBS} )
    
    
    add_executable(gins_node  gins.cpp)
    target_link_libraries(gins_node gins_lib)

第一句

首要步骤为自基础构建:

复制代码
    cmake_minimum_required(VERSION 3.0 FATAL_ERROR)
    project(gins)

本段内容用于完成项目基础配置工作。首行用于设定CMake所需的最低版本要求,此处限定为3.0以上版本。当检测到实际版本不满足条件时,参数项FATAL_ERROR将触发强制性错误提示并中止整个编译流程。第二行通过project指令用于定义项目标识符gins,该标识符最终将作为可执行文件的命名依据。需要特别指出的是,在执行各类构建命令过程中系统会自动生成相应的预处理宏定义。以执行project(gins)指令为例,在完成该操作后系统将自动生成对应的预定义宏:

复制代码
     - PROJECT_NAME: 将名称赋值给PROJECT_NAME,即${PROJECT_NAME} = cmaketest
     - PROJECT_SOURCE_DIR: 当前工程的源码路径
     - <PROJECT-NAME>_SOURCE_DIR:指定工程的源码路径。如果PROJECT_NAME就是当前工程,则与PROJECT_SOURCE_DIR相同。
     - PROJECT_BINARY_DIR:当前工程的二进制路径
     - <PROJECT-NAME>_BINARY_DIR: 指定工程的二进制路径。若PROJECT_NAME
     - CMAKE_PROJECT_NAME:顶层工程的名称。cmake命令首次调用那个CMakeLists.txt对应工程的名字

尽管后续存在大量相关指令会创建相似的宏定义,在常规情况下仅凭这些标识符的命名特征即可推测其大致含义。

第二句

复制代码
    set(CMAKE_BUILD_TYPE "Release")
    set(CMAKE_CXX_STANDARD 14)
    #-DEIGEN_USE_MKL_ALL")
    set(CMAKE_CXX_FLAGS_RELEASE "-O3 -Wall -g")

在此环节中需进行若干关键参数的配置工作,在常规操作流程中每当遇到set指令时通常会执行属性设定任务。例如当前场景下将编译选项设定为Release模式,并指定所采用的C++语言版本为C++11标准;同时定义当CMake构建Release版本时向编译器传递的具体标志位集合。其中-O3属于代码优化级别标识符,-Wall用于激活全部常规警告提示功能,-g则指示编译器生成可用于调试的信息数据。

鉴于上述内容提及的内容,现进一步阐述Release与Debug两种构建模式的相关特性差异性问题。实际上在多数应用场景下这两种模式并无本质区别,但针对特定需求仍存在明显特征划分.Debug模式毫无疑问会嵌入完整的调试信息,若需实施断点调试则必须采用此版本进行程序构建,其特点在于以原始形态完成程序编译过程——这种表述方式正是通过与Release版本形成对比而得出的结论。所谓Release版本即最终交付客户的正式发布版,其核心特征在于一般情况下禁用调试功能并实施代码层面的优化处理,使程序体积更为精简且逻辑架构更加紧凑据相关资料记载,两种版本之间的文件体积差异可达数百MB之多

第三句

复制代码
    find_package(Eigen3 REQUIRED)
    find_package(catkin REQUIRED COMPONENTS
      roscpp
      std_msgs
      cv_bridge
      image_transport
      sensor_msgs
    )

在构建过程中又接触到了一项新语法规范:find_package()指令具备自动识别并设置外部依赖库的功能特性,在定位系统预装组件或第三方开发包时具有重要作用。从基础层面理解可发现:各类第三方软件在不同设备中的存储路径存在差异性特征,因此无法采用固定绝对路径进行引用操作。这就需要借助特定检索机制引入相关依赖库——find_package()正是按照既定规则寻找目标库对应的.cmake脚本文件。此类由CMake语言编写的配置脚本通常集成项目构建所需的命令集与逻辑规则体系,并支持通过脚本文件实现特定组件的定位功能。以FindBoost.cmake为例即可验证该机制的具体应用方式——该脚本专用于识别Boost开发库的相关资源。

实际上find_package()的功能远不止上述基础层面内容,在具体应用中还涉及两种差异化检索模式及多种可选参数设置(后续将另行详解)。此处先简要说明前述提及的关键参数:REQUIRED标志位表示若未能成功定位指定依赖项则触发编译终止流程;COMPONENTS参数用于控制依赖项加载粒度——当仅需调用某组件的部分功能模块时(如仅需roscpp模块),可通过此参数精确指定所需子模块集合。

由此可清晰解读示例代码所体现的技术逻辑:首阶段需确认Eigen3开发库的有效性;随后执行catkin库定位操作(该步骤为强制性要求),但在加载过程中仅激活其roscpp等必要功能模块即可完成需求覆盖

总结

此篇内容暂且搁置于此,因时间有限无法逐一核查,后续相关论述将另行记录于下篇笔记中。

全部评论 (0)

还没有任何评论哟~