Given the following project structure:
.
└── library/
├── CMakeLists.txt
├── include/
│ └── class1.hpp
├── src/
│ └── class1.cpp
├── build/
│ ├── _deps/
│ │ └── fmt-build
│ └── sample/
│ └── app_using_library.exe
└── sample/
├── CMakeLists.txt
└── main.cpp
CMakeLists.txt of library:
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)
CMakeLists.txt of app_using_library:
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" // cannot open source file "fmt/core.h"
class1.cpp:
#include "fmt/core.h" // works fine
Is there a possible cause or explanation for why the fmt headers are includable in class1.cpp, but not in class1.hpp when building both library
and app_using_library
? The include works correctly in the header when just building library
The compiler couldn't find the fmt headers in "class1.hpp", but it could find them in "class1.cpp".
The full error:
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.
Based on the answer from Tsyarev in the comments:
Such includes should only be done in private headers, i.e. headers not included in the INCLUDE_DIRECTORIES
for that target. This prevents any executable target using library
from also having to link to the library included in public headers.
Tsyarev's answers:
There is a notion about library's public header: that header is intended to be available to the consumers of the library. E.g., class1.hpp is public header for your library. For make a header available to the consumers, the header should be located in the PUBLIC include directory of your library. Any header included by a public header is public by yourself. E.g., since class1.hpp is a public header of the library and includes fmt/core.h, then fmt/core.h is a public header for your library too. And you need to make this headers accessible via PUBLIC include directory.
If you use fmt/core.h only in the private headers of your library, then your current code should work: library is PRIVATE linked with fmt::fmt, app_using_library is linked with library.