我在工具链文件中看到了以下设置 CMAKE_CXX_FLAGS 的方法:
SET(CMAKE_CXX_FLAGS "-m32" CACHE STRING "C++ compiler flags" FORCE)
Run Code Online (Sandbox Code Playgroud)
我应该在工具链文件中使用它而不是
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32")
Run Code Online (Sandbox Code Playgroud)
?
它们之间有什么区别?
tl;dr:有两种可接受的方法可以做到这一点。
首先,大多数时候(90%+),您可以按照文档的建议_INIT使用变量:
set(CMAKE_CXX_FLAGS_INIT "-m32")
Run Code Online (Sandbox Code Playgroud)
其次,如果 CMake 为您的编译器/平台组合添加了不正确/冲突的标志,您可以通过设置不带 FORCE.
set(CMAKE_CXX_FLAGS "-m32" CACHE STRING "C++ compiler flags")
Run Code Online (Sandbox Code Playgroud)
请继续阅读以了解更多详细信息。
让我们进行一些实验。我们将使用以下 CMakeLists.txt:
cmake_minimum_required(VERSION 3.23)
project(test LANGUAGES CXX)
message(STATUS "CMAKE_CXX_FLAGS_DEBUG = ${CMAKE_CXX_FLAGS_DEBUG}")
Run Code Online (Sandbox Code Playgroud)
在大多数系统上,CMakeCMAKE_CXX_FLAGS默认留空。主要的例外是带有 MSVC 的 Windows,它添加了/EHsc和 (在旧版本上)/GR以确保启用标准 C++ 异常处理和 RTTI。
由于我无法立即访问 Windows 系统,因此我使用CMAKE_CXX_FLAGS_DEBUG,它在大多数编译器上都有默认初始化标志。不过,同样的原则适用,因为在这两种情况下设置这些都是平台模块的责任。
$ cmake -S . -B build
-- The CXX compiler identification is GNU 11.2.0
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- CMAKE_CXX_FLAGS_DEBUG = -g
-- Configuring done
-- Generating done
-- Build files have been written to: /path/to/build
Run Code Online (Sandbox Code Playgroud)
所以在这个编译器上,CMAKE_CXX_FLAGS_DEBUG设置为-g. 这是我们的基线。
现在我们将创建一个名为的工具链文件set-cache-force.cmake:
# set-cache-force.cmake
set(CMAKE_CXX_FLAGS_DEBUG "-DMY_DEBUG" CACHE STRING "C++ compiler flags" FORCE)
Run Code Online (Sandbox Code Playgroud)
我们将使用此工具链配置项目:
$ rm -rf build
$ cmake -S . -B build --toolchain set-cache-force.cmake
...
-- CMAKE_CXX_FLAGS_DEBUG = -DMY_DEBUG
...
Run Code Online (Sandbox Code Playgroud)
正如我们所看到的,原始-g标志被抑制,-DMY_DEBUG缓存值“获胜”。当然,这不再是真正的调试模式,这应该说明为什么覆盖所有标志并不总是我们想要的。
更糟糕的是,FORCE在这里使用会禁用用户覆盖CMAKE_CXX_FLAGS_DEBUG自己的能力:
$ rm -rf build
$ cmake -S . -B build --toolchain set-cache-force.cmake -DCMAKE_CXX_FLAGS_DEBUG="-DOVERRIDE"
...
-- CMAKE_CXX_FLAGS_DEBUG = -DMY_DEBUG
...
Run Code Online (Sandbox Code Playgroud)
这是非常不受欢迎的行为。用户需要编辑您的工具链文件来解决错误或添加进一步的自定义。
如果我们运行与以前相同的实验而不FORCE进行设置,那么我们仍然会得到相同的标志,但我们保留增量覆盖工具链文件的能力。
# set-cache.cmake
set(CMAKE_CXX_FLAGS_DEBUG "-DMY_DEBUG" CACHE STRING "C++ compiler flags")
Run Code Online (Sandbox Code Playgroud)
现在我们可以看到它有效:
$ rm -rf build
$ cmake -S . -B build --toolchain set-cache.cmake
...
-- CMAKE_CXX_FLAGS_DEBUG = -DMY_DEBUG
...
Run Code Online (Sandbox Code Playgroud)
并且它仍然可以被覆盖:
$ rm -rf build
$ cmake -S . -B build --toolchain set-cache.cmake -DCMAKE_CXX_FLAGS_DEBUG="-DOVERRIDE"
...
-- CMAKE_CXX_FLAGS_DEBUG = -DOVERRIDE
...
Run Code Online (Sandbox Code Playgroud)
它甚至可以再次被覆盖:
$ cmake -S . -B build -DCMAKE_CXX_FLAGS_DEBUG="-DOVERRIDE2"
...
-- CMAKE_CXX_FLAGS_DEBUG = -DOVERRIDE2
...
Run Code Online (Sandbox Code Playgroud)
现在我们尝试将其设置为普通变量。再次,我们将创建一个名为的工具链文件set-normal.cmake:
# set-normal.cmake
set(CMAKE_CXX_FLAGS_DEBUG "-DMY_DEBUG")
Run Code Online (Sandbox Code Playgroud)
再次,运行此命令显示-DMY_DEBUG“获胜”,覆盖 CMake 的默认标志:
$ cmake -S . -B build --toolchain set-normal.cmake
...
-- CMAKE_CXX_FLAGS_DEBUG = -DMY_DEBUG
...
Run Code Online (Sandbox Code Playgroud)
与实验 2 一样,这会阻止用户覆盖它......糟糕!
$ cmake -S . -B build --toolchain set-normal.cmake -DCMAKE_CXX_FLAGS_DEBUG="-DOVERRIDE"
...
-- CMAKE_CXX_FLAGS_DEBUG = -DMY_DEBUG
...
Run Code Online (Sandbox Code Playgroud)
现在我们将尝试使用您帖子中的代码。同样,我们将使用一个名为的工具链append-normal.cmake:
# append-normal.cmake
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DMY_DEBUG")
Run Code Online (Sandbox Code Playgroud)
现在我们得到了一个非常不同的结果:
$ rm -rf build
$ cmake -S . -B build --toolchain append-normal.cmake
...
-- CMAKE_CXX_FLAGS_DEBUG = -DMY_DEBUG -DMY_DEBUG
...
Run Code Online (Sandbox Code Playgroud)
这是完全错误的!这里发生了什么?嗯,工具链文件在项目初始化期间被多次读取,这会导致标志-DMY_DEBUG被附加两次。至少这是第一次运行时发生的情况:
$ cmake -S . -B build
...
-- CMAKE_CXX_FLAGS_DEBUG = -g -DMY_DEBUG
...
Run Code Online (Sandbox Code Playgroud)
第一次运行后,CMake 默认值会被缓存,因此我们会在后续运行中附加到该默认值。此外,CMake 现在只读取您的工具链文件一次。
您必须始终使工具链文件具有幂等性。这意味着运行两次与运行一次效果相同。
_INIT变量这是开发人员按照文档设计的做事方式。请参阅此处的文档: https: //cmake.org/cmake/help/latest/variable/CMAKE_LANG_FLAGS_INIT.html
CMAKE_<LANG>_FLAGS第一次为 language 配置构建树时用于初始化缓存条目的值<LANG>。该变量旨在由工具链文件设置。CMake 可能会根据环境和目标平台在该值前面或附加内容。
现在我们使用一个名为的工具链文件init-var.cmake:
# init-var.cmake
set(CMAKE_CXX_FLAGS_DEBUG_INIT "-DMY_DEBUG")
Run Code Online (Sandbox Code Playgroud)
我们重新运行构建:
$ rm -rf build
$ cmake -S . -B build --toolchain init-var.cmake
...
-- CMAKE_CXX_FLAGS_DEBUG = -DMY_DEBUG -g
...
Run Code Online (Sandbox Code Playgroud)
现在我们可以看到 CMake 将其默认标志附加到我们提供的初始标志上。事实上,这仍然允许用户覆盖一些东西:
$ cmake -S . -B build --toolchain init-var.cmake -DCMAKE_CXX_FLAGS_DEBUG="-DOVERRIDE"
...
-- CMAKE_CXX_FLAGS_DEBUG = -DOVERRIDE
...
Run Code Online (Sandbox Code Playgroud)
根据我的经验,90% 以上的情况下,让 CMake 使用实验 6(变量)添加额外标志是正确的_INIT。但时不时地,您会希望使用实验 3(set(CACHE) 不带 FORCE)完全覆盖 CMake。
您不想做的是在后续运行中表现不同的行为(如实验 5)或禁用关键 CMake 功能(即尊重缓存变量,如实验 2 和 4)。
| 归档时间: |
|
| 查看次数: |
2469 次 |
| 最近记录: |