Transitive target_include_directories on OBJECT li

2019-01-18 20:24发布

问题:

Here is snippet from make CMakeLists.txt:

add_library(foo-object OBJECT src/foo.cpp)
target_include_directories(foo-object PUBLIC include)
add_library(foo SHARED $<TARGET_OBJECTS:${PROJECT_NAME}-object>)
add_library(foo_static STATIC $<TARGET_OBJECTS:${PROJECT_NAME}-object>)

Now, this all works fine, both libraries are generated. However I have a problem when I try to use it:

add_executable(bar src/main.cpp)
target_link_libraries(bar foo)

Target bar doesn't compile, because include directories from foo-object are not propagated. If I add target_include_directories directly on foo as well, everything will compile fine.

How can I make both foo and foo_static automatically use (and forward to stuff depending on them) include directories from foo-object?

回答1:

Hm, at the moment I came up with following:

add_library(foo-object OBJECT src/foo.cpp)
target_include_directories(foo-object PUBLIC include)

get_property(object_include_dirs TARGET foo-object PROPERTY INCLUDE_DIRECTORIES)
get_property(object_link_libs TARGET foo-object PROPERTY LINK_LIBRARIES)

add_library(foo SHARED $<TARGET_OBJECTS:${PROJECT_NAME}-object>)
target_include_directories(foo PUBLIC ${object_include_dirs})
target_link_libraries(foo PUBLIC ${object_link_libs})

add_library(foo_static STATIC $<TARGET_OBJECTS:${PROJECT_NAME}-object>)
target_include_directories(foo_static PUBLIC ${object_include_dirs})
target_link_libraries(foo_static PUBLIC ${object_link_libs})

but come on, there must be better way :/



回答2:

It seems that transitive properties only work when targets are linked through a chain of target_link_library calls. In your case, you do not have such a link between foo-object and foo.

If you add a source file to foo, that one should also not be able to see the include directory from foo-object.

This might be an oversight in the design of OBJECT libraries, as it essentially breaks the transitive properties for those.



回答3:

On CMake <3.12, use the following:

add_library(foo SHARED $<TARGET_OBJECTS:${PROJECT_NAME}-object>)
target_include_directories(foo
    PRIVATE
    $<TARGET_PROPERTY:${PROJECT_NAME}-object,INTERFACE_INCLUDE_DIRECTORIES>)

On CMake >=3.12, take a look at this answer (thanks @ian5v for the suggestion)


How it works:

target_include_directories(...)

...

PUBLIC and INTERFACE items will populate the INTERFACE_INCLUDE_DIRECTORIES property of <target>.

Therefore ${PROJECT_NAME}-object has INTERFACE_INCLUDE_DIRECTORIES set on it. We need to fetch this property and insert it into our own include path.

This looks like a job for "generator expressions"!. In particular, $<TARGET_PROPERTY:tgt,prop> looks like it will come in handy here.

Our tgt will be ${PROJECT_NAME}-object, and we're trying to extract all of the values of INTERFACE_INCLUDE_DIRECTORIES, so INTERFACE_INCLUDE_DIRECTORIES will be prop.

This comes out to $<TARGET_PROPERTY:${PROJECT_NAME}-object,INTERFACE_INCLUDE_DIRECTORIES>, which is exactly what we've used in the code above.



标签: cmake