Popular C and C++ compilers interpret the quoted include directive (#include "path") to mean that the specified path should be searched first in the directory of the including file. If not found there, these files are next searched as if they were included using the angle bracketed include directive (#include <...>). Typically, compilers interpret ``directory of the including file'' to mean either or both of the directory of the file containing the #include, and the directory of the top level (primary) source file. Note that this interpretation of the quoted include directive is not specified in the C standard, that standard only states that quoted include files are to be searched for in an ``implementation-defined manner.'' (ISO/IEC 9899-1990(E) 6.8.2)
In a viewpathing situation, searching only in the directory of the including file is no longer sufficient, because the including file may be in a viewpath node that is ``up the viewpath''; according to viewpathing semantics, a file in this directory may be overridden by a file in the corresponding directory in a ``closer'' viewpath node. -I- and prefixinclude generalize the concept of ``directory of including file'' to support viewpathing.
For example, say a viewpath of ``node1:node2'' is being used. With this, files in node1 have precedence over files in node2. Files in node1 should be used when they exist, otherwise the file will be picked up from node2. If a source file, a.c, is in node2, and an included file, a.h(node2), is in the same directory, and a newer a.h(node1) exists in node1, then the compiler will include a.h(node2) and ignore the newer a.h(node1), thus violating the viewpath. This can also occur when a header file includes another header file.
Effectively, the -I- option replaces the single ``directory of the including file'' with a series of directories, which are specified using -I options appearing before the the -I- option on the compiler command line. We will call this directory sequence ``the local include search path.'' Instead of looking only in the ``directory of the including file'' for files specified using the #include "..." directive, the -I- option specifies that the compiler should search the local include search path. The -I- search scheme is sufficient to handle the case where the ``directory of the including file'' is directly on the search path specified by the -I options.
There may be no more than one -I- flag on the command line. To summarize, the -I- flag does the following:
$ cc -I. -I/bld/src/myproj -I../../include -I/bld/include -I../inclu de -I/bld/src/include -I- -I/opt/A/include -I/opt/B/include -c main.c
The -I- option is not sufficient to handle the case involving a quoted include from a parent file which is not directly on the quoted or bracketed search paths. prefixinclude provides additional support for the case where, due to use of directory prefixes in #include directives in parent including files, the ``directory of the including file'' is no longer directly on the include search list. In the non -I- case, use of directory prefixes in parent #include directives causes the compiler to look in some directory offset from the directory of the top-level source file. Analogously, in the -I- case, use of directory prefixes in parent include files in effect define an offset relative to the directories on the search list. This is equivalent to explicitly specifying the directory prefix explicitly in the child #include "..." directive. In fact, modifying the source #include directive in this way would allow the intended included file to be found without requiring prefixinclude support in the preprocessor.
Here's an example of the problem:
$ ls -l total 16 -rw-r--r-- 1 fjb1 fjb1 20 Jul 26 08:08 a.c drwxr-xr-x 2 fjb1 fjb1 4096 Jul 26 06:33 incl -rwxr-xr-x 1 fjb1 fjb1 241 Jul 26 2000 mk $ ls -l incl total 0 -rw-r--r-- 1 fjb1 fjb1 35 Jul 26 06:44 f.h -rw-r--r-- 1 fjb1 fjb1 7 Jul 26 06:24 x.h -rw-r--r-- 1 fjb1 fjb1 7 Jul 26 06:32 y.h $ cat a.c #include "incl/f.h" $ cat incl/f.h #include "incl/y.h" #include "x.h" $ cat incl/x.h int x; $ cat incl/y.h int y; $ CC -c -I. a.c $ CC -c -I. -I- -I. a.c "./incl/f.h", line 2: Error: Could not open include file "x.h". 1 Error(s) detected.
See that a.c compiles fine with `-I.' but with `-I. -I- -I.' it fails to find x.h.
With the prefixinclude feature in effect, the subdirectory prefix is inherited from the including file for #include "..." style includes. So, if an including file was included as "prefix/includer" or <prefix/includer> then a file "includee" included by "prefix/includer" is first searched for using "prefix/includee", and, if that fails, is next searched for using "includee".
Note that adding additional -I options for each sub include directory is not correct, since include files having the same name may appear in different subdirectories of the include search path. The prefixinclude approach provides the correct behavior by maintaining the association between the file name being searched and the offset of the parent directory from the include search path.
Consider the case where there are 2 include directories, say incl1/ and incl2/. A top-level file a.c includes files in both of these subdirectories, say incl1/f1.h and incl2/f2.h. Suppose incl1/f1.h includes a file "x.h", and incl2/f2.h also includes a file "x.h". By normal C include semantics, we want incl1/f1.h to pick up incl1/x.h, and incl2/f2.h to pick up incl2/x.h. There is no sequence of -I options that will cause incl1/f1.h to always pick up incl1/x.h, and incl2/f2.h to always pick up incl2/x.h. If we say ``-Iincl1 -Iincl2'', then both incl1/f1.h and incl2/f2.h would end up getting incl1/x.h, not what we want. The prefixinclude feature takes care of this by inheriting the directory prefix from the parent. When processing incl1/f1.h the include of "x.h" causes a search for "incl1/x.h", and if that fails then a search for "x.h". Likewise, when processing incl2/f2.h the search is for "incl2/x.h", and if that fails, then "x.h".
Searches for #include <...> files are not affected by prefixinclude, only #include "..." file searches are enhanced.
Contents of main.c:
Contents of incl/f1.h:
Compile command line:
$ cc -I../include -I/bld/ofc/include -I- -I/opt/pkgs/include -c main.c
Searching for x.h: