Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Combining CMake object libraries with shared libraries

Tags:

c++

cmake

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.

like image 963
Ton van den Heuvel Avatar asked May 30 '18 09:05

Ton van den Heuvel


People also ask

How do I add multiple libraries to CMake?

To add a library in CMake, use the add_library() command and specify which source files should make up the library. Rather than placing all of the source files in one directory, we can organize our project with one or more subdirectories. In this case, we will create a subdirectory specifically for our library.

What does target link libraries do in CMake?

Specify libraries or flags to use when linking a given target and/or its dependents. Usage requirements from linked library targets will be propagated. Usage requirements of a target's dependencies affect compilation of its own sources.

How do I create a shared library in CMake?

To build everything, just place yourself into the build directory and run: /tmp/example/library/build $ cmake .. That's it, you should find mymath. h under /usr/local/include as well as libmymath.so under /usr/local/lib .


1 Answers

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.

like image 194
YSC Avatar answered Sep 17 '22 19:09

YSC