반응형

target_include_directories vs target_link_libraries 키워드

두 명령어 모두 PUBLIC / PRIVATE / INTERFACE 키워드를 사용하지만, 전파되는 속성(property)이 다르기 때문에 의미와 효과가 다릅니다.


핵심 개념: 두 가지 관점

관점 속성
헤더(컴파일) INCLUDE_DIRECTORIES, INTERFACE_INCLUDE_DIRECTORIES
링크 LINK_LIBRARIES, INTERFACE_LINK_LIBRARIES

키워드는 "이 타겟 자신에게 적용되는가""이 타겟에 의존하는 타겟에게도 전파되는가" 를 동시에 제어합니다.


키워드 의미 (공통)

               나 자신에게 적용?   의존자에게 전파?
PRIVATE         ✅                  ❌
INTERFACE       ❌                  ✅
PUBLIC          ✅                  ✅

 

 

target_include_directories

컴파일 시 헤더 탐색 경로(-I)를 제어합니다.

target_include_directories(<target>
    PUBLIC    <include_dir>   # 나도 쓰고, 나를 쓰는 놈도 써야 함
    PRIVATE   <include_dir>   # 나만 씀 (구현 내부 헤더)
    INTERFACE <include_dir>   # 나는 안 씀, 나를 쓰는 놈만 써야 함
)

 

 

실제 예시

project/
├── libfoo/
│   ├── include/foo/foo.h      ← public API 헤더
│   ├── src/foo.cpp
│   └── src/internal/detail.h  ← 내부 구현 헤더
└── app/
    └── main.cpp               ← #include <foo/foo.h> 사용

 

# libfoo/CMakeLists.txt
add_library(foo STATIC src/foo.cpp)

target_include_directories(foo
    PUBLIC  ${CMAKE_CURRENT_SOURCE_DIR}/include     # foo.h → app도 필요
    PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src/internal # detail.h → foo만 필요
)

 

# app/CMakeLists.txt
add_executable(app main.cpp)
target_link_libraries(app PRIVATE foo)
# → app은 자동으로 include/foo 경로를 얻음 (foo의 PUBLIC이 전파됨)
# → src/internal 경로는 전파 안 됨

 

전파되는 CMake 내부 속성

키워드 자신의 속성 전파되는 속성
PRIVATE INCLUDE_DIRECTORIES
INTERFACE INTERFACE_INCLUDE_DIRECTORIES
PUBLIC INCLUDE_DIRECTORIES INTERFACE_INCLUDE_DIRECTORIES

target_link_libraries

링크 시 의존 라이브러리(-l, -L)를 제어합니다. 단, 키워드가 없으면 헤더 경로까지 함께 전파됩니다 (transitive dependency).

target_link_libraries(<target>
    PUBLIC    <lib>   # 나도 링크, 나를 쓰는 놈도 링크해야 함
    PRIVATE   <lib>   # 나만 링크 (구현 내부에서만 사용)
    INTERFACE <lib>   # 나는 링크 안 함, 나를 쓰는 놈이 링크해야 함
)

 

 

실제 예시: 3계층 의존성

app → libbar → libfoo

 

# libfoo
add_library(foo STATIC foo.cpp)
target_include_directories(foo PUBLIC include)

# libbar: foo를 PUBLIC으로 링크 → bar의 헤더에서 foo 타입을 노출함
add_library(bar STATIC bar.cpp)
target_link_libraries(bar PUBLIC foo)
#   bar.h 안에 foo::SomeType 사용 → app도 foo 헤더가 필요

# app
add_executable(app main.cpp)
target_link_libraries(app PRIVATE bar)
# → app은 bar도 링크, foo도 자동으로 링크됨 (bar의 PUBLIC 전파)
# → app은 foo의 include 경로도 자동으로 얻음

 

# 반대 케이스: foo가 bar 내부 구현에서만 쓰임
target_link_libraries(bar PRIVATE foo)
# → app은 foo를 링크 안 해도 됨
# → app은 foo 헤더 경로도 받지 않음

 

 

전파되는 CMake 내부 속성

키워드 자신의 속성 전파되는 속성
PRIVATE LINK_LIBRARIES
INTERFACE INTERFACE_LINK_LIBRARIES
PUBLIC LINK_LIBRARIES INTERFACE_LINK_LIBRARIES

두 명령어의 관계

target_link_libraries로 CMake 타겟을 연결하면, 링크뿐 아니라 그 타겟의 INTERFACE_INCLUDE_DIRECTORIES도 자동으로 전파됩니다.

 

target_link_libraries(app PRIVATE foo)
# 이 한 줄이 아래 두 줄을 암묵적으로 수행:
#   - app이 foo를 링크 (-lfoo)
#   - foo의 INTERFACE_INCLUDE_DIRECTORIES → app의 INCLUDE_DIRECTORIES로 추가

 

그래서 올바르게 구성된 라이브러리라면 target_link_libraries 하나만으로 충분하고, 별도의 target_include_directories를 소비자 쪽에서 쓸 필요가 없습니다.


판단 기준 요약

이 헤더/라이브러리가...
├── 내 .cpp 구현 파일에서만 쓰임?           → PRIVATE
├── 내 공개 헤더(.h)에 노출됨?              → PUBLIC
└── 내 헤더에만 노출, 내 .cpp엔 없음?       → INTERFACE
    (header-only 라이브러리가 대표적)
반응형