参考官网:
https://cmake.org/cmake/help/latest/command/target_include_directories.html
存在两个工程的时候,如果A工程引用B工程,且A工程的的文件引用了B工程的头文件,而B工程本身的头文件也是有其他引用。这时候,不希望在A工程内还要小心翼翼的把B工程内的各种关联头文件的路径这些还要指定一遍,因为这个在B工程肯定已经做了。
希望的就是A工程只要用到了B工程的某个模块,那么这个模块的关联的头文件、库,都可以自动的被包含进来,A工程只需要指定,依赖这个模块即可。
对于头文件来说,target_include_directories这个指令就可以达到解决头文件的路径的引用问题。
如有一个算法模块:
######### ---- app -------- #####
add_library(algorithm
SHARED
app/algorithm.cpp
)
target_link_libraries(algorithm
inner_A_module
inner_B_module
)
target_include_directories(map_fusion
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src/
${CMAKE_CURRENT_SOURCE_DIR}/app/
${CMAKE_CURRENT_SOURCE_DIR}/third_party/
)
这个算法模块被另外工程引用:
# Add sources. The official does not recommend using GLOB, but practical.
file(GLOB_RECURSE PRIVATE_SOURCES "*.cpp")
file(GLOB_RECURSE PROTO_SOURCES "${CMAKE_BINARY_DIR}/bolegen/proto/*.cc")
target_sources(${OUTPUT_NAME}_shared
PRIVATE
${PRIVATE_SOURCES}
${PROTO_SOURCES}
)
set(ALGO_DIR "../../../../")
add_subdirectory(${ALGO_DIR} ${CMAKE_BINARY_DIR}/algorithm)
# Include the FindDependencies.cmake module
include(${ALGO_DIR}/FindDependencies.cmake)
target_link_libraries(${OUTPUT_NAME}_shared
PRIVATE
algorithm
)
不需要再指定任何有关被依赖的模块所用到的头文件路径了。
target_link_directories则用来指定被链接的库的路径
关于里面的public、private、interface的说明
主要描述,其他更使用模块B引用这个模块A时候,对A模块里面指定的目录,是否可见。
官方的说明:
PUBLIC:公开目录
当您将一个头文件包含目录指定为PUBLIC时,它表示该目录会添加到当前目标自身以及所有依赖于它的目标的头文件包含目录中。这意味着链接到当前目标的任何目标也将获得这些头文件包含目录。
INTERFACE:接口目录
当您将一个头文件包含目录指定为INTERFACE时,它表示该目录仅会添加到当前目标的头文件包含目录中,而不会添加到依赖于它的目标中。这在您希望将某些头文件包含目录公开给链接到当前目标的目标,但不希望在其内部包含这些目录时很有用。
PRIVATE:私有目录
当您将一个头文件包含目录指定为PRIVATE时,它表示该目录仅会添加到当前目标的头文件包含目录中,不会传递给依赖于它的其他目标。这对于包含不希望暴露给其他目标的内部头文件时很有用。
使用起来的注意事项:
如果一个头文件只在某个target的源文件(cpp)中出现,并且不需要在其他依赖于该target的目标中可见,那么可以将该头文件指定为PRIVATE。这样做的好处是,该头文件将只在当前target的编译过程中使用,并不会对其他target产生影响。
如果一个头文件c.h在target的头文件被引用,这个taget自己的头文件又被其他模块如a.h引用,那么就不能把这个c.h的目录设置为private了,否则编译器在处理a.h的时候,就会出现找不到c.h的问题。
总结起来就是:
直接包含头文件: 当一个头文件直接在目标模块的源文件中包含时,该头文件的可见性取决于目标模块的PRIVATE、INTERFACE或PUBLIC属性。如果目标模块将该头文件设置为PRIVATE,则该头文件只在当前目标模块的编译过程中可见,并不会传递给其他依赖该目标的模块。
目标模块的接口引用: 如果目标模块将头文件设置为INTERFACE或PUBLIC,那么其他依赖于该目标模块的模块也可以访问该头文件,因为它被公开为目标的接口。
使用target_link_libraries: 有时,头文件的引用是通过目标模块的依赖库间接传递的。当目标模块通过target_link_libraries连接到另一个目标时,依赖目标的INTERFACE或PUBLIC头文件也会传递给当前目标。
这个是比较常用的,所以,我们合理设计自己的代码结构,使用依赖的模块时候,用target_link_libraries引用需要的模块,里面自动处理了所依赖的文件目录。
关于编译时候,还是库已经安装后的使用选项
用INSTALL_INTERFACE以及BUILD_INTERFACE两个关键字指定。
target_include_directories(clipper PUBLIC
$<INSTALL_INTERFACE:include>
$<INSTALL_INTERFACE:some/other/path>
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
)