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

Stephen Kelly steveire at gmail.com
Thu Jan 31 05:34:14 EST 2013


Brad King wrote:

> On 01/30/2013 12:09 PM, Stephen Kelly wrote:
>>> We can document that $<TARGET_DEFINED> has scope only in the current
>>> project and will be processed away during export.  I do not think we
>>> want an upstream interface modifying its behavior based on the mere
>>> presence of an arbitrary target in the downstream anyway.
> 
> Thoughts on this behavior?

I've left it in on export because it might make sense to use it with 
generator expressions even on export:

 set(lib_genex $<$<CONFIG:Debug>:debuglib>)
 tll(tgt $<TARGET_DEFINED:${lib_genex}:$<TARGET_PROPERTY:${lib_genex},FOO>)

> 
> Another thought is to have tll() only append includes/defines if the
> target is already defined at the call site and otherwise do nothing.
> When I previously pointed out the need for handling not-yet-defined
> targets I did not realize the cost.

I've made the LINKED generator expression a first-class expression, not just 
something to be preprocessed away. I think this addresses much of the cost 
concern.

In the KDE frameworks case, it was very useful to be able to refer to 
targets which were not defined yet, which was why I implemented it. 

It was useful for two reasons. One was that often the use of 
add_subdirectory(tests) appeared before the target it was testing (which tll 
handles), and another was the use of targets as dependencies of other 
library targets before that target was defined (and where re-ordering of the 
top-level directories doesn't seem to be possible).

So, I would prefer to keep that feature.

> 
> We could even go as far as not adding the generator expression to
> INCLUDE_DIRECTORIES if the target dependency does not have an
> INTERFACE_INCLUDE_DIRECTORIES already defined too (and similarly for
> COMPILE_DEFINITIONS).
> 
> Advantages:
> 
> * Very little overhead for non-target arguments
> * Very little overhead for targets without interfaces
> * Works in the motivating case of using targets imported from an upstream
> 
> Disadvantages:
> 
> * Does not work automatically for circular dependencies.

 * Does not work if the target is not defined yet, even in the non-circular 
   case
 * Assumes that interface includes are set before the tll() call. (ie it 
   does not work so well in the motivating case of non-imported targets)

It would break this:

 add_library(foo ...)
 add_library(bar ...)

 target_link_libraries(foo bar)
 target_include_directories(bar INTERFACE /usr/include/bar)

>>> * Transitive linking is handled in C++ code rather than in generator
>>>   expressions so there is no bloat in the LINK_LIBRARIES properties
>>>   for non-target elements like the above.  Perhaps we can have a special
>>>   generator expression that has context-sensitive evaluation e.g.
>>>
>>>     $<LINKED:blah>
>> 
>> That makes sense to me. I don't have time to do it right now though.
>> Maybe I can do it later.
> 
> Perhaps there is no need for it if we use the simpler approach above.

I've implemented the approach with LINKED in the tll-includes-defines branch 
in my clone. I think it's reasonably simple, compact and acceptable.

Thanks,

Steve.






More information about the cmake-developers mailing list