
2013/10/19 Andrey Semashev
On Saturday 19 October 2013 11:22:58 John Maddock wrote:
Trying to get this discussion somewhat back on track...
There are many libraries in Boost that have "glue" headers: by this I mean small headers that allow library A to interoperate with library B. Often these are simply specializations of traits classes or function overloads, are relatively trivial, and are not included unless you need them to be. By this I mean that: suppose library B wants to interoperate with lib A. It defines a special header which #includes what it needs from lib A and defines whatever specializations are required to get the two libraries working together.
Now here's the thing: there is no dependency from lib B to lib A *unless you are already using both libraries*.
A good example would be the serialization lib: a simple dependency tracker would show this up as a dependency to a large part of Boost, but in fact that's not true: in the vast majority of those cases there is no such dependency unless you actually want to use both libraries together and do so by including the "glue" header.
So where does the glue header belong?
In most cases if you want B to interoperate with A then you define a header which:
* Includes headers from both libraries. * Uses the public interface of A, but may access the internals of B (think serialization).
Which would imply that the header belongs with B. Pure and simple. Except it's not, because these two libraries may be peers, and interoperability may be more complex than simply unidirectional.
I don't have an answer here, but it seems to me that "dependency" is a more complex thing than simply what-includes-what (and that's without getting into header file, vs source file, vs test file dependencies).
I think a notion of an optional dependency is needed. I don't know how such dependencies should be expresses in the technical sense though. Ideally, ryppl (or whatever other dependency tracking system) should offer a way to select the dependencies to install.
I agree. Lets use the example of Boost.UUID and Boost.Serialization. My gut-feeling says that serialization support for UUID belongs to UUID. But lets consider the alternatives: If serialization support for all libraries belongs to Serialization, the Serialization library is required to keep serialization support updated for all current and future Boost libraries. If we say the glue code shall be a distinct component, we and up with an explosion of glue-components, one for each edge in the worst case. So, having serialization support as an optional part of the supported components seems most viable. Simply scanning all headers for #includes gives a list of all possible dependencies. Telling whether such a dependency is actually required or just optional cannot be easily decided. A smarter dependency scanner might be able to distinguish optional dependencies for libraries that provide an "include all" header. Example: "boost/asio.hpp" pulls in most headers from Boost.ASIO, but not all. "boost/asio/ssl.hpp" is an example of such an exception. Hence, SSL is an optional dependency of Boost.ASIO. cheers, Daniel