cpp-amalgamate recursively combines C++ source files and the headers they include into a single output file. It tracks which headers have been included and skips any further references to them. Which includes are inlined and which are left as is can be precisely controlled.
It originated as an automated way to inline pre-written snippets when submitting to competitive programming sites such as Codeforces or AtCoder. Since then, it has been generalized and might be useful in other contexts as well.
When provided with one or more source files and accompanying search directories for includes,
cpp-amalgamate will concatenate the source files and recursively inline all include statements it
can resolve using the given search directories (or from the current directory, for
#include "..."
). While, by default, all resolvable includes are inlined, this can be controlled
using the --filter*
family of options. It can also insert corresponding #line num "file"
directives which allows compilers or debuggers to resolve lines in the combined file back to their
origin.
However, cpp-amalgamate does not interpret preprocessor instructions beyond #include
. This notably
means that it cannot understand traditional header guards using #if
instructions. Instead,
cpp-amalgamate assumes that every header should be included at most once, as if it was guarded by a
header guard or #pragma once
. It does detect #pragma once
instructions and removes them, as
these cause warnings or errors when compiling the combined file with some compilers.
This simplified behavior also might cause problems if #include
statements themselves are inside
#if
blocks. If the same header is referenced inside two separate #if
blocks, it will only be
expanded in the former while the latter #include
will be removed.
The basic invocation for cpp-amalgamate is
cpp-amalgamate [options] source-files...
To specify search directories, use -d
/--dir
. You can also use --dir-quote
or --dir-system
for search directories that should only be used for quote (i.e., #include "..."
) or system
includes (i.e., #include <...>
). Note that cpp-amalgamate does not use any search directories by
default!
Using -f
/--filter
, you can specify globs for includes that should not be inlined. As with search
directories, --filter-quote
and --filter-system
are versions only applicable to one type of
include. Globs can be inverted with a leading !
, causing matching headers to be inlined even if a
previous glob excluded them. Globs are evaluated in order, with the last matching glob determining
whether a header is included or not. By default (i.e., if no glob matches), all headers are inlined.
Note that these globs are applied to the absolute path of the header with all symbolic links
resolved. This means that often a **
fragment will be necessary, which matches any number of path
entries. That is,
**
matches any file,**/*.hpp
all files with the extension.hpp
,- and
/usr/local/include/**
all files in/usr/local/include
.
For the full details on the supported syntax, check the globset documentation.
Other flags supported by cpp-amalgamate are:
-o
/--output
: Write the combined source file to a file rather than the standard output.--line-directives
: Add#line num "file"
directives to the output, allowing compilers and debuggers to resolve lines to their original files.-v
/--verbose
and-q
/--quiet
: Increase or decrease the level of log messages shown. By default, only warnings and errors are shown.--unresolvable-include
: Specifies what is done when an include cannot be resolved. Possible values areerror
,warn
, andignore
, with the latter being the default. This can be useful to assert that all includes end up inlined Also available as--unresolvable-quote-include
and--unresolvable-system-include
.--cyclic-include
: Specifies how a cyclic include is handled. Supports the same values as--unresolvable-include
except witherror
as the default.
Each GitHub release contains precompiled binaries for most common operating systems/architectures. Alternatively, cpp-amalgamate can be installed using cargo which is bundled with Rust:
cargo install cpp-amalgamate