Issue
I have a C++ project that I build using GCC and CMake.
Generally I like to compile with -fmax-errors=1
. My normal workflow is to fix the first error and then rebuild since subsequent errors are often caused by the first one.
But unfortunately, with C++20, an error involving a constraint failure is often treated as multiple "errors" by GCC. In order to see why the constraint failed, I need to see more than one error.
So occasionally I like to set -fmax-errors
to a higher number, probably 2
, when such an error occurs.
But changing the compiler flags (by manually changing CMakeLists.txt
or passing a cache variable to cmake
on the command line) invalidates the CMake cache and makes the build start from scratch.
This behavior generally makes sense of course; arbitrary configuration changes could require a rebuild. But we humans understand that changing the compiler's error-formatting behavior doesn't require a rebuild. Is there a way of expressing this distinction to CMake?
Or, failing that, is there a clever way of working around this? I thought of having CMake read an environment variable at the time when the compiler is invoked (not at the time when cmake
is run), but I can't find any documentation suggesting that this is actually possible.
(I could probably create a script that forwards most of its arguments to g++
but also adds -fmax-errors="$MY_COOL_ENV_VARIABLE"
and then tell CMake that the script in question is the C++ compiler to build with, but I imagine that this might violate some of CMake's expectations about the "compiler.")
Solution
At the advice of Marc Glisse, I gave the approach that I hypothesized in parentheses at the end of the question a try. This in fact works quite well.
I now have a Python script called invoke_compiler.py
in the top-level directory of my project. I point CMake to the script in the usual way in which one specifies a C++ compiler.
set(CMAKE_CXX_COMPILER ${PROJECT_SOURCE_DIR}/invoke_compiler.py)
Now I was actually a bit terse in the question for the sake of exposition. In actuality I regularly build this project with both GCC and Clang. So I want to be able to specify the C++ compiler to CMake when I invoke cmake
.
cmake my-src-dir -DCMAKE_CXX_COMPILER=g++
So invoke_compiler.py
has to take a few extra command-line flags, --my-project-cxx-compiler
and --my-project-num-errors-flag
.
Then the script invokes the compiler (whose executable is the one specified by --my-project-cxx-compiler
), forwarding all of its command-line arguments except the extra ones mentioned above and adding f"{num_errors_flag}={os.environ.get('MY_PROJECT_NUM_ERRORS', 1)}"
. (The name of the compiler flag specifying the number of errors to display must itself be passed as an argument to the script because GCC and Clang call the flag --fmax-errors
and --ferror-limit
respectively.)
The trick is simply that the logic in CMakeLists.txt
that determines which arguments to pass to invoke_compiler.py
needs to execute before CMAKE_CXX_COMPILER
is overwritten.
The user just interacts with CMake as usual and changes the value of the MY_PROJECT_NUM_ERRORS
variable at any time in order to get a different number of errors from the compiler.
Answered By - Sam Marinelli Answer Checked By - Katrina (WPSolving Volunteer)