[cmake-developers] Setting include directories via target_link_libraries() ?

Stephen Kelly steveire at gmail.com
Fri Dec 21 13:08:57 EST 2012


Brad King wrote:

> On 12/18/2012 11:09 AM, Stephen Kelly wrote:
>>> At generate time that property
>>> will be used to accumulate values from INTERFACE_-like properties on
>>> the named interfaces and append them to LINK_LIBRARIES, etc.
>> 
>> You wrote before that you don't propose using properties and generator
>> expressions:
> 
> Well, the raw properties (e.g. INCLUDE_DIRECTORIES) would initially
> populate the generate-time C++ structures.  Then the structures would
> be extended after evaluating interfaces of dependencies.


> In the above example the target_use_interfaces command would not do
> anything except append foo to bar's USE_INTERFACES property.  Then at
> generate time for building bar, CMake would read its USE_INTERFACES
> and see that it needs to include the interface defined by foo.  It
> would then go read INTERFACE_INCLUDE_DIRECTORIES from foo and append
> the value to bar's include directories when generating.


When you get around to explaining more of your proposal, here are some more 
things I don't like about it. You can keep them in mind when updating your 
proposal, either by filling the gaps in my understanding of your proposal or 
by updating it to handle them.

1) Appending the interfaces from used targets is confusing:
 
 target_link_libraries(foo lib1)
 target_use_interfaces(foo INTERFACES lib2)
 target_link_libraries(foo lib3)

Warning: link order is lib1;lib3;lib2

 include_directories(${lib1_INCLUDE_DIRS})
 target_use_interfaces(foo INTERFACES lib2)
 include_directories(${lib3_INCLUDE_DIRS})

Warning: include order is lib1/;lib3/;lib2/

2) There is no way to 'use an interface' at the same time as manipulating 
the order of its use. 

Same code example as above does not do so:

 target_link_libraries(foo lib1)
 target_use_interfaces(foo INTERFACES lib2)
 target_link_libraries(foo lib3)

We would have to expand the 'use command' instead, and then maintain the 
expansion:

 target_link_libraries(foo lib1)
 target_link_libraries(foo lib2)
 # Warning: Required duplication. Is the reason for it clear to the reader?
 target_use_interfaces(foo INTERFACES lib2)
 target_link_libraries(foo lib3)
 
The same logic applies to include directories of course.

If the target_use_interfaces command did not manipulate a USE_INTERFACES 
property, but instead manipulated the mulitple INTERFACE_* properties in-
place (not appending) as my branch already does, it would be more clear. 

I added a patch to my wip-target-interface branch to illustrate that a bit. 

Note that my branch still uses the tll() command for populating the 
INTERFACE_* properties, but that does not matter as the transitivity-with-
properties question is separate to the new-command question.


3) Reading a property does not give a complete picture

 include_directories(${lib1_INCLUDE_DIRS})
 target_use_interfaces(foo INTERFACES lib2)

 get_target_property(_foo_includes foo INCLUDE_DIRECTORIES)
 # Warning: This output does not tell me what includes are actually used.
 message("Foo includes: ${_foo_includes}")

This problem is mostly mitigated by the debugging facility I already merged 
to next, but it is nonetheless surprising.

4) Upstream can not communicate an order of dependenency includes.

 target_use_interfaces(lib2 INTERFACES lib1)
 target_use_interfaces(foo INTERFACES lib2)
 target_use_interfaces(foo INTERFACES lib3)

lib1 and lib2 both have a common.h header. lib2 must be used with the 
common.h from lib1. 

Assuming the order of used interfaces is 'direct interfaces first, followed 
by their dependencies' the order of resulting includes will be:

 lib2/;lib3/;lib1

lib2.h includes common.h expecting that it will come from lib1, but when foo 
uses it, it comes from lib3.

The top commit in my wip-target-interface branch also illustrates this 
problem.



I can see the attraction of a single first-class property for 'using an 
interface', but I think the way that an interface is to be used depends on 
the property, and so I think it makes more sense to determine dependencies 
of them on a per-property basis. I much prefer the granularity.

As far as I understand your proposal as explained so far, I think it is more 
complex to understand and implement. I haven't spent any brain-cycles on 
considering the export stuff. I assume that may be complex with the 
USE_INTERFACES property.

Hopefully you can clarify with these kinds of cases in mind.

Thanks,

Steve.





More information about the cmake-developers mailing list