问题描述
假设动态库B依赖动态库A,可执行程序C依赖动态库B。 如下图:
C[程序C] -->|依赖| B(动态库B) --> |依赖|A(动态库A)
在linux平台下,按照正常来说,在编译C时,只需要链接B就好了。
但是使用Cmake编译时,会报找不到libA.so的错误。
通过cmake生成的gcc命令看到,编译命令确实将A也链接了进来。
那么问题来了,为什么cmake会将B的依赖加到我C的头上?
答案
原因在于 target_link_libraries()
命令。
熟悉cmake的朋友都知道这是设置链接库的命令。
但其实它的原型是:
target_link_libraries(<target>
<PRIVATE|PUBLIC|INTERFACE> <lib> ...
[<PRIVATE|PUBLIC|INTERFACE> <lib> ... ] ...])
可以通过PRIVATE | PUBLIC | INTERFACE 设置依赖的传递性.
摘抄一下官方文档的描述:
The PUBLIC, PRIVATE and INTERFACE keywords can be used to specify both the link dependencies and the link interface in one command. Libraries and targets following PUBLIC are linked to, and are made part of the link interface. Libraries and targets following PRIVATE are linked to, but are not made part of the link interface. Libraries following INTERFACE are appended to the link interface and are not used for linking <target>.
参考:
https://cmake.org/cmake/help/v3.0/command/target_link_libraries.html
其实大白话就是:
- 如果B的头文件中包含了A的头文件(源文件间接包含),那么这里应该用PUBLIC,依赖关系会传递下去。
- 如果B仅源文件中包含了A的头文件,那么这里应该用PRIVATE,依赖关系不会传递。
- 如果B的头文件包含A,但源文件未包含,那么这里应该用INTERFACE,依赖关系不会传递。
好了,大家以后再使用target_link_libraries()
的时候就可以加上PRIVATE
关键字,这样C就不会链接A了。
需要注意:
根据CMP0023描述:
加关键字和不加关键字的用法不可以混合使用,如下面一起使用就会报错。
target_link_libraries(mylib A)
target_link_libraries(mylib PRIVATE B)
参考:
https://cmake.org/cmake/help/v3.0/policy/CMP0023.html