Hacker News new | ask | show | jobs
by mehrdada 1498 days ago
You can do some tricks but the basic issue is that the "environment" in which you interpret the preprocessor directives for a ".h" file may change across different contexts resulting in a potentially distinct AST: simplest example is the common #ifndef guard (evaluates the true branch in the first load, false in subsequent ones).
2 comments

The compiler would store the condition in memory, and reevaluate the condition every time the file is included again. If the contents of the file aren't skipped, then it would actually read the file again and parse it normally.

For instance, if the file was this:

    // my-file.h
    
    #ifndef MY_FILE_INCLUDE_GUARD
    #define MY_FILE_INCLUDE_GUARD

    void f(void);

    #endif
the compiler would remember the “#ifndef MY_FILE_INCLUDE_GUARD” part.
Sure you can reuse a cached file at a token level, but you cannot easily do that at the parse tree can be completely different based on preprocessor state.
I'm just showing how a compiler could optimize files that have include guards. This doesn't do anything for files that are intended to be included multiple times.
Ach. Fun
Plus the default is to launch a different instance of the compiler for every .c/.cpp file, so that state has to be written out to disk and reread by the next one.

If I ever did another C or C++ project (which would probably only be at gun–point), I would go the opposite route and have only a single compilation unit. I would have a single primary source file that included all of the others, and none of the others would include anything. Then I could run the compiler a single time on just that one file and it would be as fast and as simple as possible. Well, I don’t know of any C or C++ compilers that can spread their work over multiple cpus (since we usually just run multiple instances simultaneously with make -j), but other than that it would be as fast as possible.

If you use cmake it can do exactly this for you automatically : just pass -DCMAKE_UNITY_BUILD=1
“Unity build” seems like a pretty good name for it.