CMake编译传递

传递使用要求 (Transitive Usage Requirements)

Target的使用要求可以传递到依赖项. target_link_libraries()命令有 PRIVATEINTERFACEPUBLIC关键字来控制传递.

当创建动态库时,

  • 若源文件(例如cpp)中包含第三方头文件,而头文件(例如hpp)中不包含该第三方文件头,采用PRIVATE
  • 若源文件和头文件中都包含该第三方文件头,采用PUBLIC
  • 若头文件中包含该第三方文件头,而源文件(例如cpp)中不包含,采用INTERFACE

举个例子吧. 有三个库archivearchiveExtrasserialization以及一可执行文件consumer

add_library(archive archive.cpp)
target_compile_definitions(archive INTERFACE USING_ARCHIVE_LIB)

add_library(serialization serialization.cpp)
target_compile_definitions(serialization INTERFACE USING_SERIALIZATION_LIB)

add_library(archiveExtras extras.cpp)
target_link_libraries(archiveExtras PUBLIC archive)
target_link_libraries(archiveExtras PRIVATE serialization)
# archiveExtras is compiled with -DUSING_ARCHIVE_LIB
# and -DUSING_SERIALIZATION_LIB

add_executable(consumer consumer.cpp)
# consumer is compiled with -DUSING_ARCHIVE_LIB
target_link_libraries(consumer archiveExtras)

由于archivearchiveExtrasPUBLIC 依赖项, 因此它的使用要求也会传递给consumer. 因为serializationarchiveExtras的私有依赖,所以它的使用要求不会传递给consumer.

接口库 (Interface Libraries)

INTERFACE 目标没有 LOCATION 且是可变的,而且其他方面类似于 IMPORTED target.
它可以指定使用要求, 例如 INTERFACE_INCLUDE_DIRECTORIESINTERFACE_COMPILE_DEFINITIONSINTERFACE_COMPILE_OPTIONSINTERFACE_LINK_LIBRARIESINTERFACE_POSITION_INDEPENDENT_CODE.只有 target_include_directories()target_compile_definitions()target_compile_options()target_link_libraries() 命令的 INTERFACE 模式可以与 INTERFACE 库一起使用.
INTERFACE库的主要用例是仅含头文件的库.

add_library(Eigen INTERFACE)
target_include_directories(Eigen INTERFACE
  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
  $<INSTALL_INTERFACE:include/Eigen>
)

add_executable(exe1 exe1.cpp)
target_link_libraries(exe1 Eigen)

这里, 来自Eigen目标的使用要求在编译时被消耗和使用, 但它对链接没有影响.

参考链接

  • CMake transitive usage requirements
  • CMake target_Link_libraries interface dependencies