[cmake-developers] Object library linking (and a bit about INTERFACE_SOURCES)

Ben Boeckel ben.boeckel at kitware.com
Mon Feb 23 13:44:13 EST 2015


Hi,

I have a branch on my Github fork to support object library linking:

    object-library-linking
    https://github.com/mathstuf/CMake/tree/object-library-linking

This implements support (rather, remove restrictions) for the following:

    target_link_libraries(lib     objlib)
    target_link_libraries(objlib  lib)
    target_link_libraries(objlib1 objlib2)

The test cases are kind of rudimentary (makes sure it is allowed,
symbols exist, and that usage requirements work), so any other cases you
can think of would be nice to add to the test suite.

There is also a commit which updates usage of $<TARGET_OBJECTS> to not
be allowed in IMPORTED targets. This would likely require a policy
unless anyone can think of a use case for allowing it (or just do "no
worse" than previous versions and just let it be).

What it does *not* do is set INTERFACE_SOURCES to $<TARGET_OBJECTS> for
object libraries because to do so would mean that the objects would get
compiled into each library which requires it. I thought about denying
INTERFACE_SOURCES to objlibs altogether but decided against it since the
same thing can be done with other libraries anyways. I think the real
solution to this is to make INTERFACE_SOURCES not transitive and only
apply for direct usage through target_link_libraries (and punt for now
on "diamond inheritence" of INTERFACE_SOURCES). Here's the commit
message I wrote when initially blocking INTERFACE_SOURCES from objlibs:

    INTERFACE_SOURCES is a special beast anyways in that the following
    setup is likely to cause duplicate symbols:

        add_library(a INTERFACE)
        target_sources(a INTERFACE sym1.c)
        target_include_directories(a INTERFACE some/path/for/sym1)
        target_compile_definitions(a INTERFACE CLIENT_DEFINE)

        add_library(b SHARED shared.c)
        target_link_libraries(b PUBLIC a) # Needs CLIENT_DEFINE and to
                                          # propagate the include

        add_executable(exe main.c)
        target_link_libraries(exe b)

    Here, sym1.c is compiled as part of 'b' and 'exe'. Issues arise when
    a either has global statics within the source file (ld-linux.so will
    construct it once, but try to destroy it twice), exports symbols
    (multiple definitions), etc. This is especially prone to abuse with
    OBJECT libraries, so block its usage.

    The real fix is to make INTERFACE_SOURCES only applicable when
    directly linked and not transitive, but that is a bigger change.

A workaround for now could be to do:

    add_library(objlib OBJECT)

    add_library(objlib-srcs INTERFACE)
    target_sources(objlib-srcs INTERFACE $<TARGET_OBJECTS:objlib>)

    add_library(a)
    target_link_libraries(a PUBLIC objlib PRIVATE objlib-srcs)

but that is a little messy (though at least a bit cleaner than
$<TARGET_OBJECTS:objlib> repetition everywhere).

--Ben


More information about the cmake-developers mailing list