Faking additional include directories

What are additional include directories

In C and C++ additional include directories (as it is called in Microsoft’s Visual C++) are the directories where include files are searched when they are not present in the current directory or in the standard library.

example:

#include <iostream> // <== file from the standard library
#include "MyHeaderFile.h" // <== where does that file exists?

MyHeaderFile.h will be searched in the same directory as the current file (which includes the include statement). If it is not found the compiler will search it in all additional include directories.

Who defines the additional directories?

You as a programmer define these directories. The compiler just define the (additional) directories for the standard library shipped with the compiler.

But why faking additional include directories?

As you can read in the title of this post, I will explain how you can fake additional include directories. But why should you do something like that?

Short answer: If your build system has no additional include directories support!

At work I have to integrate our internal framework into the CAD system called CATIA. CATIA is one of the biggest commercial CAD’s in the world. It’s framework is called CATIA CAA. I worked with CAA for the last 12 years and build a lot of features with it. CAA can be use in Visual Studio via RADE (Rapid Application Development Environment). RADE is, in short, a compiler toolset, which is build on top of msvc. RADE is mostly based on (naming) conventions. Shared libraries have to be on a specific place in the project directory to be detected by RADE.

A typical CAA project directory look like the following (simplified)

  • MyFramework
    • PublicInterfaces
    • MyShareLib.m
    • MySecondShareLib.m
  • MyOtherFramework
    • PublicInterfaces
    • MyLib.m

The toplevel directories contains the frameworks. Each framework contains a list of modules.

All directories ending with .m are code modules. They can build *.dll, *.exe and some other types depending on the settings in the makefile in the module directory.

The PublicInterfaces directory contains all the header file which can be used from outside. And here is where the problem starting.

Generating a CAA Framework

To be able to integrate our framework (which is prebuilt) into CAA, I have to create a CAA framework which can be used by other frameworks.

It was easy to create the framework directory and copy the lib and dll files into specific folder that they can be used by RADE. The problem was the PublicInterfaces directory. I can not add additional directories (I can only add absolute paths which is not a good approach. The reason is easy, RADE copy the header files to the other framework when they are used, so relative paths would not work with RADE). And here is where my idea of faking additional include directories rise.

How does additional include directories work?

Additional include directories are really simple. The are just a list of directory paths which are searched from left to right to find the given header file.

f.e. the list could look like C:\MyDir1;C:\MyDir2;D:\MyDir3 When there is a include statement like #include "MyHeaderFile.h" the preprocessor will look into the directory for the file which contains the include statement, then in C:\MyDir1, C:\MyDir2 and D:\MyDir3. When it find the file it will stop the search and go to the next include statement (otherwise you will get an error).

To be able to “emulate” that we need to find a way to get the same behavior without additional include directories property.

Conan the c++ package manager

I will use conan, the C++ package manager, which is a really great tool and I highly recommend it. With conan it is really easy to get all my additional include directories, lib, dll and exe files because our framework is available as a conan recipe. Without that it would be really hard to get all the required information.

Fake it

The idea is simple. I just have to copy all header files from right to left from the additional include directories into the PublicInterfaces. With that every file which would be the same will be overwritten. Because of the right to left order I will get the same behavior as searching from left to right. Damn, that was easy. But there is one problem. The include statement in the copied include file were no longer valid because the paths are different.

Next step: copy all headers from all project to the PublicInterfaces directory and replace all include statements with the new locations.

Thanks to a real long python script with some regex magic I was able to do that.

I also learned that the Windows filesystem (NTFS) has also the same limitation as the linux one, you can not have a file and a directory which have exactly the same name in the same directory. I’ve solved that problem by always prefer the directory, which works in my scenario.

Conclusion

If your build system support additional include directories, just use it. If you can’t, there is an option like presented in this post ๐Ÿ˜‰.