CMake:处理共享库与静态库的链接 我的项目,我希望能够将核心C++库构建为静态库,但将主JNI(java胶粘)编译为共享库(需要在JVM运行时加载)。在伪代码中,这将是: 项目(foo-CXX) 添加_库(foo1 foo1.cxx) 添加_库(foo2 foo2.cxx) 添加库(foojni共享foojni.cxx) 目标链接库(foojni链接私有foo1 foo2)

CMake:处理共享库与静态库的链接 我的项目,我希望能够将核心C++库构建为静态库,但将主JNI(java胶粘)编译为共享库(需要在JVM运行时加载)。在伪代码中,这将是: 项目(foo-CXX) 添加_库(foo1 foo1.cxx) 添加_库(foo2 foo2.cxx) 添加库(foojni共享foojni.cxx) 目标链接库(foojni链接私有foo1 foo2),c++,cmake,shared-libraries,static-libraries,C++,Cmake,Shared Libraries,Static Libraries,现在在x86_64上,它失败并显示以下错误消息: relocation R_X86_64_32 against `.rodata' cannot be used when making a shared object; recompile with -fPIC 显然,简单的解决方法是: set(CMAKE\u位置\u独立\u编码开启) 然而,我更喜欢为我的用户提供一个侵入性较小的解决方案,相反,我考虑的是: if(构建JNI) if(非构建共享库) 如果(CMAKE_编译器_是_GNUCXX

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

relocation R_X86_64_32 against `.rodata' cannot be used when making a shared object; recompile with -fPIC
显然,简单的解决方法是:

set(CMAKE\u位置\u独立\u编码开启)
然而,我更喜欢为我的用户提供一个侵入性较小的解决方案,相反,我考虑的是:

if(构建JNI)
if(非构建共享库)
如果(CMAKE_编译器_是_GNUCXX)
如果(CMAKE_ARCHITECTURE STREQUAL“x86_64”)#修复我!!
设置(CMAKE\U位置\U独立\U代码开启)
endif()
endif()
endif()
endif()
当然,下面这行行不通(没有像
CMAKE\u架构这样的东西)

if(CMAKE_架构STREQUAL“x86_64”)#FIXME!!
由于检测体系结构似乎相当困难(),即使我能够做到这一点,我也不知道ppc64el、mips或m68k(在此处插入任何外来系统)的要求是什么。因此,我想知道是否有一种简单的方法可以查询cmake:

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

我知道:

if(CMAKE\u系统处理器STREQUAL“x86\u 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)

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

因此,我最终继续并以这种方式简单地实现了:

#公开一种将-fPIC传递给gdcm核心的静态lib的方法,同时仍将包装语言构建为共享lib:
if(未定义GDCM_使用_PIC_表示_STATIC_LIBS)
if(GDCM\u WRAP\u JAVA)
if(非构建共享库)
如果(CMAKE_编译器_是_GNUCXX)
设置(GDCM_使用_PIC_用于静态_LIBS ON)
endif()
endif()
endif()
endif()
if(GDCM_使用_PIC_表示_STATIC_LIBS)
if(构建共享库)
消息(致命错误“静态/共享库配置无效”)
else()
设置(CMAKE\U位置\U独立\U代码开启)
endif()
endif()
这就解决了:

  • 链接错误,如x86_64所示,并在我的原始问题中引用
  • 在常规x86(如i686)上,虽然引入了较小的开销,但它大大简化了cmake的编写(例如,指针的大小不会在ppc/x86/mips和arm之间产生分布)
  • 最后,为了让用户仍然覆盖默认行为(在
    x86\u 64
    x86
    上验证),我在顶层添加了:

    if(未定义GDCM\u使用PIC\u表示静态库)
    
    因此,人们仍然可以使用以下工具进行编译:

    $cmake-DGDCM\u使用PIC\u表示静态\u LIBS:BOOL=OFF。。。
    
    这应该可以处理未在此处测试的疯狂系统(
    powerpc
    sparc64


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