Improvements to ADDITIONAL_CLEAN_FILES
I want the global clean
task to do a better job of actually removing the junk files that cmake plops onto my project tree during builds.
Two important use cases for fully cleaning all junk files include:
Reducing disk space associated with working on many cmake projects on my machine.
And resolving conflicts when the user runs cmake
on the same host project directory in WSL with apt cmake
, and again in PowerShell with Chocolatey cmake
. cmake absolutely hates seeing leftover files that target one or the other environment. Yet, cmake is not good about automatically removing these paths as part of its global clean
task.
I can add CMakeFiles
and other patterns to ADDITIONAL_CLEAN_FILES
. And in fact, the file patterns are successfully deleted (when make is the active sub-build tool). However, the basic UX for cmake cleaning still has many quirks:
When CMakeFiles
is appended to ADDITIONAL_CLEAN_FILES
, then the global clean
task exits non-zero and triggers spurious errors on make clean
: CMakeFiles/uninstall.dir/build.make: No such file or directory
The behavior with ninja is even worse. ninja clean
exits non-zero, and emits spurious errors error: loading 'build.ninja': No such file or directory
, when cmake insists on running ninja -t clean
after we instruct cmake to delete build.ninja
.
More concerning, cmake refuses to delete .ninja_log
, even when this file path is explicitly appended to ADDITIONAL_CLEAN_FILES
.
I suspect that cmake's order of operations unfortunately has been touching the .ninja_log
file after any ninja
tasks run, creating a paradox where it is never able to delete its own junk files.
ninja -t clean
and ninja -t clean -g
don't delete hardly any files mentioned in ADDITIONAL_CLEAN_FILES
at all, except for build.ninja
.
The word splitting behavior of paths in ADDITIONAL_CLEAN_FILES
does not permit whitespace. Which means no multiline strings allowed. Which means having to maintain a rather long string.
Neither cmake's internal junk files, nor make's, nor ninja's are included in the default clean files to remove on {make,ninja} clean
.
This is the boilerplate I am tinkering with in my CMakeLists.txt:
set_property(
DIRECTORY .
APPEND PROPERTY
ADDITIONAL_CLEAN_FILES
"${EXECUTABLE_OUTPUT_PATH};Makefile;build.ninja;.ninja_deps;Testing;CTestTestfile.cmake;CMakeCache.txt;cmake_install.cmake;conanbuildinfo.cmake;conanbuildinfo.txt;conaninfo.txt;graph_info.json;conan.lock;conanfile.txt"
)
I also tried reordering the paths in the ADDITIONAL_CLEAN_FILES string value, in case that might help to delete the .ninja_log
file.
I also tried cmake --build . --target clean
.
But no luck either way.
Can we please address more of these quirks with how cmake projects can be cleaned up?
I think it would help if cmake processed the global clean
task in a way that isolates it from the usual post-processing behaviors that cmake executes for other tasks. That way, fewer things will fail during cleanup.
One workaround involves never using ninja. But that can dramatically slow down software builds for large C/C++ projects.
One workaround involves manual rm -rf
... commands. Though scripting them in a portable way that works on Command Prompt just as well as bash, is rather difficult. No, I don't want to have to run batsh commands as part of my development process.
Another workaround involves running cmake exclusively in Docker containers. But it's generally not a good idea to preclude host-native development.
As a workaround, I wrote an entire build system just to wrap cmake and offer better cleaning semantics: https://github.com/mcandre/rez