17

I have the following CMakeLists.txt defining an object library and a shared library depending on the object library, as follows:

add_library(foo OBJECT 
  foo.cpp
)

add_library(bar SHARED 
  bar.cpp
  $<TARGET_OBJECTS:foo>
)

add_executable(baz baz.cpp)
target_link_libraries(baz
  PUBLIC bar
)

I get the following linker error when linking baz:

/usr/bin/ld: CMakeFiles/foo.dir/foo.cpp.o: relocation R_X86_64_PC32 against symbol `_ZSt4cout@@GLIBCXX_3.4' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Bad value

This is because foo.cpp is not build with -fPIC (bar.cpp is). This can be solved by adding:

set_property(TARGET foo PROPERTY POSITION_INDEPENDENT_CODE ON)

Is this the right way to fix this issue? I seems to me there should be a cleaner solution for this. I feel CMake can be smarter here and see that the objects from foo are only used in a context where -fPIC is required. I am using CMake 3.11.

Some context; in our project, we need to build a single shared library from a lot of sources scattered around in different directories. Right now, we create separate shared libraries for each directory. Most of these libraries depend on Bison sources, which behind the scenes depend on add_custom_command to be build. This introduces compile time dependencies between the libraries, seriously limiting how much we can parallelize the build (see: https://gitlab.kitware.com/cmake/cmake/issues/15555).

Object libraries per directory which are then used to build the shared library seem to be a nice solution for this problem.

Ton van den Heuvel
  • 10,157
  • 6
  • 43
  • 82
  • CMake properties such as compiler flags will – to the extent required – trickle down to all dependent targets. However, what you want is basically that certain properties can also "trickle up". I don't think that's how it works or even how it's expected to work from the CMake devs' perspective. Sure, you could write a patch for CMake to do that, but I doubt it will ever be accepted into mainline, just saying… :-) – Arne Vogel May 30 '18 at 10:05
  • @ArneVogel, indeed, that makes sense. – Ton van den Heuvel May 30 '18 at 10:08
  • I'm amused, I would've asked this question today if you hadn't asked it yesterday. :-) – Omnifarious May 31 '18 at 22:05

1 Answers1

12

Is this the right way to fix this issue?

Yes it is.

Since bar (shared) is linked against foo (static), both of bar and foo must be compiled with position independent code.

CMake knows bar is a shared library, and enables position independent code by default. But since foo is a static object, even though it could guess it needs to be PIC1, it does not enable PIC by default for foo.

According to SO's question What is the idiomatic way in CMAKE to add the -fPIC compiler option?

You can set the position independent code property on all targets:

set(CMAKE_POSITION_INDEPENDENT_CODE ON)

or in a specific library:

add_library(lib1 SHARED lib1.cpp)
set_property(TARGET lib1 PROPERTY POSITION_INDEPENDENT_CODE ON)

Reference: CMAKE_POSITION_INDEPENDENT_CODE cmake build system


1) This could be a suggested feature, maybe it is already.

Community
  • 1
  • 1
YSC
  • 38,212
  • 9
  • 96
  • 149
  • 2
    Note that `foo` is not a static library. It's an `OBJECT` library in CMake terminology, effectively just a collection of object files. – Angew is no longer proud of SO May 30 '18 at 09:27
  • @Angew A static library is just a bunch of objects (.o) archived by `ar` ;) But ok, I'll fix that ^^ – YSC May 30 '18 at 09:29
  • I know they're almost equivalent on-disk, but they're quite distinct in CMake-verse, and I feel it could be confusing to mix them up. – Angew is no longer proud of SO May 30 '18 at 09:30
  • 2
    "even though it could guess it needs to be PIC" - From my understanding, CMake **never** attempts to *guess* a library properties according to its *usage*. More likely it *could be* `add_library(foo OBJECT SHARED ...)` for inform CMake, that library's objects will be used for SHARED library, so PIC-related options should be the same. (PIC seems to be the only difference between STATIC and SHARED libraries when **compile** their sources). – Tsyvarev May 30 '18 at 09:47