camomilla: C++ error simplification script
I’ve recently released a script on my GitHub page that simplifies C++ compiler error messages: camomilla
.
What does it do?
camomilla
uses simple text transformations to make gcc
and clang
errors smaller and easier to read. During the development of ecst
, a compile-time Entity-Component-System C++14 library developed for my BCS thesis, I encountered a lot of huge undeciphrable errors that sometimes completely filled my terminal buffer. Here’s an example:
Before:
After:
The reason for these enormous outputs is the fact that both gcc
and clang
completely expand all nested typename definitions in the context of the error.
Transformations
The main text transformation used by camomilla
to prevent full expansion of templates is “template typename collapsing”, which hides nested typenames up to a user-specified depth. Example:
echo "metavector<metatype<metawhatever<int>>>::method()" | camomilla -d0
# outputs
"metavector<?>::method()"
echo "metavector<metatype<metawhatever<int>>>::method()" | camomilla -d1
# outputs
"metavector<metatype<?>>::method()"
echo "metavector<metatype<metawhatever<int>>>::method()" | camomilla -d2
# outputs
"metavector<metatype<metawhatever<?>>>::method()"
echo "metavector<metatype<metawhatever<int>>>::method()" | camomilla -d3
# outputs
"metavector<metatype<metawhatever<int>>>::method()"
The two other current transformations offered by camomilla
are simple regex replacements that can act on namespaces or generic symbols. They can be defined in .json
configuration files (which can recursively include each other!) as follows:
{
// Add namespace replacements
"namespaceReplacements": [
"std": "",
"boost::hana": "bh",
"boost::fusion": "bf",
"boost::spirit": "bs",
],
// Add generic replacements
"genericReplacements" : [
"tuple": "tpl",
"forward": "fwd"
]
}
The configuration file above can be loaded and used as follows:
(Note: |&
pipes both stdout
and stderr
to camomilla
.)
Reprocessing
Ever felt like you were “debugging an error” when dealing with huge template-heavy compiler outputs? camomilla
helps with that by automatically caching the last processed original error, so that the user can play around with different transformations and options. Example:
# Let's compile this `Boost.Hana`-heavy project:
g++ ./bhtest.cpp |& camomilla
# Error output: huge list of nested `boost::hana::tuple`
# and `boost::hana::integral_constant` instances.
# No problem! Reprocess the last error with additional options.
# (Setting "template typename collapsing" depth to `0`)
camomilla -r -d0
# Too many typenames hidden away? Play with the depth:
camomilla -r -d1
camomilla -r -d2
camomilla -r -d3
# ...
Solution or workaround?
(From camomilla/README.md
.)
camomilla
is merely a workaround for the fact that compilers do not filter (either automatically or through flags) the depth of template typenames. Errors in projects making use of libraries such as boost::hana
or boost::fusion
therefore include a lot of “typename boilerplate” that can make the error harder to read.
Library developers are sometimes forced to make use of techniques to erase the long typenames in order to simplify the errors and decrease compilation time: boost::experimental::di
is an example.
I think this is something that should be addressed directly in the compilers - I’ve created a feature request/bug report both in the GCC Bug Tracker and in the Clang Bug Tracker.
Results
I currently pipe everything I compile on my machine to camomilla
- I find the reduced noise/boilerplate quite useful when constantly reading template-heavy errors (…pretty much all of my code is template-heavy). This is a table that shows the size reduction of some errors generated from a real project, ecst, by simply mispelling a member field name in a template-heavy context:
Bytes (original) | Bytes (after camomilla) | Relative size change | |
---|---|---|---|
g++ 6.1.1 | 38487 | 3680 | -90.43% |
clang++ 3.8.1 | 16856 | 2990 | -82.26% |
clang
usually does a much better job than gcc
in showing the source of the error and placing it at the top of the output, but the size reduction often means that mistakes are easier to pinpoint and track.
Using/hacking camomilla
You can get and install camomilla
by cloning the official GitHub repository and using the setup.py
script. Contributions are welcome - camomilla
is written as a single Python 3 script file. (I used Python instead of C++ because camomilla
is the “evolution” of an older poorly designed script that attempted to simplify errors for ecst
.)