我有一个使用 GCC 和 CMake 构建的 C++ 项目。
一般我喜欢用
-fmax-errors=1
来编译。我的正常工作流程是修复第一个错误,然后重建,因为后续错误通常是由第一个错误引起的。
但不幸的是,在 C++20 中,涉及约束失败的错误通常会被 GCC 视为多个“错误”。为了了解约束失败的原因,我需要看到多个错误。
所以偶尔我喜欢将
-fmax-errors
设置为更高的数字,可能是 2
,当出现此类错误时。
但是更改编译器标志(通过手动更改
CMakeLists.txt
或在命令行上将缓存变量传递给 cmake
)会使 CMake 缓存失效并使构建从头开始。
当然,这种行为通常是有道理的;任意配置更改可能需要重建。但我们人类知道,改变编译器的错误格式化行为并不需要重新构建。有没有办法向 CMake 表达这种区别?
或者,如果做不到这一点,是否有一种聪明的方法可以解决这个问题?我想过让 CMake 在调用编译器时读取环境变量(而不是在运行
cmake
时),但我找不到任何文档表明这实际上是可能的。
(我可能可以创建一个脚本,将其大部分参数转发给
g++
,但也添加 -fmax-errors="$MY_COOL_ENV_VARIABLE"
,然后告诉 CMake 有问题的脚本是用于构建的 C++ 编译器,但我想这可能会违反一些CMake 对“编译器”的期望。)
根据 Marc Glisse 的建议,我尝试了问题末尾括号中假设的方法。这实际上效果很好。
我现在在项目的顶级目录中有一个名为
invoke_compiler.py
的 Python 脚本。我以通常的方式将 CMake 指向脚本,即指定 C++ 编译器。
set(CMAKE_CXX_COMPILER ${PROJECT_SOURCE_DIR}/invoke_compiler.py)
为了便于说明,我实际上在问题上有点简洁。事实上,我经常使用 GCC 和 Clang 构建这个项目。因此,我希望在调用
cmake
时能够将 C++ 编译器指定为 CMake。
cmake my-src-dir -DCMAKE_CXX_COMPILER=g++
因此
invoke_compiler.py
必须采用一些额外的命令行标志,--my-project-cxx-compiler
和 --my-project-num-errors-flag
。
然后脚本调用编译器(其可执行文件是由
--my-project-cxx-compiler
指定的编译器),转发除上述额外参数之外的所有命令行参数并添加 f"{num_errors_flag}={os.environ.get('MY_PROJECT_NUM_ERRORS', 1)}"
。 (指定要显示的错误数量的编译器标志名称本身必须作为参数传递给脚本,因为 GCC 和 Clang 分别调用该标志 --fmax-errors
和 --ferror-limit
。)
技巧很简单,
CMakeLists.txt
中确定要传递给invoke_compiler.py
的参数的逻辑需要在CMAKE_CXX_COMPILER
被覆盖之前执行。
用户只需像往常一样与 CMake 交互,并随时更改
MY_PROJECT_NUM_ERRORS
变量的值,以便从编译器获得不同数量的错误。
下面的方法不需要更改您的CMakeLists.txt和其他源文件或使CMake缓存失效。它有点 hackish,但当 CMake 与 make 一起用作构建系统和 GCC 编译器时应该可以工作。它使用
--
CMake 命令行参数将附加参数传递给底层构建工具(在我们的例子中是 make)。它还使用 make 的 -e
标志使其更喜欢环境变量而不是本地 makefile 分配。
CXX_FLAGS="... -fmax-errors=1" cmake --build <dir> -- -e
而不是
...
,您应该传递当前分配给为当前 CMake 构建配置生成的 makefile 中的 CXX_FLAGS 变量的内容。要找出答案,您可以研究生成的 makefile 或尝试运行类似的内容
cmake --build <dir> -- -pn | grep ^CXX_FLAGS
它告诉底层 make 避免实际构建,而是打印一些信息,包括变量的分配,然后我们 grep 获取所需的分配。
例如就我而言,运行上面的命令会打印
CXX_FLAGS = -g -fPIC -Wno-deprecated -pthread
所以我需要跑步
CXX_FLAGS="-g -fPIC -fvisibility=hidden -Wno-deprecated -pthread -fmax-errors=1" cmake --build <dir> -- -e
将 GCC 编译错误限制为只有一个。
P.S.:
CXX_FLAGS
变量名称似乎没有记录,可能是 CMake 实现细节,将来可能会更改。在这种情况下,您需要研究生成的 makefile 以获取所需的变量名称。