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

Stephen Kelly steveire at gmail.com
Wed Feb 25 17:43:18 EST 2015


Ben Boeckel wrote:

>> It is just as easy to get into this situation when linking static
>> libraries, right? Object libraries are not part of the problem, right? Or
>> could you post a sscce?
> 
> It is, so maybe it's less of an issue. I just think it is much easier to
> stumble upon it when you start throwing objects directly into link lines
> implicitly rather than with a staticWithGlobalStatic -> {sharedA,
> sharedB} -> exeUsingAandB setup.

Right. Consider

 add_library(upstream ...)

 add_library(middle ...)
 target_link_libraries(middle ${SCOPE} upstream}

 add_executable(consumer1)
 target_link_libraries(consumer1 middle)

 add_library(consumer2 SHARED)
 target_link_libraries(consumer2 middle)

We have these possible scenarios (omitting INTERFACE scope, and omitting 
middle=OBJECT because I think it doesn't change anything):

  upstream    SCOPE      middle
 ----------  ---------  --------
  STATIC      PRIVATE    STATIC
  OBJECT      PRIVATE    STATIC
  STATIC      PUBLIC     STATIC
  OBJECT      PUBLIC     STATIC
  STATIC      PRIVATE    SHARED
  SHARED      PRIVATE    SHARED
  OBJECT      PRIVATE    SHARED
  STATIC      PUBLIC     SHARED
  SHARED      PUBLIC     SHARED
  OBJECT      PUBLIC     SHARED

Omitting the upstream = SHARED or STATIC cases too, because I think they're 
not relevant to this discussion.

  upstream    SCOPE      middle
 ----------  ---------  --------
  OBJECT      PRIVATE    STATIC
  OBJECT      PUBLIC     STATIC
  OBJECT      PRIVATE    SHARED
  OBJECT      PUBLIC     SHARED

If middle is STATIC, and SCOPE is PRIVATE, then the upstream objects are 
archived together with the rest of middle. Consumers use middle as if the 
upstream objects were not declared separately.

If SCOPE is PUBLIC, perhaps it should be treated as PRIVATE or INTERFACE? 
That is, either not archive the upstream objects with middle (letting 
downstreams link the objects directly instead), or not link them in with 
downstreams (which will get them anyway through linking with middle).

If middle is SHARED and scope is PRIVATE, then there is no problem (Except 
perhaps the global object issue, but that is present also if upstream is 
STATIC and it can be argued that no library should legitimately do that 
anyway).

If middle is SHARED and scope is PUBLIC, then the situation is very similar 
to upstream=STATIC, in that the objects get compiled into middle and into 
each of the consumers. Is this an undesired effect? 

Let's imagine upstream is statically compiled zlib and middle is the 
FooCompress library which uses zlib in its implementation and uses zlib 
headers in FooCompress.h, but doesn't dllexport the zlib symbols (Is that a 
realistic scenario?), and expects consumers to also link the zlib.a instead. 
I have trouble imagining any other reason a SHARED library would PUBLIC link 
a STATIC or OBJECT library otherwise. But in the scenario I described, 
consumers must link the zlib.a (or .o), right? 

Or should it be prohibited to put OBJECT libraries in the INTERFACE of 
SHARED libraries?

Again, even if the upstream is STATIC, this is a problem only in the 
presence of global objects provided by upstream.

>> > For the diamond-usage problem, is there some way of utilizing the
>> > COMPATIBLE_INTERFACES to deny the mixing of two libraries where each
>> > built with an object libraries' objects? Having a property to trigger
>> > that would be nice...
>> 
>> Yes, that's possible by adding an ExclusiveList compatible type and
>> populating an appropriate property when linking to OBJECT libraries. I've
>> written a prototype and can clean it up and post it if that's part of the
>> solution.
> 
> As long as it is opt-in, I'm fine with this (it only really makes sense
> in the presence of global statics with dtors).

That appears to be the only problem being discussed here. I'm sure 
ExclusiveList could help, but in the case you describe, CMake wouldn't 
populate anything automatically (thereby making it opt-in).

>> > Until that problem is solved we cannot make object libraries
>> > implicitly offer their objects just through tll().
>> 
>> Honestly, the problem is still not clear to me. Is it something you would
>> want to write and expect to be correct, but which would actually be
>> incorrect? Is the static global object instance a necessary part of the
>> problem-scenario?
> 
> So this problem came up in a project where the current code uses LIBADD
> in autotools. These added libraries are conditionally built and have
> varying usage requirements (headers, linking, defines, etc.). Oh, they
> also have symbols which need exporting. 

What is the type of these libraries? I'm guessing SHARED as you talk about 
exporting.

> Yes, I already tried using static libraries (I think $<LINK_ONLY> made
> the duplicate symbols occur in dependent projects which use shared libs
> through the transitive linking which then all went into an executable);
> that's how I ended up trying object libraries.

Maybe something I wrote above is fuel for thought here?

Thanks,

Steve.




More information about the cmake-developers mailing list