On 12/12/2012 05:32 PM, David Cole wrote: > I strongly agree with Alex here. > > Mysteriously changing the target_link_libraries implementation to > automatically do a bunch of stuff BY DEFAULT that it didn't used > to do violates the principle of least surprise big time.
Yes. Also I think some of the complexity, as discussed in related threads during the last couple of days, comes from trying to figure out when to propagate linking (-l), includes (-I), definitions (-D), and any other part of the usage requirements transitively. The main distinction between the two approaches is: * target_link_libraries: Specify link (-l) rules explicitly, get other usage requirements (-I/-D) implicitly. * target_use_interfaces: Specify interfaces explicitly, get all usage requirements implicitly (-l/-I/-D). I think what David and Alex are saying is that the latter is much clearer. After your (Steve's) dive into the former approach so far we've seen that implementation is difficult, especially when considering compatibility. Having thought more about how to implement either approach I think that the latter approach is not only clearer but cleaner too. I really like the name "target_use_interfaces" because it reads as "use the interfaces defined by the following". Any of the normal target types can define interface properties. The proposed INTERFACE_LIBRARY would be distinct only in that it does not do anything other than define an interface. I think the key here is to make the "interface" a first-class concept that subsumes all usage requirements (-l/-I/-D/etc.). Transitive closure can be handled at the interface usage level and the results used to populate the interface components. I propose the following new command: target_use_interfaces(tgt [<PUBLIC|PRIVATE|INTERFACE> tgts...]...) Forcing use of the keywords handles Daniel's concern about clear argument separation. The command will populate target properties: USE_INTERFACES = to build tgt (set by PUBLIC/PRIVATE) INTERFACE_USE_INTERFACES = to use tgt (set by PUBLIC/INTERFACE) To generate the build rules for a target read its USE_INTERFACES, follow the INTERFACE_USE_INTERFACES dependency links of those, and compute the transitive interface closure. Order it by a simple topological sort that starts with the original USE_INTERFACES and adds any dependencies in topological order. This is how library ordering already works for linking, but it will be simpler for interfaces because all dependencies are explicit and cycles are not allowed. Note that this says nothing about what is *in* the interfaces. It only declares relationships. We don't even need to distinguish separate behavior for STATIC v. SHARED libraries. The distinction can be made under the hood in populating the interface components. I'll defer my thoughts on details of defining and exporting each part of the interface for a future message after we've discussed the overall approach. Now, given the interface closure computed as above to build a target, we simply take (non-transitively) the usage requirements from each interface and append them to the corresponding build rules of the target: impl.Libraries += iface.Libraries impl.Includes += iface.Includes impl.Defines += iface.Defines ... This can all be done inside C++ structures rather than with properties and generator expressions because it is only done during generation. The final impl.Libraries will still be processed to compute a final transitive link closure, but that won't add anything new to the other usage requirements anyway. So, the final build rules (-l/-I/-D/etc.) for a target will start with whatever was specified explicitly via target_link_libraries, include_directories, add_definitions, etc., which take precedence. Then we append anything from the used interfaces. The project can choose whether to use the old approach or the new approach or a mixture of the two. -Brad -- Powered by www.kitware.com Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ Follow this link to subscribe/unsubscribe: http://public.kitware.com/cgi-bin/mailman/listinfo/cmake-developers