Sorry in advance that this is pretty vague, but wanted to bring it up before 3.21.0 gets officially released. I’ve noticed lately that it seems like various built-in commands are not halting when they encounter fatal errors. They report an error and I’d expect processing to halt immediately, but it continues. Maybe it’s always been like that and I just happen to be a bit more tuned into it lately, but it feels like it’s happening much more often than I recall noticing before.
Thought I’d mention it now in case it jogs someone’s memory for a change new in 3.21. If I can provide some clearer examples in the coming days, I will try to do so.
This is not for message() commands, it’s for other ordinary commands that catch and report fatal errors internally. No I don’t have examples at the moment, but as mentioned, I’ll add some here if I can in the next few days.
I’ve had a chance to try some things out. Looks like this is not new for CMake 3.21 and has always been like this for lots of things I would have expected to halt processing. An example showing the sort of things I’m talking about:
cmake_minimum_required(VERSION 3.8)
project(fatalerrors)
# Should halt processing but doesn't
add_subdirectory(does_not_exist)
add_executable(MyApp main.cpp)
get_target_property(var MyApp) # Fatal error, but processing continues
# Should halt processing but doesn't
install(TARGETS targetNotDefined)
# Should halt processing but doesn't
target_compile_definitions(targetStillNotDefined PRIVATE Blah)
message("Should not see this message, it is after fatal errors")
From another point of view, halting processing at the first error is a bit painful when you are writing CMakeLists.txt files: It requires a lot of cycles of edition/run to fix all errors!
For example, a c/c++ compiler does not work like this: When you compile a file with multiple errors, the compiler try to achieve the compilation of the file (if possible) and show multiple errors… So you can fix all the errors at once before launching a new compilation!
Maybe the right solution is to introduce a cmake option (like --stop-on-error) to control the behavior of processing: stop or continue on fatal error…
Yeah, but from my experience that only (sometimes) helps in understanding the first error and does not help fixing multiple problems. That’s because typically the first error is real and the next few pages of errors will disappear once I fix the first problem.
In writing the responses below, I feel like I’ve brought at least some of these points up before, but I could only find issues which relate to the message() command, which is different but has some overlapping discussions:
CMake is different to a compiler, it caches things between runs. If you don’t stop on the first error, the code that follows it might make a wrong decision and cache that wrong result. Then, even after you fix the error, the cached wrong result is kept. This is something I would expect most users to overlook, especially in big, complex projects.
CMake is already inconsistent in when it stops immediately and when it doesn’t. For example, a find_package(Blah REQUIRED) will halt immediately if it doesn’t find the requested package. I ended up starting this discussion because I kept seeing CMake continue processing way past errors in large, complex projects. In some cases, there is a lot of configure output and just finding the error is a pain. I am finding CMake’s current lack of consistency and the commands that allow processing to continue to be a much more common problem than wishing I could have processing continue past a given error. I think it should be consistent and always halt. If you really want to allow execution to go past that, I’d say maybe add an option for that rather than requiring an option to make it halt on first error.
We don’t even have to worry about a policy here, since we are talking about fatal errors. Any affected behavior is already resulting in a non-functional project, so we don’t have to preserve the current behavior.
Regarding differences of CMake and compilers, I think it is an erroneous behavior to keep the cache if the configuration step is not successful. It seems more reasonable to invalidate the cache if some error is detected during CMake processing.
Now, I am OK to enforce stop on error as standard behavior and add an option to override it (i.e. --continue-on-error).
Some things are fine to cache (e.g., I wouldn’t want CMake to redetect the compiler just because I made a typo in some CMake file). I think FATAL_ERROR is safer than SEND_ERROR in general, but the latter still has uses. I only see a few uses of SEND_ERROR in VTK and they seem to be detecting errors that don’t cause problems immediately (like, say how list(GET lst not_an_index out) can only poison out) and instead are diagnostics for “this looks fishy, but you’re probably OK to continue going”. FWIW, FindPython uses SEND_ERROR for potentially missed component suggestions which seems fine as it’d be a linker error later, but it’s not going to interfere with (most) any subsequent CMake processing of the situation. This also seems like an OK use of SEND_ERROR to me.