|
|
A usage dependency exists when one component refers to another, either in its interface, or in its implementation. We refer to the first kind of dependency as an interface dependency and to the second kind as a linkage dependency.
One way to avoid excessive compilation time is to minimize interface dependencies when designing components. For example, consider the use of class ostream (defined in the iostream(3C++) component) by the stream insertion operator of the String(3C++) component (assume that iostream.h does not have an init object, and hence that we are not prevented from #include'ing it for the reasons explained in ``More about avoiding init objects''):
String.h class String {...}; // The following introduces an interface // dependency // (The String interface refers to iostream) inline ostream& operator<<(ostream& os, const String& s) { os << (const char*)s; }
This will not compile as written, since class ostream is undefined. An obvious (but inefficient) solution would be for String.h to include iostream.h:
String.h #include <iostream.h> class String {...}; inline ostream& operator<<(ostream& os, const String& s) { os << (const char*)s; }
If we do this, then any file that includes String.h will also include iostream.h, plus any header files that iostream.h includes, and so on. In general, including one header file for one component brings in all header files in the transitive closure of the component's interface dependencies. In the worst case, this can be all the header files in the library! In our experience, programmers will complain vigorously about the time it takes for such files to compile.
Our solution is to minimize interface dependencies. In the above example, this is fairly easy to do: we simply replace the include directive by a forward declaration of class ostream, and take the insertion operator out of line, moving its implementation to a .c file:
String.h // Note that we no longer include iostream.h class ostream; // forward declaration class String {...}; ostream& operator<<(ostream& os, const String& s);
Now the compilation speed penalty for including iostream.h is paid only once - when the library is built.