当前位置: 首页 > 工具软件 > interface > 使用案例 >

CMAKE 里PRIVATE、PUBLIC、INTERFACE属性示例详解

吕飞翼
2023-12-01

闲扯

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)

示例

PUBLIC传播

这里我们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 

private 私有传播

将所有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

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里的关键字控制头文件目录以及链接库传递。

  • PUBLIC:对内对外都公开,可将头文件目录以及链接库传递给连接者。
  • PRIVATE:对内公开,对外不公开,不可传递头文件目录以及链接库。
  • INTERFACE:对外公开,对内不公开,可传递头文件目录以及链接库,但内部不可使用头文件及连接库,只能接口传递。
 类似资料: