[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