如何配置CMake区分#include<...>与#include"..."的头文件加载逻辑?
回答
当然可以!CMake完全支持区分#include<...>和#include"..."的头文件搜索行为,甚至能完美解决你提到的string.h冲突问题。下面分两个场景详细说明:
1. 区分#include "foo.h"和#include <foo.h>的加载目录
你之前用include_directories(src lib)的问题在于,这个命令会把两个目录同时加到全局的包含路径,不管是用引号还是尖括号引入,编译器都会按顺序搜索,自然会优先匹配第一个目录的文件。
要实现你要的区分,关键是利用CMake对包含目录的类型控制,以及编译器本身的搜索规则:
- 编译器对
#include"..."会优先搜索-I参数指定的目录(用户自定义路径) - 对
#include<...>会优先搜索-isystem参数指定的目录(系统级路径)
CMake里可以通过target_include_directories命令的关键字来控制这一点:
# 先定义你的目标(假设是可执行文件,库文件同理) add_executable(my_project src/foo.c lib/foo.c) # 配置包含目录: target_include_directories(my_project # PRIVATE:对应编译器的`-I`参数,优先被`#include"..."`搜索 PRIVATE src # SYSTEM:对应编译器的`-isystem`参数,优先被`#include<...>`搜索 SYSTEM lib )
这样配置后:
- 当你写
#include "foo.h"时,编译器会先搜索src目录,加载src/foo.h - 当你写
#include <foo.h>时,编译器会先搜索lib目录,加载lib/foo.h
如果你的源文件不在src目录下,还可以开启CMAKE_INCLUDE_CURRENT_DIR让编译器优先搜索当前源文件所在目录,再匹配PRIVATE路径。
2. 解决自定义string.h与系统库的冲突
你遇到的问题是自定义string.h被#include<string.h>加载,本质是因为自定义目录被加到了-I或-isystem路径中,导致编译器在搜索尖括号引入的头文件时,先找到了你的自定义文件。
要实现#include<string.h>加载系统文件,#include"string.h"加载自定义文件,只需把自定义string.h所在的目录仅加到PRIVATE包含路径:
# 假设自定义string.h在src目录下 target_include_directories(my_project PRIVATE src # 仅用`-I`参数添加,只会被`#include"..."`优先搜索 # 不要把src加到SYSTEM路径! )
原理是:
- 对于
#include<string.h>:编译器会优先搜索系统默认的-isystem路径(比如/usr/include),找到系统的string.h,完全不会去搜PRIVATE的src目录(因为-isystem的优先级高于-I) - 对于
#include"string.h":编译器会先搜索当前源文件目录,再搜索PRIVATE的src目录,找到你的自定义文件
这种配置和你在Keil里的行为完全一致,不需要重命名或移动自定义文件。
额外注意事项
- 尽量避免使用全局的
include_directories命令,改用target_include_directories针对单个目标配置,这样不会影响其他目标的包含路径 - 如果你的项目是多目标结构,比如同时有库和可执行文件,可以把公共的包含路径用
PUBLIC关键字配置,私有路径用PRIVATE
内容的提问来源于stack exchange,提问作者Simon Schüpbach
相关产品推荐
相关产品推荐

