Combining C++ header files

(Adapting an answer to my dupe question:)

There are several other libraries which aim for a single-header form of distribution, but are developed using multiple files; and they too need such a mechanism. For some (most?) it is opaque and not part of the distributed code. Luckily, there is at least one exception: Lyra, a command-line argument parsing library; it uses a Python-based include file fuser/joiner script, which you can find here.

The script is not well-documented, but they way you use it is with 3 command-line arguments:

  • --src-include - The include file to convert, i.e. to merge its include directives into its body. In your case it's libfoo.h which includes the other files.
  • --dst-include - The output file to write - the result of the merging.
  • --src-include-dir - The directory relative to which include files are specified (i.e. an "include search path" of one directory; the script doesn't support the complex mechanism of multiple include paths and search priorities which the C++ compiler offers)

The script acts recursively, so if file1.h includes another file under the --src-include-dir, that should be merged in as well.

Now, I could nitpick at the code of that script, but - hey, it works and it's FOSS - distributed with the Boost license.


If your library is so big that you cannot build and maintain a single wrapping header file like Kiril suggested, this may mean that it is not architectured well enough.

So if your library is really huge (above a million lines of source code), you might consider automating that, with tools like

  • GCC make dependency generator preprocessor options like -M -MD -MF etc, with another hand made script sorting them
  • expensive commercial static analysis tools like coverity
  • customizing a compiler thru plugins or (for GCC 4.6) MELT extensions

But I don't understand why you want an automated way of doing this. If the library is of reasonable size, you should understand it and be able to write and maintain a wrapping header by hand. Automating that task will take you some efforts (probably weeks, not minutes) so is worthwhile only for very large libraries.


A little bit late, but here it is. I just recently stumbled into this same problem myself and coded this solution: https://github.com/rpvelloso/oneheader

How does it works?

  1. Your project's folder is scanned for C/C++ headers and a list of headers found is created;

  2. For every header in the list it analyzes its #include directives and assemble a dependency graph in the following way:

    1. If the included header is not located inside the project's folder then it is ignored (e.g., if it is a system header);

    2. If the included header is located inside the project's folder then an edge is create in the dependency graph, linking the included header to the current header being analyzed;

  3. The dependency graph is topologically sorted to determine the correct order to concatenate the headers into a single file. If a cycle is found in the graph, the process is interrupted (i.e., if it is not a DAG);

Limitations:

  1. It currently only detects single line #include directives (e.g., #include );
  2. It does not handles headers with the same name in different paths;
  3. It only gives you a correct order to combine all the headers, you still need to concatenate them (maybe you want remove or modify some of them prior to merging).

Compiling:

g++ -Wall -ggdb -std=c++1y -lstdc++fs oneheader.cpp -o oneheader[.exe]

Usage:

./oneheader[.exe] project_folder/ > file_sequence.txt


As your comment says:

.. I want to make it easier for library users, so they can just do one single #include and have it all.

Then you could just spend some time, including all your headers in a "wrapper" header, in the right order. 50 headers are not that much. Just do something like:

// libfoo.h
#include "header1.h"
#include "header2.h"
// ..
#include "headerN.h"

This will not take that much time, if you do this manually.

Also, adding new headers later - a matter of seconds, to add them in this "wrapper header".

In my opinion, this is the most simple, clean and working solution.