CMake嵌套目标中源文件可引用fmt头文件但头文件不可用问题排查
问题分析:头文件引用
fmt/core.h编译失败的原因 项目结构
. └── library/ ├── CMakeLists.txt ├── include/ │ └── class1.hpp ├── src/ │ └── class1.cpp ├── build/ │ ├── _deps/ │ │ └── fmt-build │ └── sample/ │ └── app_using_library.exe └── sample/ ├── CMakeLists.txt └── main.cpp
相关CMake配置
library的CMakeLists.txt
project(library) include(FetchContent) FetchContent_Declare( fmt URL https://github.com/fmtlib/fmt/releases/download/9.1.0/fmt-9.1.0.zip ) FetchContent_MakeAvailable(fmt) add_library(library STATIC "src/class1.cpp" "include/class1.hpp" ) target_include_directories(library PUBLIC include) target_link_libraries(library PRIVATE fmt::fmt)
(注:原配置中add_library语句缺少闭合括号,属于语法错误,但并非导致当前问题的核心原因)
sample的CMakeLists.txt
project(app_using_library) add_executable(app_using_library main.cpp) target_link_libraries(app_using_library PRIVATE library)
问题现象
class1.hpp中包含#include "fmt/core.h",单独编译library目标时可正常通过,但编译依赖library的app_using_library时,编译器提示无法找到fmt/core.h。class1.cpp中同样的#include "fmt/core.h"语句始终正常工作。- 完整错误日志:
FAILED: sample/CMakeFiles/app_using_library.dir/main.cpp.obj C:\msys64\mingw64\bin\g++.exe -ID:/Programming/cpp/library/include -g -std=gnu++20 -MD -MT sample/CMakeFiles/app_using_library.dir/main.cpp.obj -MF sample\CMakeFiles\app_using_library.dir\main.cpp.obj.d -o sample/CMakeFiles/app_using_library.dir/main.cpp.obj -c D:/Programming/cpp/library/sample/main.cpp In file included from D:/Programming/cpp/library/sample/main.cpp:2: D:/Programming/cpp/library/include/class1.hpp:4:10: fatal error: fmt/core.h: No such file or directory 4 | #include "fmt/core.h" | ^~~~~~~~~~~~ compilation terminated.
原因解析
- 依赖传递性限制:
library目标通过PRIVATE关键字链接fmt::fmt,这意味着fmt的依赖信息(包括头文件路径)仅作用于library自身的编译过程,不会传递给依赖library的其他目标(比如app_using_library)。 - 编译阶段差异:
- 编译
library的源文件(class1.cpp)时,CMake会自动将fmt的头文件路径加入编译器的include搜索列表,因此class1.cpp中的引用可以正常找到文件。 - 编译
app_using_library的main.cpp时,编译器仅能获取library通过PUBLIC声明的include目录(即library/include),但fmt的头文件路径因是PRIVATE依赖,不会被传递过来。而main.cpp包含了class1.hpp,此时需要找到fmt/core.h,但编译器搜索路径中无对应目录,因此报错。
- 编译
- 单独编译与联合编译的区别:单独编译
library时,仅处理自身编译任务,PRIVATE依赖的头文件路径生效;联合编译时,app_using_library作为依赖方无法继承library的PRIVATE依赖,导致头文件查找失败。
内容的提问来源于stack exchange,提问作者LordMustang
相关产品推荐
相关产品推荐

