cmake target_link_libraries 中的PRIVATE, PUBLIC, INTERFACE 详解

发布时间 2023-07-19 15:30:52作者: DoubleLi

网上关于 target_link_libraries 中的 PRIVATE, PUBLIC , INTERFACE  的解释大部分是错的,而且不是一般的错,是胡说。 因为这三个属性在不同的命令中使用时意义不同,有很多是从target_include_libraries中抄来的。

以下的解释主要场景是linux中,windows不存在这种关系,无需考虑。

我们来解释下,假设我们有一个程序 A  , A调用库B, B调用库C. 

A -> B -> C

A link B时不管是private还是public都没关系,毕竟A不需要导出符号,也没有人以API方式调用它。

现在主要问题就是B这个库用private还是public.  C是动态库。

如果B是动态或静态库,C是动态库,这个问题就会有影响。同样,如果B、C同为静态库时也会有问题。 

B用private link C,  此时A link B,但是不知道B->C这层关系,可以正常link B. 运行时,A->B->C 时,B找不到C中的函数。linux下没有直接依赖关系,所有的B/C的依赖都会转到到A下,可以用LDD命令验证,此时A只依赖于B, 不见C, 当B中的函数调用C中的函数时,因为没有加载C, 所以报找不到符号错误。解决的办法就是在A link B时,同样也写上C. 但是因为private的原因,A是不知道C中的符号这事,只能强制 link C到A才能解决。

如果B link C时用public 指示, 当编译A时,就会检查到C中的符号没有实现,此时你就会知道要把C link到A来解决这个问题了。

其实private/public 解决的是指示问题,本质上可以使用public 来解决, 可以减少坑。

下面是target_link_libraries中的解释,不想看英文的,直接拉到最后。

Link Inheritance

Similarly, for any target, in the linking stage, we would need to decide, given the item to be linked, whether we have to put the item in the link dependencies, or the link interface, or both, in the compiled target. Here the link dependencies means the item has some implementations that the target would use, and it is linked to the item, so that whenever we call the functions or methods corresponding to those implementations it will always be mapped correctly to the implementations in item via the link, whereas the link interface means the target becomes an interface for linking the item for other targets which have dependencies on the target, and the target does not have to use item at all.

Link TypeDescription
PUBLICAll the objects following PUBLIC will be used for linking to the current target and providing the interface to the other targets that have dependencies on the current target.
PRIVATEAll the objects following PRIVATE will only be used for linking to the current target.
INTERFACEAll the objects following INTERFACE will only be used for providing the interface to the other targets that have dependencies on the current target.

For example, if the fruit library has the implementation of functions, such as size and color, and the apple library has a function apple_size which called the size from the fruit library and was PRIVATE linked with the fruit library. We could create an executable eat_apple that calls apple_size by PUBLIC or PRIVATE linking with the apple library. However, if we want to create an executable eat_apple that calls the size and color from the fruit library, only linking with the apple library will cause building error, since the fruit library was not part of the interface in the apple library, and is thus inaccessible to eat_apple. To make the apple library to inherit the size and color from the fruit library, we have to make the linking of the apple library to the the fruit library PUBLIC instead of PRIVATE.

下面用人话(汉语)翻译下:

PUBLIC    在public后面的库会被Link到你的target中,并且里面的符号也会被导出,提供给第三方使用。

PRIVATE  在private后面的库仅被link到你的target中,并且终结掉,第三方不能感知你调了啥库

INTERFACE   在interface后面引入的库不会被链接到你的target中,只会导出符号。

---- 更新----------

​​​​​​​target_link_libraries 会在目标程序中生成rpath, 这点请注意 。