CMake:为每个项目设置编译选项和编译功能

Geo*_* P. 9 cmake

我有一个包含多个软件组件(可执行文件、库)的代码库(例如存储库)。所有内容都是使用 CMake 构建的,每个组件都有单独的目标。

现在,我知道设置编译器标志的现代方法是特定于目标的:

target_compile_options(foo PRIVATE -Werror -Wall -Wextra -pedantic)
target_compile_features(foo PRIVATE cxx_std_17)
Run Code Online (Sandbox Code Playgroud)

但是,我希望整个项目中的所有目标都具有相同的标志。为每个目标编写这些行会导致代码重复并且容易出错(尤其是当标志数量增加时)。有没有某种方法可以将编译器标志附加到项目而不是目标?

我知道我可以向顶级目录添加选项,如下所示:

add_compile_options(-Werror -Wall -Wextra -pedantic)
Run Code Online (Sandbox Code Playgroud)

但我不确定这是否是正确的方法,而且我也不确定如何对编译功能执行相同的操作(cxx_std_17)。

Ale*_*ing 10

现在,我知道设置编译器标志的现代方法是特定于目标的:

target_compile_options(foo PRIVATE -Werror -Wall -Wextra -pedantic)
target_compile_features(foo PRIVATE cxx_std_17)
Run Code Online (Sandbox Code Playgroud)

这实际上不是最好/最现代的方式。如果您使用的是 CMake 3.19+,最好的办法是创建一个预设

创建一个名为CMakePresets.json您的顶级文件旁边的文件CMakeLists.txt,其中包含以下内容:

{
  "version": 1,
  "cmakeMinimumRequired": {
    "major": 3,
    "minor": 19,
    "patch": 0
  },
  "configurePresets": [
    {
      "name": "default",
      "displayName": "Default",
      "description": "Default build using Ninja",
      "generator": "Ninja",
      "binaryDir": "${sourceDir}/build",
      "cacheVariables": {
        "CMAKE_CXX_FLAGS": "-Werror -Wall -Wextra -pedantic",
        "CMAKE_CXX_STANDARD": "17",
        "CMAKE_CXX_STANDARD_REQUIRED": "YES",
        "CMAKE_CXX_EXTENSIONS": "OFF"
      }
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)

然后配置:

$ cmake --preset=default
Run Code Online (Sandbox Code Playgroud)

这样做的原因是因为(理想情况下)CMakeLists.txt中不应包含构建项目所必需的任何内容。警告标志不在该集合中,因此它们属于此处。否则,您会给最终用户带来潜在无效的标志。这在警告标志中非常常见。有些标志仅适用于 GCC 或 Clang,其他标志已被删除或重命名,还有一些标志的敏感性在各个版本之间发生了变化。如果您的用户手动添加via并且您以其他方式添加标志,则可能会出现问题。-WerrorCMAKE_CXX_FLAGS

这确实意味着对于,设置cxx_std_NNvia通常是合适的target_compile_features,其中NN是库的最低兼容 C++ 版本(不是首选版本,尽管它们可能一致)。INTERFACE这是因为可以在(equiv. ) 属性中设置该功能PUBLIC,以确保链接者对库的标头使用足够新的版本。如果两者CMAKE_CXX_STANDARD都设置了,则将使用最大值。

在旧版本的 CMake 中,工具链文件可用于相同的目的。