[cmake-developers] Generator expressisons in target properties

Stephen Kelly steveire at gmail.com
Wed Nov 7 07:33:00 EST 2012


Brad King wrote:

> On 11/06/2012 02:07 PM, Stephen Kelly wrote:
>>> I don't think we should honor both properties at once.  If the new
>>> name is set the old names should be ignored (perhaps with a warning if
>>> an old name is set too).
>> 
>> That could be an option. I think it gets complicated though.
>> 
>> 1. In my branch I made tll() populate the INTERFACE_LINK_LIBRARIES prop
> 
> That opens a big can of worms because now activation of new interfaces
> for these features does not depend on modification of projects using the
> old interfaces.

Yes.

> An export generated with the new interfaces in it will not be understood
> by an older CMake.

The new content will not be understood, but the old content is still 
generated and will contain equivalent information (and possibly more 
information, if the maintainer populated the LINK_INTERFACE_LIBRARIES_DEBUG 
for example, but didn't add an equivalent new-style entry to the 
INTERFACE_LINK_LIBRARIES).

> This is okay if activation of new interfaces is
> explicit and intentional.  The user has then declared they are willing
> to require 2.8.11 for downstream consumers.  If activation is implicit
> then the generated export files must be able to work with either older
> or newer CMakes.

Yes. I wouldn't like to force maintainers to be able to use the new features 
only if they explicitly will bump the required version for their consumers 
too. 

I would prefer to make generated files work with both older and newer CMake 
files.

> I think 2.8.11 will have to generate export files that provide both
> old and new interfaces.

This is currently the case in my branch. The generator expression content is 
created in FooTargets.cmake and the old-style information is still generated 
in FooTargets-<Config>.cmake

> The choice will be made when they are loaded
> and depends on whether the application has also activated support for
> the new interfaces.

The problem with making an either-or choice on loading is that upstream may 
not have generated appropriate exported targets for that.

If upstream does this:

 add_library(foo ...)
 set_property(TARGET foo PROPERTY LINK_INTERFACE_LIBRARIES_DEBUG bar)

but does not do this:

 set_property(TARGET foo PROPERTY 
     INTERFACE_LINK_LIBRARIES $<$<CONFIG:Debug>:bar>
 )

and downstream chooses the CMake 2.8.11 behavior, they will not link to bar.

Using the union of new and old properties works around that, and it leaves 
upstream with the responsibility to decide when they don't support 
downstreams using CMake < 2.8.11 anymore (by not populating 
LINK_INTERFACE_LIBRARIES_DEBUG anymore and by adding and maintaining the 
generator expression property instead). 

This is similar to the choice of whether to use CMAKE_CURRENT_LIST_DIR in 
config files where it is very useful. In KDE we don't use it because we 
allowed downstreams to use CMake < 2.8.3 until recently.

So, I think using a union solves the problem of consuming and production, 
but as the solution is not explicit, it doesn't help us with the include-
directories/policy issue.

As far as I can see, the include directories issue is entirely contained 
upstream and doesn't affect downstream. Upstream can't have exported 
INTERFACE_INCLUDE_DIRECTORIES yet, so if they publish include directory 
information for downstreams, they do it using Foo_INCLUDE_DIRS which are 
hand-maintained.

Would it be an option to introduce something like 

 set(CMAKE_EXCLUDE_COMPILE_INFORMATION_IN_TLL TRUE)

or a better name, or a policy which has no warning (so new behaviour is only 
activated if cmake_minimum_required is 2.8.11), to make tll() not add the 
include directories and compile definitions as I've done in my patch? 

In cases where the include directory order is relevant, and where the order 
is different (necessarily or accidentally) to the order of libraries in 
tll(), users could either set that, or move their include_directories() call 
higher (In KDE at least it's uncommon for the include_directories() call to 
be below the add_* or tll() call). 

It is an incompatibility, but I want to float the idea of explicitly turning 
it off instead of explicitly turning it on. Explicitly turning it on would 
also solve the problem, but then everyone would have to have it as 
boilerplate in their CMakeLists files, and that's something non-obvious for 
someone who in 2 years sees the KDE buildsystem and tries to do the same, 
but it doesn't work. It harms adoption of the new features.

A new target_use_targets() command might also solve the problem, but my 
preference remains above until I know it's absolutely not an option :).

> 
> The question remains how to make activation explicit when combinations
> of old and new CMake versions are involved but automatic when everyone
> requires a newer CMake.
> 
>>> Yes, interfaces should be flattened and replaced with their content.
>> 
>> So the INTERFACE_LINK_LIBRARIES property would be handled differently for
>> an INTERFACE_LIBRARY than a SHARED_LIBRARY. I think that's a bit
>> confusing.
> 
> An interface wrapping around a single other library should be equivalent
> to defining the interface directly on that other library.  The logical
> name of the interface target is kind of like a generator expression when
> referenced in INTERFACE_LINK_LIBRARIES.  Wherever it is you process the
> generator expressions, first transform "myinterface" to
> $<TARGET_PROPERTY:myinterface,INTERFACE_LINK_LIBRARIES> or something
> like that.

Having thought about it more, I think that using 

 tll(foo iface) 

should not flatten. If the user explicitly wants flattening, I think they 
should have to use 

 tll(foo $<$<TARGET_PROPERTY:iface,INTERFACE_LINK_LIBRARIES>)

or even 

 tll(foo $<CONSUME:iface>)

or whatever.

Maybe we can come back to this point later after the rest is in place and 
we'll see the use-cases for flattening and not flattening.

Thanks,

Steve.





More information about the cmake-developers mailing list