cmake定义的target有两个名字类似的属性:POSITION_INDEPENDENT_CODE
和INTERFACE_POSITION_INDEPENDENT_CODE
,本文说明它们的含义和区别
介绍POSITION_INDEPENDENT_CODE
和INTERFACE_POSITION_INDEPENDENT_CODE
属性前先介绍一下-fPIC编译选项。
-fPIC
是gcc编译器的编译参数,以下是机器人告诉我的关于-fPIC
参数的作用
在GCC编译器中,
-fPIC
参数是指生成位置无关代码(Position Independent Code,PIC)。位置无关代码是一种可在内存中的任何位置加载和执行的代码。它通常用于动态链接库(shared library)的编译。使用
-fPIC
参数编译代码时,生成的目标文件中的代码和数据引用都使用相对地址,而不是绝对地址。这样,当目标文件被加载到内存中时,它可以被放置在任何可用的内存地址上,而不会发生地址冲突。通过使用位置无关代码,可以使得动态链接库在不同的内存地址空间中被加载和共享,提供更高的灵活性和可移植性。这对于操作系统和应用程序来说是非常重要的,因为它们可以在不同的环境中加载和使用这些动态链接库,而无需担心地址冲突和重新编译的问题。
总结来说,
-fPIC
参数的作用是生成位置无关代码,用于编译动态链接库,以提供更高的灵活性和可移植性。
可以看出-fPIC
参数是用于动态库的编译参数。
定义 -fPIC
参数最直接的方式是通过CMAKE_CXX_FLAGS
或CMAKE_C_FLAGS
参数定义,
示例如下,因为它只是clang和gcc才有的参数所以在设置-fPIC参数的时候需要判断编译器
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
endif()
但这样在跨平台项目编译时需要更多的维护工作量,为了让CMakeLists.txt脚本更简洁,减少编译器无关性,通过POSITION_INDEPENDENT_CODE
属性来定义-fPIC
参数是推荐的方式:
POSITION_INDEPENDENT_CODE
是cmake为target定义的属性
可以通过set_property,set_target_properties
函数来定义POSITION_INDEPENDENT_CODE
属性
## set_property示例
set_property(TARGET my_target PROPERTY POSITION_INDEPENDENT_CODE ON)
## set_target_properties 示例
set_target_properties (my_target PROPERTIES POSITION_INDEPENDENT_CODE ON)
根据cmake官方文档说明,当target为动态库时POSITION_INDEPENDENT_CODE 默认值为True,否则为静态库时默认为False;
参见 POSITION_INDEPENDENT_CODE
注意POSITION_INDEPENDENT_CODE
是target的属性,所以set_property,set_target_properties 调用只对target有效,而通过CMAKE_CXX_FLAGS
或CMAKE_C_FLAGS
参数定义定义 -fPIC
参数对所有target有效。如果也希望一次定义所有target的POSITION_INDEPENDENT_CODE
属性,则可以通过设置CMAKE_POSITION_INDEPENDENT_CODE
变量来实现,用于定义所有target的POSITION_INDEPENDENT_CODE
属性的默认值
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
INTERFACE_POSITION_INDEPENDENT_CODE
也是target的属性,但它的作用与POSITION_INDEPENDENT_CODE
不同
INTERFACE_POSITION_INDEPENDENT_CODE
属性通知消费者(即依赖于当前target的target)是否需要将他们的 POSITION_INDEPENDENT_CODE
属性设置为ON。如果该属性被设置为ON,那么所有消费者的 POSITION_INDEPENDENT_CODE
属性也将被设置为ON。同样地,如果该属性被设置为OFF,那么所有消费者的 POSITION_INDEPENDENT_CODE
属性也将被设置为OFF。如果该属性未定义,那么消费者将通过其他方式确定他们的 POSITION_INDEPENDENT_CODE
属性。
总结就是INTERFACE_POSITION_INDEPENDENT_CODE
用于确保消费者与链接的目标的POSITION_INDEPENDENT_CODE
属性保持一致性。
简单来说就是
如果一个target定义了INTERFACE_POSITION_INDEPENDENT_CODE
属性并不会影响自己的POSITION_INDEPENDENT_CODE
属性,而是会影响依赖它的Target的POSITION_INDEPENDENT_CODE
属性
add_library(a STATIC a.cpp)
set_target_properties (a PROPERTIES
POSITION_INDEPENDENT_CODE ON
INTERFACE_POSITION_INDEPENDENT_CODE ON)
add_library(b SHARED b.cpp)
如上示例中,静态库a设置了POSITION_INDEPENDENT_CODE
为ON
,INTERFACE_POSITION_INDEPENDENT_CODE
为ON
,因为INTERFACE_POSITION_INDEPENDENT_CODE
的传递作用,
动态库b的POSITION_INDEPENDENT_CODE
属性自动为ON
INTERFACE_POSITION_INDEPENDENT_CODE
属性实际只有静态库需要设置,对于动态库不需要设置该属性,因为动态库不需要依赖库保存位置无关代码(PIC)一致性
前面说了-fPIC参数是用于动态库的编译参数。但对于静态库有时也需要指定-fPIC编译出位置无关代码,因为一个动态库连接静态库时,如果其连接的静态库都不是编译为位置无关代码代码(-fPIC),则在连接阶段可能会报错:
/usr/bin/ld: …/…/static.a(file.cpp.o): relocation R_X86_64_TPOFF32 against symbol `_ZGVZN6spdlog7details2os9thread_idEvE3tid’ can not be used when making a shared object; recompile with -fPIC
https://cmake.org/cmake/help/latest/prop_tgt/POSITION_INDEPENDENT_CODE.html
https://cmake.org/cmake/help/latest/prop_tgt/INTERFACE_POSITION_INDEPENDENT_CODE.html
https://cmake.org/cmake/help/latest/variable/CMAKE_POSITION_INDEPENDENT_CODE.html