cmake 里面target_include_directories,target_link_libraries这两个命令里面有三种属性PRIVATE、PUBLIC、INTERFACE。
cmake PRIVATE、PUBLIC、INTERFACE的讲解网络上很多,但是总觉得太过偏概念了,看完并没有让人有深入细节的了解。
于是动手做个示例,就有了本杂文。
这三种属性,从根本上来讲属于cmake里面传播特性的三种等级。
既然传播特性,那么我们肯定需要多个target来演示传播。
testCMake
├─ add.cpp
├─ build
├─ CMakeLists.txt
├─ Iadd
│ └─ add.h
├─ Isub
│ └─ sub.h
├─ main.cpp
└─ sub.cpp
项目结构如上,生成两个动态库,一个可执行文件
但三个cpp文件对头文件都没有包含关系,方便演示。
环境 minggw gcc 8.1.0+win10
add_library(add SHARED add.cpp)
add_library(sub SHARED sub.cpp)
add_executable(sample main.cpp)
这里我们sample(main) 只link sub库,不做另外的include_directories操作,sub在另外link add库做链接库和头文件库传递给sample。
//IADD里面的头文件可以传递给连接add的target,头文件传播
target_include_directories(add PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/iadd)
//Isub的头文件传递给连接sub库的target,头文件传播
target_include_directories(sub PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/isub)
//sub连接add库,连接sub的库也将连接add,连接库传播(含头文件)
target_link_libraries(sub PUBLIC add)
// sample 连接sub
target_link_libraries(sample PUBLIC sub) //无视,因为属于最尾子节点,没有下一级来传播
可能光看上面还是不太明白,那我们查看build/cmakefiles/xxxx.dir下生成的gcc 语句吧。
includes_CXX.rsp存储include path
linklibs.rsp存储link library
add.dir,第一级节点,没啥好说的
//include
-ID:/workspace/testCmake/iadd
// link
-lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32
sub ,注意include
//include,由于add库包含头文件使用的是public,所以sub只要link了add库,就会自动包含add的头文件目录 不需要另外include_directories,
-ID:/workspace/testCmake/isub -ID:/workspace/testCmake/iadd
// link
libadd.dll.a -lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32
sample
//include,isub同理,另外由于sub是public连接add库,因此add库的头文件可以传递到链接sub的sample
-ID:/workspace/testCmake/isub -ID:/workspace/testCmake/iadd
// 由于sub是public连接add库,sample也连接了add库
libsub.dll.a libadd.dll.a -lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32
将所有public,改为private,再次构建,查看对应的生成语句。
add.dir,第一级节点,没啥好说的
//include
-ID:/workspace/testCmake/iadd
// link
-lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32
sub ,注意include
//include,由于add库包含头文件使用的是private,所以sub包含没有iadd
-ID:/workspace/testCmake/isub
// link
libadd.dll.a -lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32
sample
//include为空,add及sub头文件都无法传递至sample
// link 只link sub
libsub.dll.a -lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32
interface比较特殊,他是指给连接者提供接口,而被连接者不对该接口做调用。
还是具体举例加深理解,除sample全部改成interface。
target_include_directories(add INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/iadd)
target_include_directories(sub INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/isub)
target_link_libraries(sub INTERFACE add)
target_link_libraries(sample PUBLIC sub) //private也可
add.dir
//include 为空,也就是上文中的只给连接者提供接口,而被连接不依赖该接口,只做include path的传递
// link
-lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32
sub
//include为空,同理
// link,link也是interface,不链接,只做链接库的传递
-lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32
sample(public link sub)
//include,由于是public连接sub,所以sub传递给sample的interface include都显示在sample的编译语言里
-ID:/workspace/testCmake/isub -ID:/workspace/testCmake/iadd
// 同上
libsub.dll.a libadd.dll.a -lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32
target_include_directories里面的关键字控制头文件目录传递。
target_link_libraries里的关键字控制头文件目录以及链接库传递。