【问题标题】:CMake: handle linking of shared library with static librariesCMake:处理共享库与静态库的链接
【发布时间】:2018-03-18 10:24:21
【问题描述】:

对于我的项目,我希望能够将核心 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:

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

我知道:

if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")

但如上面链接中所述,这不适用于交叉编译。


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

【问题讨论】:

  • 如果您的目标是 Android x86_64,则 NDK cmake 工具链文件将为您处理 PIC。

标签: c++ cmake shared-libraries static-libraries


【解决方案1】:

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

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?

【讨论】:

    【解决方案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 之间进行区分)

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

    if(NOT DEFINED GDCM_USE_PIC_FOR_STATIC_LIBS)
    

    所以仍然可以编译:

    $ cmake -DGDCM_USE_PIC_FOR_STATIC_LIBS:BOOL=OFF ...
    

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

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        猜你喜欢
        • 2015-10-08
        • 2013-10-09
        • 1970-01-01
        • 1970-01-01
        • 2020-12-17
        • 2020-04-27
        • 1970-01-01
        • 1970-01-01
        • 2019-04-19
        相关资源
        最近更新 更多