You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CMake如何将编译器自动添加的系统包含目录指定为-isystem类型

CMake自动识别的系统包含目录警告过滤问题及解决方案

问题背景

已知通过SYSTEM参数标记包含目录,可实现第三方库头文件的警告过滤,避免开启警告视为错误时第三方库的警告打断编译:

target_include_directories(my_target SYSTEM PRIVATE ${SOME_THIRD_PARTY_LIBRARY_INCLUDES})

开启警告视为错误的配置示例:

list(APPEND CXX_COMPILER_FLAGS_TO_USE "-Werror")

遇到的问题

上述方案无法覆盖CMake自动检测识别的系统包含目录。比如CentOS 7环境下使用devtoolset-10提供的GCC 10时,开启-Wundef选项会触发系统头文件报错:

list(APPEND CXX_COMPILER_FLAGS_TO_USE "-Wundef")

具体报错信息如下:

In file included from /opt/rh/devtoolset-10/root/usr/include/c++/10/x86_64-redhat-linux/bits/c++config.h:2791,
                 from /opt/rh/devtoolset-10/root/usr/include/c++/10/cmath:41,
                 ...
/opt/rh/devtoolset-10/root/usr/include/c++/10/pstl/pstl_config.h:47:5: error: "__clang__" is not defined, evaluates to 0 [-Werror=undef]
   47 | #if __clang__
      |     ^~~~~~~~~
compilation terminated due to -Wfatal-errors.
cc1plus: all warnings being treated as errors

报错的头文件路径/opt/rh/devtoolset-10/root/usr/include/是CMake自动检测添加,没有在配置文件中手动声明。手动硬编码路径标记为SYSTEM目录可以临时解决,但不具备通用性,也不符合配置规范:

target_include_directories(my_target SYSTEM PRIVATE /opt/rh/devtoolset-10/root/usr/include)

补充说明:编译器是在根目录CMakeLists.txt最开头手动指定,避免调用CentOS自带的低版本GCC 4.8:

SET(CMAKE_CXX_COMPILER "/opt/rh/devtoolset-10/root/usr/bin/g++")
SET(CMAKE_C_COMPILER "/opt/rh/devtoolset-10/root/usr/bin/gcc")

解决方案

方案1:使用CMake原生特性(适用CMake 3.26及以上版本)

CMake 3.26版本新增了CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES_IS_SYSTEM和CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES_IS_SYSTEM全局变量,默认值为ON,会自动将编译器的隐式包含目录标记为SYSTEM类型。
如果使用该版本及以上的CMake,无需额外配置即可解决问题。如果特性未生效,可以在CMakeLists.txt的project指令之前手动开启:

set(CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES_IS_SYSTEM ON)
set(CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES_IS_SYSTEM ON)

方案2:低版本CMake通用兼容方案

如果无法升级CMake版本,可以通过读取编译器隐式包含目录属性批量标记为SYSTEM:

# 替换my_target为你的实际目标名
get_target_property(target_includes my_target INCLUDE_DIRECTORIES)
get_property(implicit_cxx_dirs DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY CXX_IMPLICIT_INCLUDE_DIRECTORIES)
foreach(dir ${implicit_cxx_dirs})
    list(FIND target_includes ${dir} dir_index)
    if(${dir_index} EQUAL -1)
        target_include_directories(my_target SYSTEM PRIVATE ${dir})
    endif()
endforeach()

该方案不需要硬编码路径,自动适配当前编译器的所有隐式系统包含目录,跨环境通用。

方案3:编译选项临时规避

如果仅需要解决指定警告触发的系统头文件报错,可以直接添加GCC/Clang原生支持的忽略系统头文件警告选项:

list(APPEND CXX_COMPILER_FLAGS_TO_USE "-Wundef" "-Wno-system-headers")

-Wno-system-headers会直接忽略所有系统头文件产生的警告,不需要修改包含目录配置,适配所有CMake版本。


内容的提问来源于stack exchange,提问作者Alvaro Palma Aste

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 22:39:00