5

For my project, I'd like to be able to build the core c++ libraries as static libraries, but compile the main JNI (Java glue) as a shared library (needs to be loaded at runtime by JVM). In pseudo code this would be:

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)

Right now on x86_64, it fails with the following error message:

relocation R_X86_64_32 against `.rodata' cannot be used when making a shared object; recompile with -fPIC

Obviously the simple fix is:

set(CMAKE_POSITION_INDEPENDENT_CODE ON)

However I'd prefer a less invasive solution for my users, instead, I am thinking of:

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

Of course, the following line does not work (no such thing as CMAKE_ARCHITECTURE).

if(CMAKE_ARCHITECTURE STREQUAL "x86_64") # FIXME !!

Since detecting architecture seems quite hard (see) and even if I was able to do so, I do not know what are the requirements for ppc64el, mips or m68k (insert any exotic system here). So I'd like to know if there is a simple way to query cmake about:

  • Does my compiler supports linking shared library to static library?
  • Ideally: Dump the missing compiler flags required to achieve such linking step.

I know of:

if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")

But as explained in the link above, this will not work for cross-compilation.


Update: The question is obviously not how to set -fPIC (or equivalent) compiler flag, but when do I need to set it.

malat
  • 12,152
  • 13
  • 89
  • 158

3 Answers3

2

You can set position-independent code as a property of the libraries opposed to globally

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)

See What is the idiomatic way in CMAKE to add the -fPIC compiler option?

nktiwari
  • 97
  • 2
2

So I finally went ahead and simply implemented this way:

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

This solve:

  1. The linking error as seen on x86_64 and referenced in my original question
  2. On regular x86 (eg. i686) while it introduce a minor overhead, it greatly simplify writing of cmake (size of pointer does not make distrinction between ppc / x86 / mips & arm for example)

Finally as a way for a user to still override the default behavior (verified on x86_64 and x86) I added at the toplevel:

if(NOT DEFINED GDCM_USE_PIC_FOR_STATIC_LIBS)

So that one can still compile with:

$ cmake -DGDCM_USE_PIC_FOR_STATIC_LIBS:BOOL=OFF ...

This should handle crazy system not tested here (powerpc, sparc64...)

malat
  • 12,152
  • 13
  • 89
  • 158
0

As said by nktiwari, you can (and should) use library properties:

set_property(TARGET my_lib PROPERTY POSITION_INDEPENDENT_CODE ON)

Then, to detect 64bit compilation, just use the following (idiomatic) CMake test:

if(CMAKE_SIZEOF_VOID_P EQUAL 8)
    # ...
endif()

which gives something like:

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()
Synxis
  • 9,236
  • 2
  • 42
  • 64