CMake:处理共享库与静态库的链接
CMake: handle linking of shared library with static libraries
对于我的项目,我希望能够将核心 C++ 库构建为静态库,但将主要 JNI(Java 胶水)编译为共享库(需要在运行时加载)通过 JVM)。在伪代码中,这将是:
project(foo CXX)
add_library(foo1 foo1.cxx)
add_library(foo2 foo2.cxx)
add_library(foojni SHARED foojni.cxx)
target_link_libraries(foojni LINK_PRIVATE foo1 foo2)
现在在 x86_64,它失败并显示以下错误消息:
relocation R_X86_64_32 against `.rodata' cannot be used when making a shared object; recompile with -fPIC
显然简单的修复是:
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
但是我更喜欢对我的用户侵入性较小的解决方案,相反,我正在考虑:
if(BUILD_JNI)
if(NOT BUILD_SHARED_LIBS)
if(CMAKE_COMPILER_IS_GNUCXX)
if(CMAKE_ARCHITECTURE STREQUAL "x86_64") # FIXME !!
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
endif()
endif()
endif()
endif()
当然下面这行不行(没有CMAKE_ARCHITECTURE
)
if(CMAKE_ARCHITECTURE STREQUAL "x86_64") # FIXME !!
由于检测体系结构似乎很难 (see),即使我能够这样做,我也不知道 ppc64el、mips 或 m68k 的要求是什么(在此处插入任何异国情调的系统)。所以我想知道是否有一种简单的方法来查询 cmake about:
- 我的编译器是否支持link将共享库转换为静态库?
- 理想情况下:转储实现此类 linking 步骤所需的缺少的编译器标志。
我知道:
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
但是正如上面 link 中所解释的,这对交叉编译不起作用。
更新:问题显然不是 how to set -fPIC
(or equivalent) compiler flag,而是 when do我需要设置它。
您可以将与位置无关的代码设置为 属性 相对于全局
的库
project(foo CXX)
add_library(foo1 foo1.cxx)
set_property(TARGET foo1 PROPERTY POSITION_INDEPENDENT_CODE ON)
add_library(foo2 foo2.cxx)
set_property(TARGET foo2 PROPERTY POSITION_INDEPENDENT_CODE ON)
add_library(foojni SHARED foojni.cxx)
target_link_libraries(foojni LINK_PRIVATE foo1 foo2)
见
正如 nktiwari 所说,您可以(并且应该)使用库属性:
set_property(TARGET my_lib PROPERTY POSITION_INDEPENDENT_CODE ON)
然后,要检测 64 位编译,只需使用以下(惯用的)CMake 测试:
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
# ...
endif()
这给出了类似的东西:
if(BUILD_JNI AND (NOT BUILD_SHARED_LIBS) AND CMAKE_COMPILER_IS_GNUCXX)
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set_property(TARGET my_lib PROPERTY POSITION_INDEPENDENT_CODE ON)
endif()
endif()
所以我终于继续简单地实现了这种方式:
# Expose a way to pass -fPIC to static libs of gdcm core, while still build wrapped language as shared lib:
if(NOT DEFINED GDCM_USE_PIC_FOR_STATIC_LIBS)
if(GDCM_WRAP_JAVA)
if(NOT BUILD_SHARED_LIBS)
if(CMAKE_COMPILER_IS_GNUCXX)
set(GDCM_USE_PIC_FOR_STATIC_LIBS ON)
endif()
endif()
endif()
endif()
if(GDCM_USE_PIC_FOR_STATIC_LIBS)
if(BUILD_SHARED_LIBS)
message(FATAL_ERROR "Invalid configuration for static/shared lib")
else()
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
endif()
endif()
这个解决了:
- 在 x86_64 上看到并在我的原始问题
中引用的链接错误
- 在常规 x86(例如 i686)上,虽然引入了少量开销,但它大大简化了 cmake 的编写(例如,指针的大小不会区分 ppc / x86 / mips 和 arm)
最后,作为一种让用户仍然覆盖默认行为的方式(在 x86_64
和 x86
上验证),我在顶层添加了:
if(NOT DEFINED GDCM_USE_PIC_FOR_STATIC_LIBS)
以便仍然可以编译:
$ cmake -DGDCM_USE_PIC_FOR_STATIC_LIBS:BOOL=OFF ...
这应该可以处理未在此处测试的疯狂系统(powerpc
、sparc64
...)
对于我的项目,我希望能够将核心 C++ 库构建为静态库,但将主要 JNI(Java 胶水)编译为共享库(需要在运行时加载)通过 JVM)。在伪代码中,这将是:
project(foo CXX)
add_library(foo1 foo1.cxx)
add_library(foo2 foo2.cxx)
add_library(foojni SHARED foojni.cxx)
target_link_libraries(foojni LINK_PRIVATE foo1 foo2)
现在在 x86_64,它失败并显示以下错误消息:
relocation R_X86_64_32 against `.rodata' cannot be used when making a shared object; recompile with -fPIC
显然简单的修复是:
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
但是我更喜欢对我的用户侵入性较小的解决方案,相反,我正在考虑:
if(BUILD_JNI)
if(NOT BUILD_SHARED_LIBS)
if(CMAKE_COMPILER_IS_GNUCXX)
if(CMAKE_ARCHITECTURE STREQUAL "x86_64") # FIXME !!
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
endif()
endif()
endif()
endif()
当然下面这行不行(没有CMAKE_ARCHITECTURE
)
if(CMAKE_ARCHITECTURE STREQUAL "x86_64") # FIXME !!
由于检测体系结构似乎很难 (see),即使我能够这样做,我也不知道 ppc64el、mips 或 m68k 的要求是什么(在此处插入任何异国情调的系统)。所以我想知道是否有一种简单的方法来查询 cmake about:
- 我的编译器是否支持link将共享库转换为静态库?
- 理想情况下:转储实现此类 linking 步骤所需的缺少的编译器标志。
我知道:
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
但是正如上面 link 中所解释的,这对交叉编译不起作用。
更新:问题显然不是 how to set -fPIC
(or equivalent) compiler flag,而是 when do我需要设置它。
您可以将与位置无关的代码设置为 属性 相对于全局
的库project(foo CXX)
add_library(foo1 foo1.cxx)
set_property(TARGET foo1 PROPERTY POSITION_INDEPENDENT_CODE ON)
add_library(foo2 foo2.cxx)
set_property(TARGET foo2 PROPERTY POSITION_INDEPENDENT_CODE ON)
add_library(foojni SHARED foojni.cxx)
target_link_libraries(foojni LINK_PRIVATE foo1 foo2)
见
正如 nktiwari 所说,您可以(并且应该)使用库属性:
set_property(TARGET my_lib PROPERTY POSITION_INDEPENDENT_CODE ON)
然后,要检测 64 位编译,只需使用以下(惯用的)CMake 测试:
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
# ...
endif()
这给出了类似的东西:
if(BUILD_JNI AND (NOT BUILD_SHARED_LIBS) AND CMAKE_COMPILER_IS_GNUCXX)
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set_property(TARGET my_lib PROPERTY POSITION_INDEPENDENT_CODE ON)
endif()
endif()
所以我终于继续简单地实现了这种方式:
# Expose a way to pass -fPIC to static libs of gdcm core, while still build wrapped language as shared lib:
if(NOT DEFINED GDCM_USE_PIC_FOR_STATIC_LIBS)
if(GDCM_WRAP_JAVA)
if(NOT BUILD_SHARED_LIBS)
if(CMAKE_COMPILER_IS_GNUCXX)
set(GDCM_USE_PIC_FOR_STATIC_LIBS ON)
endif()
endif()
endif()
endif()
if(GDCM_USE_PIC_FOR_STATIC_LIBS)
if(BUILD_SHARED_LIBS)
message(FATAL_ERROR "Invalid configuration for static/shared lib")
else()
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
endif()
endif()
这个解决了:
- 在 x86_64 上看到并在我的原始问题 中引用的链接错误
- 在常规 x86(例如 i686)上,虽然引入了少量开销,但它大大简化了 cmake 的编写(例如,指针的大小不会区分 ppc / x86 / mips 和 arm)
最后,作为一种让用户仍然覆盖默认行为的方式(在 x86_64
和 x86
上验证),我在顶层添加了:
if(NOT DEFINED GDCM_USE_PIC_FOR_STATIC_LIBS)
以便仍然可以编译:
$ cmake -DGDCM_USE_PIC_FOR_STATIC_LIBS:BOOL=OFF ...
这应该可以处理未在此处测试的疯狂系统(powerpc
、sparc64
...)