寻找一个“cmake clean”命令来清除CMake输出。

616

就像make clean会删除Makefile生成的所有文件一样,我希望在CMake中也能做到同样的事情。经常需要手动浏览目录并删除类似cmake_install.cmakeCMakeCache.txtCMakeFiles等文件。

是否有像cmake clean这样的命令可以自动删除所有这些文件?理想情况下,这应该遵循当前目录下的CMakeLists.txt文件定义的递归结构。


5
针对 CMake 3.0 及更高版本的用户,您可以使用命令 cmake --build <build-dir> --target clean 来清除构建目录。 - Sean Francis N. Ballais
26个回答

692

CMake 3.X

CMake 3.X提供了一个'clean'目标。

cmake --build C:/foo/build/ --target clean

来自CMake 3.0.2文档:

--clean-first  = Build target 'clean' first, then build.
                 (To clean only, use --target 'clean'.)

CMake 2.X

CMake版本2.X中没有cmake clean命令。

通常我将项目构建在一个名为"build"的文件夹中。所以如果我想要执行make clean,我可以直接运行rm -rf build命令。

在与根目录下的"CMakeLists.txt"相同的文件夹中创建一个名为"build"的文件夹通常是不错的选择。要构建您的项目,只需将CMakeLists.txt的位置作为参数传递给cmake。例如:cd <location-of-cmakelists>/build && cmake ..。(来自@ComicSansMS)


133
这被称为“源外构建”,应该是首选的方法。它避免了名称冲突等问题。 - arne
25
支持源外编译是个好习惯,特别是在构建多种架构时更为重要。例如,如果使用源内编译,则无法同时生成64位和32位二进制文件,因为需要两个不同的CMake缓存层级结构。 - ComicSansMS
9
你可以把文件夹放在任何地方,但通常将生成的文件夹放在与源代码根目录下的CMakeLists.txt文件相同的目录中是一个不错的选择。构建时,只需将CMakeLists.txt文件所在的位置作为参数传递给cmake即可。例如:cd <cmakelists的位置>/build && cmake .. - ComicSansMS
86
确实应该有一个cmake clean命令。即使是习惯于在源代码目录以外进行构建的人,也曾经不小心在错误的目录中运行了cmake,手动清理非常麻烦。 - pavon
31
但是反过来并不成立;一个文件不在版本控制下并不意味着它是由CMake生成的且可以被安全删除。挑选哪些未进行版本控制的文件是正在处理的工作,需要保留哪些以及哪些是CMake冗余文件是很麻烦的,特别是当许多CMake文件是复制或类似命名的时候。 - pavon
显示剩余19条评论

115

在 Git 遍地的今天,你可能会忘记 CMake,并使用 git clean -d -f -x 命令,它可以删除所有不在源代码控制下的文件。


28
那个 -x 选项真的很妙。这是 git 行业的一个绝妙技巧。尽管我个人仍然会先运行一次干假操作,即 git clean -d -f -x -n。偶尔我会在受 git 控制的项目文件夹中添加一个方便文件,但这不是我想与他人分享的东西,所以我不会将其通过 git add 添加到项目中。如果我没有小心地添加 -e <pattern> 选项,它就会将那种类型的文件删除。顺便说一下,如果 git.gitcleanignore 文件就好了 :) 。 - CivFan
3
@CivFan 你可以尝试使用chattr +i $filename命令(需要root权限),这样即使像rm -f一样被执行,git也无法删除该文件。请注意,此操作将禁止修改该文件。 - Ruslan
4
假设是在源代码文件中进行构建,这本身应该被避免。 - Slava
4
那么对于用户忘记git add的新添加文件怎么办呢? - yugr
1
很好的回答;您能否请包括组合标志参数的概念?例如:git clean -dfx。这也依赖于一个良好的 .gitignore 文件。 - Seth
显示剩余5条评论

93

CMake官方FAQ指出:

使用GNU autotools创建的某些构建树具有“make distclean”目标,该目标会清理构建,并删除Makefiles和其他生成的构建系统的部分。 CMake不生成“make distclean”目标,因为CMakeLists.txt文件可以运行脚本和任意命令;CMake无法跟踪到确切哪些文件作为运行CMake的一部分而生成。提供distclean目标将使用户误以为它能够按预期工作。 (CMake生成一个“make clean”目标以移除由编译器和链接器生成的文件。)

只有用户执行源内构建时才需要“make distclean”目标。 CMake支持源内构建,但我们强烈建议用户采用源外构建的概念。使用与源码树分开的构建树将防止CMake在源码树中生成任何文件。因为CMake不更改源代码树,所以没有必要进行distclean。您可以通过删除构建树或创建单独的构建树来开始新的构建。


4
最初,由GNU Autotools引入和使用的“distclean”目标旨在使源代码树准备好打包并创建tar分发。这样,用户可以下载tar文件并解压缩,在不需要Autotools(aclocal、automake、autoconf等)的情况下运行“configure”和“make”。如果我们推广到CMake,则“make distclean”将留下一个干净的源代码,可以在没有安装CMake的情况下构建。但是,如果生成器是单目标生成器(如“make”目标),则这种方法无法正常工作,因为使用CMake进行配置时会发生以下事情: - Carlo Wood
1
运行cmake。制作一个无法配置、甚至不进行平台测试等的分发是没有用的。因此,cmake不存在“distclean”目标。cmake 必须存在于最终用户的计算机上。 - Carlo Wood
9
我们强烈鼓励用户采用源外构建的概念,但可惜他们将其设置为默认行为。 (说真的,让默认行为成为您不希望用户执行的操作是一个愚蠢的设计决策。) - BrainSlugs83

60

我 Google 了半个小时,唯一有用的东西是调用 find 实用程序:

# Find and then delete all files under current directory (.) that:
#  1. contains "cmake" (case-&insensitive) in its path (wholename)
#  2. name is not CMakeLists.txt
find . -iwholename '*cmake*' -not -name CMakeLists.txt -delete

此外,在此之前一定要调用make clean(或者您正在使用的任何CMake生成器)

:)


39
如果您正在使用版本控制,我建议不要采用这种方法:当我尝试在svn中使用此方法时,它会删除一些存储库的工作文件。 - bcumming
11
可能还有其他与 cmake 匹配的文件,所以这并不是一种通用的方法。这样做应该可以:rm -rf CMakeFiles;rm -rf CMakeCache.txt;rm -rf cmake_install.cmake; - honza_p
4
由于此命令可能会删除一些用户文件,所以我已将其投下反对票。我更喜欢 honza_p 的命令,它不仅更简单、风险更小,而且长度也并不比这个命令长。 - Adrien Descamps
3
@AdrienDescamps:除了它仍然在子目录中留下与CMake相关的垃圾。我执行了rm -rf CMakeFiles ; rm -rf */CMakeFiles ; rm -rf */*/CMakeFiles ; rm -rf */*/*/CMakeFiles,但还没有完成... - SF.
1
如果有人在我的源代码树中执行此命令,我会开枪打他们。 - Erki Aring
显示剩余5条评论

41
您可以使用类似以下的方法:
add_custom_target(clean-cmake-files
   COMMAND ${CMAKE_COMMAND} -P clean-all.cmake
)

// clean-all.cmake
set(cmake_generated ${CMAKE_BINARY_DIR}/CMakeCache.txt
                    ${CMAKE_BINARY_DIR}/cmake_install.cmake
                    ${CMAKE_BINARY_DIR}/Makefile
                    ${CMAKE_BINARY_DIR}/CMakeFiles
)

foreach(file ${cmake_generated})

  if (EXISTS ${file})
     file(REMOVE_RECURSE ${file})
  endif()

endforeach(file)

我通常会创建一个“make clean-all”命令,在之前的示例中添加一个调用“make clean”的命令。
add_custom_target(clean-all
   COMMAND ${CMAKE_BUILD_TOOL} clean
   COMMAND ${CMAKE_COMMAND} -P clean-all.cmake
)

不要尝试将"clean"目标作为依赖项添加:

add_custom_target(clean-all
   COMMAND ${CMAKE_COMMAND} -P clean-all.cmake
   DEPENDS clean
)

因为“clean”不是CMake中的真正目标,所以这样做不起作用。

此外,您不应将“clean-cmake-files”用作任何东西的依赖项:

add_custom_target(clean-all
   COMMAND ${CMAKE_BUILD_TOOL} clean
   DEPENDS clean-cmake-files
)

因为,如果你这样做,在执行clean-all命令完成之前,所有的CMake文件都将被删除,然后make会搜索"CMakeFiles/clean-all.dir/build.make"并抛出一个错误。因此,在任何情况下,“任何东西”之前都不能使用clean-all命令:

add_custom_target(clean-all
   COMMAND ${CMAKE_BUILD_TOOL} clean
   COMMAND ${CMAKE_COMMAND} -P clean-all.cmake
)

那也不行。


有没有一种方法可以自动填充 cmake_generated?或许,可以将其与 yuri.makarevich 的答案相结合?目前,这不会删除 ${CMAKE_BINARY_DIR} 子目录中的文件。 - foxcub
不适用于Ninja或Visual Studio。我不建议这样的方法。 - usr1234567
不错的想法,但这并没有删除CMakeCache.txt,也没有帮助我,但我找到了这种类似的方法来更新每个构建中的变量,因此无需删除CMakeCache.txt:https://dev59.com/m1QJ5IYBdhLWcg3wwYv7#53159688 - Celuk

38

对我来说,简单地执行rm CMakeCache.txt也可以解决问题。


1
只有在CMakeCache.txt中删除相关变量对我也起作用。 - Yorkwar
2
@nenchev 你需要再次运行 cmake /build-path - Samaursa
1
@Samaursa cmake --build 在需要时重新运行 cmake,这种方法会破坏构建目录并导致 cmake 报错。我的下面的回答告诉你删除 CMakeFiles/ 目录,这将导致进行干净的重建并自动重新运行 cmake。 - nenchev
2
@nenchev 我明白你的意思,我同意。 - Samaursa
如果您在不同的子目录中有多个缓存,则不能这样做。 - avans
显示剩余4条评论

24

CMake 3.24 开始,存在一个名为 --fresh 的命令行选项,它会在每次构建时重建整个构建树:

--fresh

版本 3.24 中新增。

对构建树执行新的配置。这将删除任何现有的 CMakeCache.txt 文件和相关的 CMakeFiles/ 目录,并从头开始重新创建它们。

https://cmake.org/cmake/help/latest/manual/cmake.1.html#options


这还远远不足以删除典型CMake项目生成的所有不同垃圾文件。 - mcandre
@mcandre 不,它并不会影响,但这也无关紧要。构建树将被重新生成,包括缓存。因此,构建输出应该不受垃圾文件的影响,无论这些文件是否存在。 - SkryptX

19

也许有点过时,但既然你在谷歌搜索cmake clean时看到了这篇文章,那我会补充一下:

由于您可以使用以下命令在构建目录中启动带有指定目标的构建:

cmake --build . --target xyz

当然,您也可以运行以下命令:

cmake --build . --target clean

以在生成的构建文件中运行clean目标。


9

我认为,离线源码构建是最佳答案。但对于必须进行源代码内构建的情况,我编写了一段Python脚本,可在此处下载,该脚本:

  1. 运行 "make clean"
  2. 删除顶级目录中特定的CMake生成文件,如CMakeCache.txt。
  3. 对于每个包含CMakeFiles目录的子目录,删除CMakeFiles、Makefile和cmake_install.cmake。
  4. 删除所有空的子目录。

谢谢。我想在你的脚本中添加一行代码,以便在之前进行清理时(即使没有Makefile),可以使此脚本成为幂等性。只需在第24行之前添加以下行(正确缩进):if os.path.isfile(os.path.join(directory,'Makefile')):,当然还要缩进刚刚添加的行后面的函数体的其余部分。这将仅在当前正在清理的目录中存在Makefile时执行make ... clean。否则,该脚本是完美的! - Michael Goldshteyn
但是,有时您确实必须进行源内构建。但这些时间到底是什么时候呢?我希望这些情况如今已经很少见了,每当遇到这种情况时,您都会向维护者提交错误报告,要求他们修复其构建工具。任何使用CMake的项目至少需要支持源外构建,否则它们的代码在使用ExternalProject(需要BUILD_IN_SOURCE,意味着隐含的祭品)时就会很繁琐,并且我甚至不确定使用FetchContent是否可能,因为它没有类似的选项。 - FeRD

8

这个问题引起了很多关注和复杂的解决方案,实际上这表明没有一种干净的方法来使用cmake。

你可以在工作目录下执行cd build_work,然后当需要清理时,执行rm -rf *。然而,rm -rf *是一个危险的命令,因为许多人经常不知道他们在哪个目录下。

如果你执行cd ..rm -rf build_work,然后mkdir build_work,接着再执行cd build_work,那就太麻烦了。

因此一个好的解决方法是保持在源文件目录之外,并告诉cmake路径:
配置: cmake -B build_work
构建: cmake --build build_work
安装: cmake --install build_work
清理: rm -rf build_work
重新创建build文件夹:甚至不需要mkdir build_work,只需用cmake -B build_work来配置它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接