目录
1.简介
check_include_file
是 CMake 提供的一个宏(macro),用于检查系统是否存在指定的头文件(.h
或 .hpp
等),并根据检查结果设置相应的变量。它通常用于跨平台项目中,判断目标系统是否支持某个头文件,从而条件性地启用或禁用某些功能。
基本语法:
check_include_file(<header> <resultVar> [FLAGS <flags>] [LANGUAGE <lang>])
<header>
:要检查的头文件名称(如stdio.h
、boost/filesystem.hpp
)。<resultVar>
:输出变量名,若找到头文件则设为1
(TRUE
),否则设为0
(FALSE
)。FLAGS <flags>
(可选):传递给编译器的额外 flags(如-I
指定包含路径)。LANGUAGE <lang>
(可选):指定检查使用的语言(C
或CXX
,默认C
)。
2.使用前提
check_include_file
定义在 CMake 的 CheckIncludeFile
模块中,使用前需先通过 include
命令加载该模块:
include(CheckIncludeFile) # 加载模块
3.基本用法示例
# 加载模块
include(CheckIncludeFile)
# 检查 stdio.h 是否存在(C 语言头文件)
check_include_file("stdio.h" HAVE_STDIO_H)
# 检查 boost/filesystem.hpp 是否存在(C++ 头文件,需指定语言)
check_include_file("boost/filesystem.hpp" HAVE_BOOST_FILESYSTEM_HPP LANGUAGE CXX)
# 根据检查结果条件编译
if(HAVE_STDIO_H)
message(STATUS "找到 stdio.h")
add_definitions(-DHAVE_STDIO_H) # 传递给源码的宏定义
else()
message(WARNING "未找到 stdio.h")
endif()
if(HAVE_BOOST_FILESYSTEM_HPP)
message(STATUS "找到 boost/filesystem.hpp")
else()
message(FATAL_ERROR "未找到 boost/filesystem.hpp,无法继续编译")
endif()
4.进阶用法
1.检查 C++ 头文件
默认情况下,check_include_file
使用 C 编译器检查头文件。若要检查 C++ 头文件(如 STL 或 Boost 头文件),需显式指定 LANGUAGE CXX
:
check_include_file("iostream" HAVE_IOSTREAM LANGUAGE CXX)
check_include_file("boost/asio.hpp" HAVE_BOOST_ASIO LANGUAGE CXX)
2.指定额外包含路径
若头文件位于非标准路径(如自定义安装的库),可通过 FLAGS
传递 -I
选项指定包含目录:
# 检查位于 /opt/myLib/include 下的 myHeader.h
check_include_file(
"myHeader.h"
HAVE_MY_HEADER
FLAGS "-I/opt/myLib/include" # 添加包含路径
LANGUAGE CXX
)
3.在源码中使用检查结果
通过 add_definitions
或 target_compile_definitions
将检查结果传递给源码,实现条件编译:
# CMakeLists.txt 中
if(HAVE_BOOST_FILESYSTEM_HPP)
target_compile_definitions(myapp PRIVATE HAVE_BOOST_FILESYSTEM)
endif()
// 源码中(main.cpp)
#ifdef HAVE_BOOST_FILESYSTEM
#include <boost/filesystem.hpp>
// 使用 Boost 文件系统功能
#else
// 降级处理或报错
#error "Boost filesystem 头文件不存在"
#endif
5.工作原理详解
CheckIncludeFile
的工作流程可分为以下 6 个步骤:
1.加载模块与宏定义
首先需通过 include(CheckIncludeFile)
加载模块,模块会定义核心宏 check_include_file
,该宏是执行检查的入口:
include(CheckIncludeFile) # 加载模块,定义 check_include_file 宏
2.用户调用宏指定检查目标
开发者调用 check_include_file
时,需传入两个关键参数:
- 第一个参数:待检查的 C 头文件名(如
stdio.h
、unistd.h
); - 第二个参数:存储结果的变量(如
HAVE_STDIO_H
),找到则设为1
(TRUE
),否则为0
(FALSE
)。
示例:
check_include_file("stdio.h" HAVE_STDIO_H) # 检查标准 C 头文件
check_include_file("sys/stat.h" HAVE_SYS_STAT_H) # 检查系统特定头文件
3.生成临时 C 测试代码
模块在 CMake 临时目录(如 CMakeFiles/CMakeTmp
)中,自动生成一段仅包含目标头文件的 C 代码,例如检查 stdio.h
时生成:
#include <stdio.h> // 目标头文件
int main(void) { return 0; } // 空主函数,仅用于编译检查
代码设计原则:仅包含头文件,不执行任何逻辑,目的是验证 “头文件能否被编译器找到并正常预处理”。
4.配置编译参数
- 编译器:使用当前项目配置的 C 编译器(如
gcc
、cl.exe
); - 包含路径:自动继承项目的
CMAKE_INCLUDE_PATH
等变量,支持通过FLAGS
选项添加额外路径(如-I/path/to/include
)。
5.尝试编译测试代码
通过 CMake 的 try_compile
命令编译临时代码:
- 编译成功:说明头文件存在且可被编译器识别(无 “头文件未找到” 错误);
- 编译失败:通常因 “
fatal error: xxx.h: No such file or directory
” 报错,说明头文件不存在或路径错误。
6. 设置结果变量并缓存
- 根据编译结果,将用户指定的变量(如
HAVE_STDIO_H
)设为1
或0
; - 结果会被缓存到
CMakeCache.txt
中,后续构建时直接复用,避免重复编译。
6.与 check_include_files
的区别
CMake 还提供 check_include_files
(注意复数形式),用于一次性检查多个头文件,所有头文件都存在时结果才为 TRUE
:
include(CheckIncludeFiles) # 加载对应的模块
# 检查 stdio.h 和 stdlib.h 是否同时存在
check_include_files("stdio.h;stdlib.h" HAVE_STD_HEADERS)
7.check_include_file的检测头文件说明
check_include_file
并非只能检查系统头文件,它可以检查任何路径下的头文件,包括系统默认路径、自定义路径(如项目本地头文件、第三方库头文件)等。其核心功能是验证 “指定头文件是否能被编译器找到并正常包含”,与头文件是否为 “系统级” 无关。
1.系统头文件:无需额外配置即可检查
系统头文件(如 stdio.h
、unistd.h
)通常位于编译器默认的包含路径(如 /usr/include
、/usr/local/include
)中,check_include_file
会自动搜索这些路径,因此直接检查即可:
check_include_file("stdio.h" HAVE_STDIO_H) # 无需额外路径
2.非系统头文件(自定义 / 第三方):需指定包含路径
对于不在编译器默认路径中的头文件(如项目内的 myheader.h
、Boost 库的 boost/filesystem.hpp
),需通过 FLAGS
参数手动指定包含路径( -I<path>
),否则检查会失败。
示例:
# 检查项目本地头文件(位于 ./include 目录)
check_include_file(
"myheader.h"
HAVE_MY_HEADER
FLAGS "-I${CMAKE_SOURCE_DIR}/include" # 指定自定义路径
)
# 检查 Boost 库头文件(位于 /opt/boost/include 目录)
check_include_file(
"boost/filesystem.hpp"
HAVE_BOOST_FILESYSTEM
FLAGS "-I/opt/boost/include" # 指定 Boost 头文件路径
LANGUAGE CXX # Boost 是 C++ 库,需指定语言
)
3.第三方库头文件的检查场景
例如,检查项目依赖的 Boost、Qt、OpenCV 等库的头文件是否存在时,check_include_file
非常有用。只需通过 FLAGS
传入第三方库的头文件路径(通常通过变量如 BOOST_INCLUDE_DIRS
、Qt5Core_INCLUDE_DIRS
获取),即可验证头文件是否可访问。
示例(结合 Boost 路径):
# 假设已通过 find_package 找到 Boost 的包含路径
find_package(Boost REQUIRED)
# 检查 Boost 某个具体头文件
check_include_file(
"boost/asio.hpp"
HAVE_BOOST_ASIO
FLAGS "-I${Boost_INCLUDE_DIRS}" # 使用 Boost 的包含路径
LANGUAGE CXX
)
8.CheckIncludeFileCXX
CheckIncludeFileCXX
是 CMake 提供的一个模块,专门用于检查 C++ 头文件是否存在,并根据检查结果设置相应的变量。它与适用于 C 语言的 CheckIncludeFile
模块对应,但针对 C++ 头文件(如 STL 头文件、第三方 C++ 库头文件等)进行优化,确保能正确处理 C++ 特定的头文件格式和依赖。
CheckIncludeFileCXX的语法和使用原理都和
CheckIncludeFile差不多,就不在这里赘述了。
CheckIncludeFileCXX与CheckIncludeFile的区别:
特性 | CheckIncludeFileCXX (C++) |
CheckIncludeFile (C) |
---|---|---|
适用语言 | C++ 头文件(如 <iostream> 、Boost) |
C 头文件(如 <stdio.h> 、<unistd.h> ) |
编译器 | 使用 C++ 编译器(如 g++ 、cl.exe ) |
使用 C 编译器(如 gcc 、cl.exe ) |
头文件语法支持 | 支持 C++ 语法(如命名空间、模板) | 仅支持 C 语法 |
依赖的语言标准 | 可通过 FLAGS 指定 C++ 标准(如 -std=c++17 ) |
通常使用 C 标准(如 -std=c99 ) |
9.注意事项
1. 头文件存在但检查失败
- 原因:
- 头文件依赖特定 C++ 标准(如
<filesystem>
需要 C++17),未指定相应编译选项; - 头文件位于非标准路径,未通过
FLAGS
添加-I
包含路径; - 头文件本身有语法错误或依赖其他缺失的头文件。
- 头文件依赖特定 C++ 标准(如
- 解决:
# 示例:检查需要 C++17 和自定义路径的头文件
check_include_file_cxx(
"mycpp17lib.hpp"
HAVE_MYCPP17LIB
FLAGS "-std=c++17 -I${CMAKE_SOURCE_DIR}/include"
)
if(HAVE_CXX_FILESYSTEM)
set(CMAKE_CXX_STANDARD 17) # 启用 C++17
target_compile_definitions(myapp PRIVATE USE_STD_FILESYSTEM)
endif()
2.跨平台路径差异
- 原因:Windows 和 Unix 系统的头文件路径分隔符(
\
vs/
)或默认安装路径不同。 - 解决:使用 CMake 路径变量(如
${CMAKE_SOURCE_DIR}
)和跨平台路径处理函数(如file(TO_CMAKE_PATH)
):
file(TO_CMAKE_PATH "${MY_INCLUDE_DIR}" MY_INCLUDE_DIR_CMAKE) # 统一路径格式
check_include_file_cxx(
"platform_header.hpp"
HAVE_PLATFORM_HEADER
FLAGS "-I${MY_INCLUDE_DIR_CMAKE}"
)
相关链接
- CMake 官网 CMake - Upgrade Your Software Build System
- CMake 官方文档:CMake Tutorial — CMake 4.1.0-rc2 Documentation
- CMake 源码:https://github.com/Kitware/CMake
- CMake 源码:CMake · GitLab
- 中文版基础介绍: CMake 入门实战 | HaHack
- wiki: Home · Wiki · CMake / Community · GitLab
- Modern CMake 简体中文版: Introduction · Modern CMake