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 SH
For me something like the following seems to be working:
add_library(foo_objects OBJECT src/foo.cpp src/foo.hpp)
set_property(TARGET foo_objects PROPERTY POSITION_INDEPENDENT_CODE ON)
target_include_directories(foo_objects PUBLIC
"$<BUILD_INTERFACE:src>"
"$<INSTALL_INTERFACE:include>")
add_library(foo_shared SHARED)
add_library(foo_static STATIC)
target_link_libraries(foo_shared PUBLIC foo_objects)
target_link_libraries(foo_static PUBLIC foo_objects)
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.
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 :/
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
andINTERFACE
items will populate theINTERFACE_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.