Linking CMake interface libraries with object libr

2020-07-08 07:18发布

问题:

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.

回答1:

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.



回答2:

Starting from cmake 3.13, object libraries can "link" to other libraries to inherit their usage requirements (doc).

So the example CMakeLists.txt from the question should get the correct definition at compile time.

Don't forget to set cmake_required(VERSION 3.13) if you use this!



标签: cmake