[CMake] OBJECT libraries and working around lake of target_link_libraries

Chuck Atkins chuck.atkins at kitware.com
Mon Jul 17 11:38:05 EDT 2017


Hi David,


> Supporting OBJECT libraries in
> target_link_libraries calls was mentioned mentioned right back here
> https://cmake.org/pipermail/cmake-developers/2012-March/015422.html but
> sadly seems still to be on the back burner.
>

It's not on the back burner!  There has been progress on desiging the rest
of the implementation to make OBJECT libraries "first class citizens" and
I  can't give you actual dates I do believe you can probably expect it some
time this year.


>
> Not being
> able to use target_link_libraries with thier transitive nature made this
> very painful, many days of work.


I actually just recently went through the exercise of creating a workaround
for this in one of my projects so I can certainly understand the gaping
hole that is currently present.  The workaround I ended up with was to
create three seperate libraries: one for the objects, one for the usage
requirements, and then a third that combines them.

add_library(foo_objects OBJECT foo_src1.cxx foo_src2.cxx ...)

add_library(foo_interface INTERFACE)
target_link_libraries(foo_interface INTERFACE FooDepend1 FooDepend2 ...)
target_include_directories(foo_interface INTERFACE
  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR})>
  $<INSTALL_INTERFACE:include>)

add_library(foo INTERFACE)
target_sources(foo INTERFACE $<TARGET_OBJECTS:foo_objects>)
target_link_libraries(foo INTERFACE foo_interface)

The interface sources property on "foo" will populate the object files into
whatever uses "foo" in its target_link_libraries and then the usage
requirements in foo_interface will populate transitively.  The only problem
with this approach, and the reason for creating three separate libraries
instead of just adding the objects to the sources on foo_interface, is that
INTERFACE_SOURCES will continue to get propagated transitively potentially
causing duplicate symbols upstream, so it's really only appropriate for
private linking so you want to link publically then add the objects
manually and pass the interface publically.  This essentially means you
need to use it like this:

// Use foo privately, so just put "foo" in TLL and it just works
add_library(bar1 bar1_src1.cxx bar1_src2.cxx)
target_link_libraries(bar1 PRIVATE foo)

// Use foo publicly so we need to separately grab the objects and
// their usage requirements.
add_library(bar2
  bar2_src1.cxx bar2_src2.cxx
  $<TARGET_OBJECTS:foo_objects>)
target_link_libraries(bar2 PUBLIC foo_interface)

This is effectively what the current plan is for the upstream
implementation, just all rolled into one; i.e. the objects get added to
whatever is explicitly linking with target_link_libraries, but all
transitive linkage only uses the interface usage requirements.  Plans, of
course, may change but that's what it's looking like right now, we just
need to find the time and funding to implement it.

- Chuck
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://public.kitware.com/pipermail/cmake/attachments/20170717/4aa1ff4d/attachment-0001.html>


More information about the CMake mailing list