0%

说明

这一章节是作者将一些分析工具以函数或内置支持的形式自动化地加入到了 CMake 构建工程的过程中了。

格式化

clang-format

静态检查

  1. clang-tidy
  2. cpplint(按照 Google Coding Style 检查)
  3. cppcheck
  4. include-what-you-use
  5. link what you use(CMake 内置)

静态检查受到 CMake 的直接支持:

All we need to do is set an appropriate target property to a semicolon-separated list containing the path to the checker’s executable, followed by any command-line options that should be forwarded to the checker.

  • <LANG>_CLANG_TIDY
  • <LANG>_CPPCHECK
  • <LANG>_CPPLINT
  • <LANG>_INCLUDE_WHAT_YOU_USE
  • LINK_WHAT_YOU_USE

Adding Doxygen to your project

安装必要软件包:

apt-get install doxygen graphviz

然后就能在 CMake 中引入 Doxygen 包并使用 doxygen_add_docs

Since CMake 3.9, we can use the doxygen_add_docs() function from FindDoxygen find-module, which sets the documentation target up.

注意 FindDoxygen module 推荐使用方式是 find_package,虽然可以 include 但是不推荐。

doxygen 用的是 Javadoc 的格式。

Exporting without installation

使用 export 命令可以创建导出文件,然后其他工程只要 include 这个导出文件就能使用当前这个包中的 target,而不需要先将这个包用 install 安装在系统里。

export(TARGETS [target1 [target2 [...]]]
      [NAMESPACE <namespace>] [APPEND] FILE <path>
      [EXPORT_LINK_INTERFACE_LIBRARIES]

NAMESPACE is recommended as a hint, stating that the target has been imported from other projects.

APPEND tells CMake that it shouldn’t erase the contents of the file before writing. 也就是说本身会按照 FILE 来覆写文件,但是 APPEND 使得写入方式变成追加。

EXPORT_LINK_INTERFACE_LIBRARIES will export target link dependencies (including imported and config-specific variants).

例子:

cmake_minimum_required(VERSION 3.20.0)
project(ExportCalcCXX)
add_subdirectory(src bin)
set(EXPORT_DIR "${CMAKE_CURRENT_BINARY_DIR}/cmake")
export(TARGETS calc
  FILE "${EXPORT_DIR}/CalcTargets.cmake"
  NAMESPACE Calc::
)
...

exportinstall 命令都有 TARGETSEXPORT 两种参数形式,所以容易混淆:

export (TARGETS ...)
  将给定的 targets 导出到 target export file,不会创建 named export

install(TARGETS ... [EXPORT] ...)
  如果有 EXPORT,除了安装之外,还会顺便从 targets 创建 named export(有两个作用!!这个是我是检查了 cmake_install.cmake 的)

export (EXPORT  ...)
  将 named export 导出到文件,可以指定名字空间

install(EXPORT  ...)
  将 named export 安装到系统,和 export(EXPORT ...) 有相似的参数,同样可以指定名字空间

export 命令用来导出 target export file。install 命令用来安装文件到系统。在 target export file 的场景下,两者都能用于“安装”,但是前者一般是用在安装在临时路径上(参考 Exporting without installation),而后者是用来安装进系统的。

例子:unnamed export VS named export

# unnamed export
export(TARGETS calc
       FILE "${EXPORT_DIR}/CalcTargets.cmake"
       NAMESPACE Calc::
)

#[=[
named export,同时还有 install(TARGETS calc) 的副作用。因而代码相当于:
install(TARGETS calc)
export(TARGETS calc
       FILE "${EXPORT_DIR}/CalcTargets2.cmake"
       NAMESPACE Calc::
)
#]=]
install(TARGETS calc EXPORT CalcTargets)
export(EXPORT CalcTargets
       FILE "${EXPORT_DIR}/CalcTargets2.cmake"
       NAMESPACE Calc::
)

总体结构

一些文件的分析

chapter12/01-full-project/src/calc/CMakeLists.txt

add_library(calc_obj OBJECT calc.cpp)
target_include_directories(calc_obj INTERFACE
  "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
  "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
)
set_target_properties(calc_obj PROPERTIES
    PUBLIC_HEADER src/calc/include/calc/calc.h
    POSITION_INDEPENDENT_CODE 1
)

add_library(calc_shared SHARED)
target_link_libraries(calc_shared calc_obj)
add_library(calc_static STATIC)
target_link_libraries(calc_static calc_obj)

一些要点:

  1. target_include_directories 使用生成器表达式为 build 和 install 之后指定了不同的包含路径。导出 target export file 的话这个细节非常重要。
  2. 然后是设置对象的属性。因为我们的库不是 SHARED 类型而是 OBJECT 类型,所以不是默认 PIC 的。需要正确设置 POSITION_INDEPENDENT_CODE 属性(我们实验室项目是在全局编译选项中加入 -fPIC 保证这一点的)。