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

时间:2017-10-06 15:01:20

标签: c++ cmake shared-libraries 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 !!

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

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

我知道:

if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")

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

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

3 个答案:

答案 0 :(得分:2)

您可以将与位置无关的代码设置为与全局

对立的库的属性
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)

请参阅What is the idiomatic way in CMAKE to add the -fPIC compiler option?

答案 1 :(得分:2)

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

# 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之间产生分歧)
  3. 最后,作为用户仍然覆盖默认行为(在x86_64x86上验证)的一种方式,我在顶层添加了:

    if(NOT DEFINED GDCM_USE_PIC_FOR_STATIC_LIBS)
    

    所以仍然可以编译:

    $ cmake -DGDCM_USE_PIC_FOR_STATIC_LIBS:BOOL=OFF ...
    

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

答案 2 :(得分:0)

正如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()
相关问题