[OpenWalnut-Dev] Includes

Christian Heine heine at informatik.uni-leipzig.de
Tue Aug 23 17:26:10 CEST 2011


Hi,

just to summarize and give new points for using relative paths in 
includes. If this email is too long read the summary at the end.

The semantics of finding include files is not explicitly specified 
in the standard. Compilers are rather free to implement file lookup. 
GCC has three lists of searched include directories. (a) the 
directory of the current base input (.cpp) file (b) include 
directories as specified on the command line, (c) include paths 
hardcoded into gcc (or preprocessor, really).

Because (b) is only known to the build system, and (c) is only known 
to the compiler, an IDE or editor cannot work with includes other 
than relative paths in "". When a different style is used, a 
compiler may even include the wrong file and have high I/O cost 
because a great many number of files need to be tested.

When using
#include "X"
the gcc tries (a) first, then (b), and then (c).

When using
#include <X>
the gcc tries (b) first, then (c).

I tested what that means in practice. I wrote some files:

core/core.hpp       // empty
module/moduleA.cpp  // #include "core/core.hpp"
module/moduleB.cpp  // #include <core/core.hpp>
module/moduleC.cpp  // #include "../core/core.hpp"
module/moduleD.cpp  // #include <../core/core.hpp>

run the preprocessor on them and straced open system calls. (and 
cleaned the output)

$ strace cc1plus moduleA.cpp

open("module/core/core.hpp",
open("/usr/include/c++/4.5/core/core.hpp",
open("/usr/include/c++/4.5/x86_64-linux-gnu/core/core.hpp",
open("/usr/include/c++/4.5/backward/core/core.hpp",
open("/usr/local/include/core/core.hpp",
open("/usr/lib/x86_64-linux-gnu/gcc/x86_64-linux-gnu/4.5.2/include/core/core.hpp",
open("/usr/lib/x86_64-linux-gnu/gcc/x86_64-linux-gnu/4.5.2/include-fixed/core/core.hpp",
open("/usr/include/x86_64-linux-gnu/core/core.hpp",
open("/usr/include/core/core.hpp",

in other words, it was not found, but quite a number of places was 
searched. Note the first futile relative to the input file's 
location. Hope that is is futile. Or would you rather include the 
wrong file? Adding -I.

$ strace cc1plus -I. moduleA.cpp:

open("module/core/core.hpp",
open("./core/core.hpp",

found it in two tries, (unless there were a module/core/core.hpp) 
but -I. is required.

$ strace cc1plus moduleB.cpp

open("/usr/include/c++/4.5/core/core.hpp",
open("/usr/include/c++/4.5/x86_64-linux-gnu/core/core.hpp",
open("/usr/include/c++/4.5/backward/core/core.hpp",
open("/usr/local/include/core/core.hpp",
open("/usr/lib/x86_64-linux-gnu/gcc/x86_64-linux-gnu/4.5.2/include/core/core.hpp",
open("/usr/lib/x86_64-linux-gnu/gcc/x86_64-linux-gnu/4.5.2/include-fixed/core/core.hpp",
open("/usr/include/x86_64-linux-gnu/core/core.hpp",
open("/usr/include/core/core.hpp",

also fails and in comparison to moduleA only the test for 
"module/core/core.hpp" is omitted. Fixing by adding -I.

$ strace cc1plus -I. moduleB.cpp

open("./core/core.hpp",

only one open. But we need -I. But assume we had another -I on the 
command line before.

$ strace cc1plus -I/local/cheine/include -I. moduleB.cpp

open("/local/cheine/include/core/core.hpp",
open("./core/core.hpp",

which in a project with many library dependencies can easily arise. 
In constrast the plain relative path:

$ strace cc1plus moduleC.cpp

open("module/../core/core.hpp",

requires only one open and does not need -I. Even if we add further -Is

$ strace cc1plus -I/local/cheine/include moduleC.cpp

open("module/../core/core.hpp",

one, and only one. Btw.

$ strace cc1plus moduleD.cpp

does not find core.hpp at all, even if -I is provided.


=== In summary === The relative paths in "" are the fastest and most 
reliable way to refer to a file (in a sense that it is always 
preferred to a file of same name in the system). It does not require 
-I. Include paths in <> are reliable only when -I. is the first of 
its kind on the command line. But you lose IDE/editor integration. 
Absolute paths in "" are very unreliable. IDEs and editors are 
puzzeled. Remember, with each additional include directory that is 
searched before the right file is found, the likelihood that another 
header file with the same name is found increases.

If you don't like ".." in relative paths (neither do I) restructure 
your code rather than use unrelyable paths.

Best regards,
Christian

On 08/23/2011 11:43 AM, Alexander Wiebel wrote:
> Hi,
> why did the paths change to absolute from relative?
> Example:
>
> #include "core/common/WAssert.h"
> instead of
> #include "../../core/common/WAssert.h"
> from a module's directory
>
> Please consider the discussion we had for FAnToM (see below).
>
> Thanks for clarifying this for me.
>
> Cheers
> Alex
>
>
> -------- Original-Nachricht (anonymisisert) --------
> Betreff: Re: [FAnToM] Includes of FAnToM
> Datum: Thu, 09 Jul 2009 15:01:54 +0200
> Von: CH
> Organisation: University of Leipzig, Germany
> An: XT
> CC: List
>
> Hi,
>
> XT schrieb:
>> Hi,
>>
>> May we ask why? This new convention sounds overly cumbersome. I
> guess
>> I am just lacking a clear understanding of the problems that led to
>> that decision.
>>
>> Thanks,
>> XT
>
> Overall this should increase the building of fanton if few things
> have changed, and removes an highly unlikely strange effect, if not
> security hole.
>
> In detail, the answer is simply because
>
> (a) #include "common/src/FString.hh"
>
> it is bad for the build environment. It should be either
>
> (b) #include "../../common/src/FString.hh"
>
> or
>
> (c) #include<common/src/FString.hh>
>
> (a) is correct code, because the §16.2 of the C++ standart (current
> working draft of c++-0x) states that in the case of (a) a compiler
> should look for the included file *relative* to the including file
> and if that search fails it should treat it as (c). But the search
> for (a) always fails and forces the compiler to traverse the
> standard include directories. Also, (c) can not avoid that a system
> installed<common/src/FString.hh>  is used rather than the one that
> is actually meant (although highly unlikly), and neither does (a) if
> the compiler is forced to fall back to (c).
>
> Because the search for (a) always fails it forces the compiler to do
> many unneccessary stats. Using (c) rather than (a) removes only one
> of them. I suggested to use (b) rather than (c) to minimize the
> number of search directories for includes and to improve on the
> build speed. Furthermore, (a) confuses the automatic generation of
> dependencies. I have observed that some files occur up to three
> times in the dependencies (for each object file), always using
> different paths. This can slow down the build environment,
> especially on NFS, because to determine whether a target has to be
> rebuilt, these file have to be stat as many times as they occur in
> the dependency lists.
>
> I agree that (b) looks bad, but it looks bad for a reason. It shows
> a poor modularization of FAnToM. It will probably look nicer if the
> whole directory restructuring is finished. But that won't remedy the
> original problem.
>
> Best regards,
> CH
> _______________________________________________
> OpenWalnut-Dev mailing list
> OpenWalnut-Dev at lists.informatik.uni-leipzig.de
> http://lists.informatik.uni-leipzig.de/mailman/listinfo/openwalnut-dev


-- 
Dipl.-Inf. Christian Heine
Institut fuer Informatik | phone: +49-341-97-32311
Universitaet Leipzig     | fax:   +49-341-97-32252
PF 100920                | mailto:heine at informatik.uni-leipzig.de
D-04009 Leipzig, Germany | http://www.informatik.uni-leipzig.de/bsv/


More information about the OpenWalnut-Dev mailing list