cmake:target属性POSITION_INDEPENDENT_CODE和INTERFACE_POSITION_INDEPENDENT_CODE的区别

文章讲述了CMake中POSITION_INDEPENDENT_CODE和INTERFACE_POSITION_INDEPENDENT_CODE两个target属性的区别,前者用于控制目标本身的代码生成位置无关性,后者影响依赖目标的设置。同时介绍了-fPIC在动态链接库编译中的作用以及两者在确保动态链接库兼容性和可移植性中的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

cmake定义的target有两个名字类似的属性:POSITION_INDEPENDENT_CODEINTERFACE_POSITION_INDEPENDENT_CODE,本文说明它们的含义和区别

-fPIC

介绍POSITION_INDEPENDENT_CODEINTERFACE_POSITION_INDEPENDENT_CODE属性前先介绍一下-fPIC编译选项。
-fPIC是gcc编译器的编译参数,以下是机器人告诉我的关于-fPIC参数的作用

在GCC编译器中, -fPIC 参数是指生成位置无关代码(Position Independent Code,PIC)。位置无关代码是一种可在内存中的任何位置加载和执行的代码。它通常用于动态链接库(shared library)的编译。

使用 -fPIC 参数编译代码时,生成的目标文件中的代码和数据引用都使用相对地址,而不是绝对地址。这样,当目标文件被加载到内存中时,它可以被放置在任何可用的内存地址上,而不会发生地址冲突。

通过使用位置无关代码,可以使得动态链接库在不同的内存地址空间中被加载和共享,提供更高的灵活性和可移植性。这对于操作系统和应用程序来说是非常重要的,因为它们可以在不同的环境中加载和使用这些动态链接库,而无需担心地址冲突和重新编译的问题。

总结来说, -fPIC 参数的作用是生成位置无关代码,用于编译动态链接库,以提供更高的灵活性和可移植性。

可以看出-fPIC参数是用于动态库的编译参数。

POSITION_INDEPENDENT_CODE

定义 -fPIC 参数最直接的方式是通过CMAKE_CXX_FLAGSCMAKE_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

CMAKE_POSITION_INDEPENDENT_CODE

注意POSITION_INDEPENDENT_CODE是target的属性,所以set_property,set_target_properties 调用只对target有效,而通过CMAKE_CXX_FLAGSCMAKE_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

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_CODEONINTERFACE_POSITION_INDEPENDENT_CODEON,因为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

请将以下CMakeLists.txt内容转换成Android.bp cmake_minimum_required(VERSION 3.16) if(LINUX) set(ICEORYX_PLATFORM ${CMAKE_CURRENT_SOURCE_DIR}/linux/) elseif(QNX) set(ICEORYX_PLATFORM ${CMAKE_CURRENT_SOURCE_DIR}/qnx/) elseif(APPLE) set(ICEORYX_PLATFORM ${CMAKE_CURRENT_SOURCE_DIR}/mac/) elseif(WIN32) set(ICEORYX_PLATFORM ${CMAKE_CURRENT_SOURCE_DIR}/win/) elseif(UNIX) set(ICEORYX_PLATFORM ${CMAKE_CURRENT_SOURCE_DIR}/unix/) else() set(ICEORYX_PLATFORM ${CMAKE_CURRENT_SOURCE_DIR}/unix/) message(WARNING "Could not detect supported platform, but I'm feeling lucky today. Maybe its Unix." ) endif() set(ICEORYX_PLATFORM ${ICEORYX_PLATFORM} CACHE PATH "" FORCE) file ( GLOB_RECURSE ICEORYX_PLATFORM_FILES ${ICEORYX_PLATFORM}/source/*.cpp ) add_library(iceoryx_platform ${ICEORYX_PLATFORM_FILES}) target_include_directories(iceoryx_platform PUBLIC $<BUILD_INTERFACE:${ICEORYX_PLATFORM}/include/> $<INSTALL_INTERFACE:include/${PREFIX}> ) set_target_properties(iceoryx_platform PROPERTIES CXX_STANDARD_REQUIRED ON CXX_STANDARD ${ICEORYX_CXX_STANDARD} POSITION_INDEPENDENT_CODE ON ) target_link_libraries(iceoryx_platform PRIVATE ${ICEORYX_SANITIZER_FLAGS}) target_compile_options(iceoryx_platform PRIVATE ${ICEORYX_WARNINGS} ${ICEORYX_SANITIZER_FLAGS}) if(LINUX) target_link_libraries(iceoryx_platform PUBLIC rt pthread ) elseif(QNX) target_link_libraries(iceoryx_platform PRIVATE socket ) elseif(APPLE) elseif(WIN32) elseif(UNIX) target_link_libraries(iceoryx_platform PUBLIC rt pthread ) endif()
最新发布
07-23
CMake的指令"target_link_libraries"用于将一个或多个目标与一个或多个库文件进行链接。通过这个指令,我们可以将目标所需的库文件关联起来,以便在编译链接过程中正确地引用库函数。 具体用法如下: target_link_libraries(target_name library_name1 library_name2 ...) 其中,target_name是要与库文件关联的目标的名称,而library_name1、library_name2等是要链接的库文件的名称。 例如,如果我们想要将名为sample的目标与curl、glibm等库文件进行链接,可以使用以下指令: target_link_libraries(sample PUBLIC CURL::curl glib m) 在使用target_link_libraries指令时,我们可以通过定义Third_part_lib参数来指定每个第三方库的名称,具体的库名称可以在库的说明文档中找到。需要注意的是,在链接库文件之前,我们需要确保这些库文件已经正确地安装并可以被找到。 总结起来,CMaketarget_link_libraries指令用于将目标与库文件进行链接,以便在编译链接过程中使用库函数。通过指定目标名称库文件名称,我们可以将它们关联起来,实现正确的链接。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [C++-Cmake指令:target_link_libraries](https://blog.youkuaiyun.com/u013250861/article/details/127939663)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

10km

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值