Lesson 10 · Targets: the core model
Linking targets
How one target says it uses another. What PRIVATE, PUBLIC and INTERFACE mean when linking, and how requirements flow through a chain.
Building libraries is only half the story. You have to connect them. target_link_libraries is how one target says “I use this other target”.
The basic form
target_link_libraries(app PRIVATE calc)
Translation. The executable app uses the library calc, and nobody needs to know about that except app. Now the keywords, same as last lesson:
- PRIVATE. Only
appneedscalc. If some other target linksapp, it does not getcalc. - PUBLIC.
appusescalc, andcalcis part of whatappoffers. If another target linksapp, it must also getcalc. Use this whencalc’s headers appear inapp’s public headers. - INTERFACE.
appdoes not linkcalcitself, but its consumers must. The header-only case from lesson 13.
The chain that just works
app ──PRIVATE──► calc ──PRIVATE──► math
math/CMakeLists.txtadd_library(math STATIC math.cpp)
calc/CMakeLists.txtadd_library(calc STATIC calc.cpp) target_link_libraries(calc PRIVATE math) # calc needs math. Consumers do not.
app/CMakeLists.txtadd_executable(app main.cpp) target_link_libraries(app PRIVATE calc) # app gets calc and math automatically
app’s final link line includes both libcalc.a and libmath.a, even though app never mentions math. Why is that correct? Because calc.cpp calls math functions, and the static library copies them into the executable. The linker has to see math when it links app.
Why
Requirements flow through the chain, so you state each connection once. In the old style you maintained
link_libraries(app math),link_libraries(calc math), and the ordering, by hand. The moment the chain grew, you got “undefined reference” errors forever. CMake builds the link line from the graph.
The classic static-library pitfall
With raw make, a static library must appear after the objects that use it, and circular dependencies (A uses B, B uses A) are a nightmare. CMake handles ordering and repetition for you. That is a big reason projects work with CMake even when hand-written link lines fail.
Which one do I use
Ask one question. Does this library appear in my public headers?
app.h#include "calc/calc.h" // is this line in a public header?
- Yes. Use
PUBLIC, orINTERFACEif you do not link it yourself. - No. Use
PRIVATE.
When in doubt, start with PRIVATE. It is the smallest scope that works.
Pitfall
You cannot link a target that does not exist yet.
add_library(calc ...)must come beforetarget_link_libraries(app ... calc). In project layout terms, add the library’s directory before the app’s (lesson 15).
Tip
A name that is not a target (for example
m,pthread,dl) is passed straight to the linker. Handy for system libraries on Linux,target_link_libraries(app PRIVATE m). But prefer imported targets when a package provides them (lesson 14).Threads::Threadsis always right, barepthreadis not.
Read the docs