繁体   English   中英

CMake:处理共享库与静态库的链接

[英]CMake: handle linking of shared library with static libraries

对于我的项目,我希望能够将核心c ++库构建为静态库,但是将主JNI(Java glue)编译为共享库(需要在运行时由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 !!

由于检测架构看起来很难( 参见参考资料),即使我能够这样做,我也不知道ppc64el,mips或m68k的要求是什么(在这里插入任何奇特的系统)。 所以我想知道是否有一种简单的方法来查询cmake:

  • 我的编译器是否支持将共享库链接到静态库?
  • 理想情况下:转储实现此类链接步骤所需的缺少的编译器标志。

我知道:

if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")

但正如上面的链接所解释的,这不适用于交叉编译。


更新:问题显然不是如何设置-fPIC (或等效)编译器标志,但何时需要设置它。

您可以将与位置无关的代码设置为与全局相对的库的属性

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)

请参阅CMAKE中添加-fPIC编译器选项的惯用方法是什么?

所以我终于继续前进,只是这样实现:

# 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()

这解决了:

  1. 链接错误,如x86_64所示,并在我的原始问题中引用
  2. 在常规的x86(例如i686)上,它引入了一个小的开销,它大大简化了cmake的写入(指针的大小不会在ppc / x86 / mips和arm之间产生分歧)

最后,作为用户仍然覆盖默认行为(在x86_64x86上验证)的一种方式,我在顶层添加了:

if(NOT DEFINED GDCM_USE_PIC_FOR_STATIC_LIBS)

所以仍然可以编译:

$ cmake -DGDCM_USE_PIC_FOR_STATIC_LIBS:BOOL=OFF ...

这应该处理未经测试的疯狂系统( powerpcsparc64 ...)

正如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()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM