Camomilla: Simplifying C++ Compiler Errors

man

Camomilla is a script designed to simplify error messages produced by GCC and Clang, making them more readable and manageable. It achieves this by applying text transformations to reduce the verbosity of template-heavy errors, which can often overwhelm the terminal buffer.

During the development of ecst, a C++14 compile-time Entity-Component-System library for my BCS thesis, I frequently encountered massive, unreadable compiler errors. Camomilla helps by condensing these errors into a more digestible format.

Example:

Before using Camomilla:

g++: before camomilla

After using Camomilla:

g++: after camomilla

How Does It Work?

One of the key transformations performed by Camomilla is template typename collapsing, which limits the expansion of nested template types up to a user-defined depth.

Example:

echo "metavector<metatype<metawhatever<int>>>::method()" | camomilla -d0
# Output: "metavector<?>::method()"

echo "metavector<metatype<metawhatever<int>>>::method()" | camomilla -d1
# Output: "metavector<metatype<?>>::method()"

echo "metavector<metatype<metawhatever<int>>>::method()" | camomilla -d2
# Output: "metavector<metatype<metawhatever<?>>>::method()"

echo "metavector<metatype<metawhatever<int>>>::method()" | camomilla -d3
# Output: "metavector<metatype<metawhatever<int>>>::method()"

Additional Transformations

Camomilla also supports custom regex-based replacements for namespaces and generic symbols. These replacements are defined in JSON configuration files, which can be recursively included.

Example Configuration:

{
    "namespaceReplacements": {
        "std": "",
        "boost::hana": "bh",
        "boost::fusion": "bf",
        "boost::spirit": "bs"
    },
    "genericReplacements": {
        "tuple": "tpl",
        "forward": "fwd"
    }
}

To use this configuration:

g++ ./file.cpp |& camomilla -c ./config.json

(Note: |& redirects both stdout and stderr to Camomilla.)

Error Reprocessing

Dealing with complex errors often requires iterative refinement. Camomilla caches the last processed error, allowing users to tweak transformations without recompiling.

Example:

g++ ./bhtest.cpp |& camomilla  # Initial compilation with error output
camomilla -r -d0  # Reprocess the last error with template depth 0
camomilla -r -d1  # Adjust depth as needed
camomilla -r -d2
camomilla -r -d3

Solution or Workaround?

Camomilla acts as a workaround for compilers’ lack of built-in filtering options for template depth in error messages. Libraries such as boost::hana or boost::fusion often produce deeply nested template errors, making debugging a challenge.

Some libraries mitigate this issue by employing techniques to shorten template names and reduce compilation time (e.g., boost::experimental::di). However, this is something that should ideally be addressed at the compiler level. I have submitted feature requests to both the GCC and Clang bug trackers.

Results

Using Camomilla significantly reduces error message size, making mistakes easier to identify. Here are some real-world results from misnaming a field in a template-heavy context within ecst:

CompilerOriginal Error Size (Bytes)After Camomilla (Bytes)Reduction (%)
g++ 6.1.138,4873,680-90.43%
clang++ 3.8.116,8562,990-82.26%

Clang generally presents errors more concisely than GCC, but Camomilla’s transformations still provide significant improvements in readability.

Installation and Contribution

Camomilla is available on GitHub. You can install it by cloning the repository and running the setup.py script. Contributions are welcome! The script is written in Python 3 for ease of modification, evolving from an earlier, less structured version used during the development of ecst.


Camomilla is a simple yet effective tool for C++ developers working with template-heavy code, helping to make compiler errors more manageable and debugging more efficient.