[cmake-developers] Setting includes, defines and other usage requirements with one command

Brad King brad.king at kitware.com
Mon Feb 11 09:06:05 EST 2013


On 02/08/2013 04:56 PM, Brad King wrote:
> On 02/08/2013 03:16 PM, Stephen Kelly wrote:
>> My preference currently is to leave things as they are including the long 
>> and useless string.
> 
> Your analysis is quite extensive, thanks.

I thought about this more over the weekend.  I think we've made this much
harder than it needs to be.  One of the main arguments for propagating
includes and defines through tll() is that all other usage requirements
like -fPIC will now be able to propagate through it too.  However, why
don't those usage requirements turn into complex interface properties like
those we've been discussing for includes/defines?  It's because they are
not applied until generation time.

Almost all of the complexity in

 +  std::string value = !isGenex ? "$<LINKED:" + lib + ">"
 +                               : "$<$<TARGET_DEFINED:" + lib + ">:" +
 +                                   "$<TARGET_PROPERTY:" + lib +
 +                                   ",INTERFACE_" + property + ">"
 +                                 ">";

is due to trying to update INTERFACE_INCLUDE_DIRECTORIES and
INTERFACE_COMPILE_DEFINITIONS immediately instead of delaying usage
requirements until generate time.  Effectively all the generate-time logic
then needs to be encoded in generator expressions.  We used $<LINKED> as
a placeholder for that logic for named (potential) targets.  We still have
not solved the problem to my satisfaction for generator expressions, and
even $<LINKED> feels like a hack.

I think we should drop all that and instead have the includes and defines
usage requirements added at generate time based on the link closure.  We
discussed this before, and the reasons for doing it immediately were:

* Ordering of tll() calls relative id()/tid() and ad()/tcd()

* Allow user code to manipulate the properties after tll sets them

Now that we have added so much complexity to the expressions, user code
will not be able to reliably work with the property values.  Even if it
could, that would restrict us from ever changing how the expressions work
without breaking existing code that depends on manipulating a particular
expression.

Ordering does not matter for compile definitions.  Ordering does matter
for includes, but the reason we added <package>_NO_INTERFACES was due
to tll() changing the order for existing projects.  I think it will be
much simpler to have usage requirements of all types simply appended
to the settings configured by the project:

* Link libraries already work this way

* Compile definitions order does not matter

* Include directories order matters sometimes, but in cases the order
  generated by appending usage requirements fails the project can
  simply use tid() with $<TPROP:foo,INTERFACE_INCLUDE_DIRECTORIES>
  themselves.  Furthermore since the usage requirements always append
  there is no compatibility issue for upstreams adding include dirs
  so we may not need <package>_NO_INTERFACES.

This approach will drop all the complex generator expressions from
the interfaces altogether.  Only the expressions written by the
user will ever be needed.  For non-target library names passed to tll()
there is no issue because at generate time we will know they are not
targets.

-Brad



More information about the cmake-developers mailing list