diff options
Diffstat (limited to 'libstdc++-v3/docs/html/17_intro/HEADER_POLICY')
-rw-r--r-- | libstdc++-v3/docs/html/17_intro/HEADER_POLICY | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/libstdc++-v3/docs/html/17_intro/HEADER_POLICY b/libstdc++-v3/docs/html/17_intro/HEADER_POLICY new file mode 100644 index 00000000000..c6fa6d38b54 --- /dev/null +++ b/libstdc++-v3/docs/html/17_intro/HEADER_POLICY @@ -0,0 +1,164 @@ + +Header Policy +------------- + +The C++ Standard specifies many mutual dependencies among the +headers it defines. It offers no advice on how to arrange headers +to avoid problems. The worst such problem is circular references. +Most simply this is "A includes B, B includes A": + + // file <A> // file <B> + #ifndef A #ifndef B + #define A 1 #define B 1 + #include <B> #include <A> + typedef int A_type; typedef int B_type; + extern B_type g(A_type); extern A_type f(B_type); + #endif /* A */ #endif /* B */ + + // file C.cc + #include <A> + +The typical effect of such an "include loop" may be seen by tracing +the preprocessor activity: + + C // file C.cc + C #include <A> + A // file <A> + A #ifndef A + A #define A 1 + A #include <B> + B // file <B> + B #ifndef B + B #define B 1 + B #include <A> + A // file <A> + A #ifndef A <-- oops, cpp symbol A defined already + A ... <-- skip <A> contents + A #endif + B typedef int B_type; + B extern A_type f(B_type); <-- error, A_type not defined yet. + B #endif /* B */ + A typedef int A_type; + A extern B_type g(A_type); + A #endif /* A */ + +The main symptom of #include loops is that definitions from file <A> +are not available after the #include <A> for certain include orders. +The number of standard headers makes testing all permutations of +include order impractical, so a policy is needed to prevent chaos. +In any case, for some standard headers (as for the above) no ordering +can eliminate the loop. + +Other factors influence the policy. Typical implementations of +Make (unfortunately including GNU make) have bugs relating to file +names with no suffix, that lead to such problems as failure to track +dependencies on such files and an inclination to _delete_ them. +Therefore, headers used in building the library are always of the +form <bits/yyy.h> generally, or specifically <bits/std_xxx.h> for +an equivalent to the standard header <xxx>. + +Standard headers <xxx> are all placed under directory std/, and +are ignored except during installation. These headers simply +#include the corresponding header <bits/std_xxx.h>. + +Standard substitute headers <bits/std_xxx.h> that have any complexity +may sub-include other headers. When they sub-include non-standard +headers, they first include all the headers required for that +non-standard header. + +Mutual dependencies are handled by splitting up the declarations +intended for standard headers among two or more files, and then +interleaving them as needed. For example, we replace <A> and <B> +above, as follows: + + // file <bits/std_A.h> + #ifndef _CPP_A + #define _CPP_A + # include <bits/A_types.h> + # include <bits/B_types.h> + # include <bits/A_funs.h> + #endif + + // file <bits/std_B.h> + #ifndef _CPP_B + #define _CPP_B + # include <bits/A_types.h> + # include <bits/B_types.h> + # include <bits/B_funs.h> + #endif + + // file <bits/A_types.h> + #ifndef _CPP_BITS_A_TYPES_H + #define _CPP_BITS_A_TYPES_H + typedef int A_type; + #endif + + // file <bits/B_types.h> + #ifndef _CPP_BITS_B_TYPES_H + #define _CPP_BITS_B_TYPES_H + typedef int B_type; + #endif + + // file <bits/A_funs.h> + #ifndef _CPP_BITS_A_FUNS_H + #define _CPP_BITS_A_FUNS_H + extern B_type g(A_type); + #endif + + // file <bits/B_funs.h> + #ifndef _CPP_BITS_B_FUNS_H + #define _CPP_BITS_B_FUNS_H + extern A_type f(B_type); + #endif + +Of course we have the standard headers under their mandated names: + + // file <std/A> + #ifndef _CPP_A + #define _CPP_A + # include <bits/std_A.h> + #endif + + // file <std/B> + #ifndef _CPP_B + #define _CPP_B + # include <bits/std_B.h> + #endif + +Notice that the include guards are named uniformly except that +the guard for standard header <bits/std_A.h> is just _CPP_A, +identically as the header <A> in std/. + +At installation the files std/* can be replaced by symbolic links, +or simply copied into place as is. The result is: + + include/ + include/A -> bits/std_A.h + include/B -> bits/std_A.h + include/bits/ + include/bits/std_A.h + include/bits/std_B.h + include/bits/A_types.h + include/bits/B_types.h + include/bits/A_funs.h + include/bits/B_funs.h + + +Of course splitting up standard headers this way creates +complexity, so it is not done routinely, but only in response +to discovered needs. + +Another reason to split up headers is for support of separate +compilation of templates. This interacts with the foregoing +because template definitions typically have many more dependencies +on other headers than do pure declarations. Non-inline template +definitions are placed in a separate ".tcc" file that is included +by the standard header, and any other standard header that +requires definitions from it for its implementation. + +The key to preventing chaos, given the above structure, is: + + Only standard headers <bits/std_xxxx.h> should sub-include + other headers. + + |