Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Linking CMake interface libraries with object libraries

Tags:

cmake

I am trying to use interface libraries to define preprocessor macros. These interface libraries will then be linked to other libraries to propagate these macros. This approach has worked with shared libraries I am creating but does not work with CMake object libraries.

I understand that you cannot directly link an interface library to an object library but you can indirectly link the TARGET_OBJECTS to the interface library.

Docs:

Although object libraries may not be named directly in calls to the target_link_libraries() command, they can be “linked” indirectly by using an Interface Library whose INTERFACE_SOURCES target property is set to name $<TARGET_OBJECTS:objlib>.

I have tried to do this but the object files are still not compiled with the appropriate definitions. Here is the minimal working example:

// a.cpp    
int a() {
  return
#ifdef MY_DEF
  5;
#endif
    }

CMakeLists:

cmake_minimum_required(VERSION 3.0.1)
project(my_question)

add_library(object_lib OBJECT a.cpp)

add_library(interface_lib INTERFACE)
target_compile_definitions(interface_lib INTERFACE MY_DEF)

# This does not set the MY_DEF flag
target_sources(interface_lib INTERFACE $<TARGET_OBJECTS:object_lib>)

add_library(main_lib SHARED $<TARGET_OBJECTS:object_lib>)
target_link_libraries(main_lib)

Output:

/Library/Developer/CommandLineTools/usr/bin/make -f CMakeFiles/object_lib.dir/build.make CMakeFiles/object_lib.dir/build
[ 50%] Building CXX object CMakeFiles/object_lib.dir/a.cpp.o
/Library/Developer/CommandLineTools/usr/bin/c++     -o CMakeFiles/object_lib.dir/a.cpp.o -c /Users/umar/devel/so_question/a.cpp
/Users/umar/devel/so_question/a.cpp:7:5: error: expected expression
    }
    ^
1 error generated.
make[2]: *** [CMakeFiles/object_lib.dir/a.cpp.o] Error 1
make[1]: *** [CMakeFiles/object_lib.dir/all] Error 2
make: *** [all] Error 2

Based on the documentation this should be possible in CMake. I am not sure if I am doing something wrong or if this is an issue in CMake. I have been able to reproduce this in CMake version 3.6 and 3.8 on Debian and OSX.

Edit:

I have been able to get around this using @utopia's approach but I was curious why the approach I used in my example did not work. I did not know if I was doing this incorrectly or if this was a problem with the tool. Perhaps StackOverflow is not the correct platform for this type of question and I should file a bug report against the project.

Edit2:

As of the most current version of CMake(3.8) this not possible in CMake(see discussion). This is something that may be supported in 3.9 via this merge request. For older versions utopia's answer is the way to go.

like image 287
Umar Arshad Avatar asked Jun 26 '17 19:06

Umar Arshad


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 is INTERFACE library in CMake?

Interface LibrariesAn INTERFACE library target does not compile sources and does not produce a library artifact on disk. However, it may have properties set on it and it may be installed and exported.

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.


1 Answers

Just copy the compile definitions from the interface library directly via properties. The information is there, just no direct support for it via the usual commands:

cmake_minimum_required(VERSION 3.1)
project(my_question)

add_library(interface_lib INTERFACE)
target_compile_definitions(interface_lib INTERFACE MY_DEF)

add_library(object_lib OBJECT a.cpp)
target_compile_definitions(object_lib PUBLIC
  $<TARGET_PROPERTY:interface_lib,INTERFACE_COMPILE_DEFINITIONS>)

add_library(main_lib b.cpp)
target_sources(main_lib PRIVATE
  $<TARGET_OBJECTS:object_lib>)

Note target_sources() was first introduced in version 3.1 not 3.0.1 it seems. It may be a good idea to update your cmake_minimum_required version.

like image 117
utopia Avatar answered Sep 19 '22 01:09

utopia