Lesson 32 · Reference
PUBLIC vs PRIVATE vs INTERFACE
cmake PUBLIC vs PRIVATE vs INTERFACE explained with a real example. What each scope does and when to use it.
CMake uses three keywords, PRIVATE, PUBLIC and INTERFACE, to define the scope of target properties (like include directories, compile flags, or linked libraries). They answer a simple question. Who does this setting apply to?
- PRIVATE: Applies only to the target itself.
- PUBLIC: Applies to the target and its users.
- INTERFACE: Applies only to the users, not the target itself.
These same keywords work across all target_* commands, including target_include_directories, target_link_libraries, and target_compile_definitions.
One example with all three
calc/CMakeLists.txtadd_library(calc STATIC src/calc.cpp) target_include_directories(calc PRIVATE src) # only calc.cpp needs src/ target_include_directories(calc PUBLIC include) # calc and anyone who uses calc target_link_libraries(calc PRIVATE math) # only calc uses math
app/CMakeLists.txtadd_executable(app main.cpp) target_link_libraries(app PRIVATE calc) # app automatically gets calc's PUBLIC settings
Because include/ is PUBLIC, app compiles #include <calc/calc.h> without mentioning the folder. Because src/ is PRIVATE, nobody else ever sees it. That is the whole mechanism.
The three scopes
| Scope | The target itself | Targets that use it |
|---|---|---|
PRIVATE | gets it | don’t |
PUBLIC | gets it | get it too |
INTERFACE | doesn’t | get it |
- PRIVATE. Only this target. Internal headers, private flags.
- PUBLIC. This target and its users. Public headers, and the C++ standard the headers need,
target_compile_features(calc PUBLIC cxx_std_20). - INTERFACE. Only the users. Used for header-only libraries and flag bundles, which have no code of their own.
How to choose
- Does the target’s own code need it? No, use
INTERFACE. - Does it show up in the target’s public headers? Yes, use
PUBLIC. No, usePRIVATE.
When unsure, use PRIVATE. It is the smallest scope, and widening it later is easy.
What goes wrong
- Using PUBLIC when you meant PRIVATE: Leaks your internal implementation details into downstream builds, exposing things users shouldn’t see.
- Using PRIVATE when you needed PUBLIC: Breaks targets that depend on yours, causing build errors like missing include directories or incorrect compiler standards.
Note
More context in Headers and include directories, Linking targets, and Interface libraries. The keywords start in What is a target.
Read the docs