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

mal*_*lat 5 c++ cmake shared-libraries 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)
Run Code Online (Sandbox Code Playgroud)

现在在 x86_64 上,它失败并显示以下错误消息:

relocation R_X86_64_32 against `.rodata' cannot be used when making a shared object; recompile with -fPIC
Run Code Online (Sandbox Code Playgroud)

显然,简单的修复方法是:

relocation R_X86_64_32 against `.rodata' cannot be used when making a shared object; recompile with -fPIC
Run Code Online (Sandbox Code Playgroud)

然而,我更喜欢为我的用户提供侵入性较小的解决方案,相反,我正在考虑:

set(CMAKE_POSITION_INDEPENDENT_CODE ON)
Run Code Online (Sandbox Code Playgroud)

当然,下面的行不起作用(没有这样的东西CMAKE_ARCHITECTURE)。

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()
Run Code Online (Sandbox Code Playgroud)

由于检测体系结构似乎相当困难(请参阅 参考资料),即使我能够做到这一点,我也不知道 ppc64el、mips 或 m68k(在此插入任何外来系统)有什么要求。所以我想知道是否有一种简单的方法来查询cmake:

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

我知道:

if(CMAKE_ARCHITECTURE STREQUAL "x86_64") # FIXME !!
Run Code Online (Sandbox Code Playgroud)

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


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

mal*_*lat 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()
Run Code Online (Sandbox Code Playgroud)

这样解决:

  1. 在 x86_64 上看到并在我原来的问题中引用的链接错误
  2. 在常规 x86(例如 i686)上,虽然它引入了较小的开销,但它极大地简化了 cmake 的编写(例如,指针的大小不会区分 ppc / x86 / mips 和 arm)

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

if(NOT DEFINED GDCM_USE_PIC_FOR_STATIC_LIBS)
Run Code Online (Sandbox Code Playgroud)

这样人们仍然可以编译:

$ cmake -DGDCM_USE_PIC_FOR_STATIC_LIBS:BOOL=OFF ...
Run Code Online (Sandbox Code Playgroud)

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