ChatGPT解决这个技术问题 Extra ChatGPT

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

正如 make clean 删除 makefile 生成的所有文件一样,我想对 CMake 做同样的事情。我经常发现自己手动浏览删除 cmake_install.cmakeCMakeCache.txt 等文件的目录以及 CMakeFiles 文件夹。

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

对于 CMake 3.0 及更高版本的用户,您可以使用 cmake --build <build-dir> --target clean

z
zsxwing

CMake 3.X

CMake 3.X 提供了一个“干净”的目标。

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

来自 3.0.2 的 CMake 文档:

--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)


这被称为“out of source build”,应该是首选的方式。它避免了名称冲突等
+1 用于源外构建。这在构建多个架构时变得至关重要。例如,您不能使用源内构建同时构建 64 位和 32 位二进制文件,因为这需要两个单独的 CMake 缓存层次结构。
您可以将文件夹放置在您想要的任何位置,但是在根 CMakeLists.txt 所在目录中的构建文件夹通常是一个不错的选择。要构建,您只需将 CMakeLists.txt 的位置作为参数提供给 cmake。例如:cd <location-of-cmakelists>/build && cmake ..
真的应该有一个cmake clean。每个曾经使用过 cmake 的人,即使他们习惯于进行源代码构建,也会不小心在错误的目录中运行 cmake,手动清理是一件非常痛苦的事情。
@DevSolar 但反之则不然;仅仅因为文件不受版本控制并不意味着它是由 cmake 生成的并且可以安全地删除。挑选出哪些未版本化的文件正在进行中,您需要保留哪些文件是 cmake cruft 是一件痛苦的事情,尤其是当许多 cmake 文件是副本/与您的文件类似命名时。
C
Community

CMake official FAQ 指出:

一些使用 GNU 自动工具创建的构建树有一个“make distclean”目标,用于清理构建并删除 Makefile 和生成的构建系统的其他部分。 CMake 不会生成“make distclean”目标,因为 CMakeLists.txt 文件可以运行脚本和任意命令; CMake 无法准确跟踪作为运行 CMake 的一部分生成的文件。提供 distclean 目标会给用户一种错误的印象,即它会按预期工作。 (CMake 确实会生成一个“make clean”目标来删除编译器和链接器生成的文件。)只有当用户执行源内构建时,才需要“make distclean”目标。 CMake 支持源内构建,但我们强烈鼓励用户采用源外构建的概念。使用与源代码树分离的构建树将阻止 CMake 在源代码树中生成任何文件。因为 CMake 不会更改源代码树,所以不需要 distclean 目标。可以通过删除构建树或创建单独的构建树来开始新的构建。


最初,正如 GNU autotools 引入和使用的那样,“distclean”目标旨在使源代码树准备好 tar 并创建 tar 分发。这样的 tar 文件用户可以下载和解压缩,然后运行“配置”和“制作”而不需要自动工具(aclocal、automake、autoconf 等)如果我们将其推断为 cmake,那么“make distclean”将为我们留下一个干净无需安装 cmake 即可构建的源代码。但是,当生成器是单目标生成器时(就像“make”目标一样),这不起作用,因为使用 cmake 的配置发生在
...运行cmake。制作一个无法配置的发行版,甚至不做平台测试等,都是没用的。因此,cmake 不存在“distclean”目标。 cmake 需要存在于最终用户的机器上。
we strongly encourage users to adopt the notion of an out-of-source build - 可惜他们当时将其设为默认行为。 (说真的,让默认行为成为你不鼓励用户做的事情是一个愚蠢的设计决定。)
P
Peter Mortensen

在 Git 无处不在的这些日子里,您可能会忘记 CMake 并使用 git clean -d -f -x,这将删除所有不受源代码控制的文件。


但是那个 -x 选项。这是 git 交易的绝妙伎俩。虽然我个人仍然会先进行试运行,git clean -d -f -x -n。每隔一段时间,我都会将用于项目的便利文件保存在项目文件夹中,并在 git 控制下,但我不想与其他人共享它,因此我不会将它git add 用于项目。如果我不小心添加了一个 -e <pattern> 选项,就会把这种文件吹走。在这方面,如果 git 有一个 .gitcleanignore 文件会很好。 :)
@CivFan 您可以尝试使用 chattr +i $filename (需要root权限,此后不允许修改文件)。这样 git 将无法删除该文件,即使它尝试像 rm -f 那样执行它。
这假设源内构建,这本身就是要避免的。
嗯,但是用户忘记了 git add 的新添加文件呢?
很好的答案;你能包括组合标志参数的概念吗?即git clean -dfx。这也依赖于一个好的 .gitignore btw
P
Peter Mortensen

我用谷歌搜索了大约半个小时,我想出的唯一有用的东西是调用 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 生成器)。

:)


如果您正在使用的目录受版本控制,我建议不要使用这种方法:当我使用 svn 尝试这种方法时,它删除了一些存储库工作文件。
可能还有其他文件与 cmake 匹配,所以这确实不是一种通用方法。这应该这样做: rm -rf CMakeFiles; rm -rf CMakeCache.txt; rm -rf cmake_install.cmake;
我会删除 -exec rm -rf {} \+ 并只使用 -delete。
否决,因为此命令可能会删除一些用户文件。我确实更喜欢 honza_p 命令,而不是更长、更简单、风险更低的命令。
@AdrienDescamps:除了它仍然在子目录中留下与 cmake 相关的垃圾。我正在做rm -rf CMakeFiles ; rm -rf */CMakeFiles ; rm -rf */*/CMakeFiles ; rm -rf */*/*/CMakeFiles,但还没有完成......
P
Peter Mortensen

你可以使用类似的东西:

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
)

不要尝试将“干净”目标添加为依赖项:

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

因为“干净”不是 CMake 中的真正目标,这不起作用。

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

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

因为,如果你这样做,所有 CMake 文件将在 clean-all 完成之前被删除,并且 make 会在搜索“CMakeFiles/clean-all.dir/build.make”时抛出错误。因此,在任何情况下,您都不能在“anything”之前使用 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} 的子目录中的文件。
不适用于 Ninja 或 Visual Studio。我不会推荐这种方法。
好主意,但这不会删除 CMakeCache.txt 也对我没有帮助,但我发现这种类似的方法可以在每次构建中更新变量,因此无需删除 CMakeCache.txtstackoverflow.com/questions/53159371/…
u
user1480788

简单地发出 rm CMakeCache.txt 也适用于我。


仅删除 CMakeCache.txt 中的相关变量也适用于我。
删除 CMakeCache.txt 然后运行“cmake --build /build-path”会导致“错误:无法加载缓存”。
@nenchev 您需要再次运行 cmake /build-path
@Samaursa cmake --build 在需要时重新运行 cmake,此方法会破坏构建目录并且 cmake 会抱怨。我的回答进一步告诉您删除 CMakeFiles/ 目录,这会导致干净的重建和 cmake 自动重新运行。
@nenchev 我明白你的意思,我同意。
r
redleg

也许它有点过时了,但由于这是您在谷歌 cmake clean 时的第一次点击,我将添加以下内容:

由于您可以使用指定的目标在构建目录中启动构建

cmake --build . --target xyz

你当然可以跑

cmake --build . --target clean

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


P
Peter Mortensen

我同意外源构建是最好的答案。但是在您必须进行源代码构建的时候,我编写了一个可用的 Python 脚本 here,它:

运行“make clean” 删除顶层目录中特定的 CMake 生成文件,例如 CMakeCache.txt 对于每个包含 CMakeFiles 目录的子目录,它会删除 CMakeFiles、Makefile、cmake_install.cmake。删除所有空子目录。


感谢那。我想在您的脚本中添加一行,当由于先前的清理(即,使该脚本具有幂等性)而没有出现 Makefile 时,该行使 make 静音。只需在第 24 行之前添加行(适当间隔):if os.path.isfile(os.path.join(directory,'Makefile')):args = [,当然在刚刚添加的行之后缩进函数体的其余部分。仅当正在清理的当前目录中存在 Makefile 时,才会执行 make ... clean。否则,脚本是完美的!
“但是对于那些你必须进行源内构建的时代” 究竟是什么时候呢?我希望这些天它们很少而且相距甚远,并且每当你遇到一个时,你都会向维护人员提交一个错误,要求他们修复他们的构建工具。至少,任何使用 CMake 的项目都需要支持外源构建,否则它们的代码与 ExternalProject 一起使用是一件苦差事(需要 BUILD_IN_SOURCE,隐含山羊牺牲),我什至不确定它是否可以使用 FetchContent,因为它缺少类似的选项。
f
frank

有趣的是,这个问题得到了如此多的关注和复杂的解决方案,这确实表明没有使用 cmake 的干净方法很痛苦。

好吧,您绝对可以cd build_work 做您的工作,然后在您需要清洁时做一个rm -rf *。但是,rm -rf * 是一个危险的命令,因为许多人通常不知道他们在哪个目录中。

如果您依次是 cd ..rm -rf build_workmkdir build_workcd build_work,那就是输入过多。

所以一个好的解决方案是离开构建文件夹并告诉 cmake 路径:
配置:cmake -B build_work
构建:cmake --build build_work
安装:cmake --install build_work
到clean:rm -rf build_work
重新创建构建文件夹:您甚至不需要 mkdir build_work,只需使用 cmake -B build_work 配置它。


P
Peter Mortensen

如果您在生成构建文件时将 -D 参数传递到 CMake 并且不想删除整个 build/ 目录:

只需删除构建目录中的 CMakeFiles/ 目录即可。

rm -rf CMakeFiles/
cmake --build .

这会导致 CMake 重新运行,并重新生成构建系统文件。您的构建也将从头开始。


那还不够。 CMakeCache.txt 也必须被删除(就像找到的库一样)。
P
Peter Mortensen

当然,源代码外构建是 Unix Makefiles 的首选方法,但如果您使用另一个生成器,例如 Eclipse CDT,它更喜欢您构建源代码。在这种情况下,您需要手动清除 CMake 文件。尝试这个:

find . -name 'CMakeCache.txt' -o -name '*.cmake' -o -name 'Makefile' -o -name 'CMakeFiles' -exec rm -rf {} +

或者,如果您使用 shopt -s globstar 启用了 globstar,请尝试使用这种不那么恶心的方法:

rm -rf **/CMakeCache.txt **/*.cmake **/Makefile **/CMakeFiles

我昨天的选择是将 repo 克隆到一个新文件夹,更新 CMakeLists.txt 以从子文件夹 build 构建。它比那些命令花费了更长的时间,但我只需要执行一次 :)
赏心悦目

尝试使用:cmake --clean-first path-of-CMakeLists.txt-file -B output-dir

--clean-first:先构建目标clean,然后再构建。 (仅清洁,使用 --target clean。)


该屏幕截图仅显示文本。然而,你截取它的屏幕截图,为任何带着屏幕阅读器来到这里的人打破了答案。请放下那张图片,复制/粘贴文本,然后花 1 分钟正确格式化该输入。
使用 --target clean 是什么意思。 $ cmake --target clean CMake 错误:未知参数 --target CMake 错误:为所有支持的选项运行“cmake --help”。
H
Hernan Villanueva

我最近发现的一个解决方案是将外源构建概念与 Makefile 包装器相结合。

在我的顶级 CMakeLists.txt 文件中,我包含以下内容以防止源内构建:

if ( ${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR} )
    message( FATAL_ERROR "In-source builds not allowed. Please make a new directory (called a build directory) and run CMake from there. You may need to remove CMakeCache.txt." )
endif()

然后,我创建一个顶级 Makefile,并包括以下内容:

# -----------------------------------------------------------------------------
# CMake project wrapper Makefile ----------------------------------------------
# -----------------------------------------------------------------------------

SHELL := /bin/bash
RM    := rm -rf
MKDIR := mkdir -p

all: ./build/Makefile
    @ $(MAKE) -C build

./build/Makefile:
    @  ($(MKDIR) build > /dev/null)
    @  (cd build > /dev/null 2>&1 && cmake ..)

distclean:
    @  ($(MKDIR) build > /dev/null)
    @  (cd build > /dev/null 2>&1 && cmake .. > /dev/null 2>&1)
    @- $(MAKE) --silent -C build clean || true
    @- $(RM) ./build/Makefile
    @- $(RM) ./build/src
    @- $(RM) ./build/test
    @- $(RM) ./build/CMake*
    @- $(RM) ./build/cmake.*
    @- $(RM) ./build/*.cmake
    @- $(RM) ./build/*.txt

ifeq ($(findstring distclean,$(MAKECMDGOALS)),)
    $(MAKECMDGOALS): ./build/Makefile
    @ $(MAKE) -C build $(MAKECMDGOALS)
endif

通过键入 make 调用默认目标 all,并调用目标 ./build/Makefile

目标 ./build/Makefile 所做的第一件事是使用 $(MKDIR) 创建 build 目录,它是 mkdir -p 的变量。目录 build 是我们将执行我们的源外构建的地方。我们提供参数 -p 以确保 mkdir 不会因为我们试图创建可能已经存在的目录而尖叫。

目标 ./build/Makefile 所做的第二件事是将目录更改为 build 目录并调用 cmake

回到 all 目标,我们调用 $(MAKE) -C build,其中 $(MAKE) 是为 make 自动生成的 Makefile 变量。 make -C 在执行任何操作之前更改目录。因此,使用 $(MAKE) -C build 等价于使用 cd build; make

总而言之,使用 make allmake 调用此 Makefile 包装器等效于执行以下操作:

mkdir build
cd build
cmake ..
make 

目标 distclean 调用 cmake ..,然后是 make -C build clean,最后从 build 目录中删除所有内容。我相信这正是您在问题中所要求的。

Makefile 的最后一部分评估用户提供的目标是否为 distclean。如果不是,它会在调用它之前将目录更改为 build。这是非常强大的,因为用户可以键入,例如 make clean,Makefile 会将其转换为 cd build; make clean 的等价物。

总之,此 Makefile 包装器与强制的源外构建 CMake 配置相结合,使用户无需与命令 cmake 交互。此解决方案还提供了一种优雅的方法来从 build 目录中删除所有 CMake 输出文件。

PS 在 Makefile 中,我们使用前缀 @ 来抑制 shell 命令的输出,使用前缀 @- 来忽略 shell 命令的错误。当使用 rm 作为 distclean 目标的一部分时,如果文件不存在,该命令将返回错误(它们可能已经使用带有 rm -rf build 的命令行被删除,或者它们从未在第一次生成地方)。这个返回错误将强制我们的 Makefile 退出。我们使用前缀 @- 来防止这种情况。如果文件已经被删除是可以接受的;我们希望我们的 Makefile 继续运行并删除其余部分。

还有一点需要注意:如果您使用可变数量的 CMake 变量来构建您的项目,例如 cmake .. -DSOMEBUILDSUSETHIS:STRING="foo" -DSOMEOTHERBUILDSUSETHISTOO:STRING="bar",则此 Makefile 可能不起作用。此 Makefile 假定您以一致的方式调用 CMake,通过键入 cmake .. 或通过提供 cmake 一致数量的参数(您可以包含在 Makefile 中)。

最后,信用到期。此 Makefile 包装器改编自 C++ Application Project Template 提供的 Makefile。


我建议永远不要将 Makefile 用作元构建器。这确实令人不安且容易出错。如果您想这样做,请编写一个脚本(例如 build.sh
P
Peter Mortensen

我为此目的使用以下 shell 脚本:

#!/bin/bash

for fld in $(find -name "CMakeLists.txt" -printf '%h ')
do
    for cmakefile in CMakeCache.txt cmake_install.cmake CTestTestfile.cmake CMakeFiles Makefile
    do
        rm -rfv $fld/$cmakefile
    done
done

如果您使用的是 Windows,请使用 Cygwin 编写此脚本。


P
Peter Mortensen

为了在使用“外源”构建(即在 build 目录中构建)时简化清理,我使用以下脚本:

$ cat ~/bin/cmake-clean-build
#!/bin/bash

if [ -d ../build ]; then
    cd ..
    rm -rf build
    mkdir build
    cd build
else
    echo "build directory DOES NOT exist"
fi

每次需要清理时,都应从 build 目录获取此脚本:

. cmake-clean-build

美好而安全。由于您可能在文件管理器中打开了构建目录,因此我建议将 cd .. ; rm ; mkdir ; cd 序列替换为 cd .. ; rm -rf build/*
Z
Zouppen

如果您有自定义定义并希望在清理之前保存它们,请在构建目录中运行以下命令:

sed -ne '/variable specified on the command line/{n;s/.*/-D \0 \\/;p}' CMakeCache.txt

然后创建一个新的构建目录(或删除旧的构建目录并重新创建它),最后使用上面脚本获得的参数运行 cmake


P
Peter Mortensen

如果你跑

cmake .

它将重新生成 CMake 文件。例如,如果您将新文件添加到由 *.cc 选择的源文件夹,则这是必需的。

虽然这本身不是“干净”的,但它确实通过重新生成缓存来“清理”CMake 文件。


它不干净。编译状态:如果 1200 个文件中的 500 个已编译,则在 "cmake ." 之后。它将继续使用最后 700 个文件。
L
LinconFive

cmake 主要是制作一个 Makefile,可以将 rm 添加到 clean PHONY

例如,

[root@localhost hello]# ls
CMakeCache.txt  CMakeFiles  cmake_install.cmake  CMakeLists.txt  hello  Makefile  test
[root@localhost hello]# vi Makefile
clean:
        $(MAKE) -f CMakeFiles/Makefile2 clean
        rm   -rf   *.o   *~   .depend   .*.cmd   *.mod    *.ko   *.mod.c   .tmp_versions *.symvers *.d *.markers *.order   CMakeFiles  cmake_install.cmake  CMakeCache.txt  Makefile

s
somethingsomewhere

这已经很老了,但是如果您完全删除 cmake-build-debug 文件夹,当您使用 cmake 编译时,它应该会自动创建一个新的 cmake-build-debug 文件夹,其中包含您需要的所有内容。在 CLion 中效果特别好。


a
aquawicket

这是我使用的。它包含在一个函数中,它是跨平台的,它演示了如何查找匹配的文件名或文件夹名称,以防您想进行任何简单的调整。这个函数在我每次构建脚本时都会运行,并且可以完美地满足我的需求。

function(DELETE_CACHE)
    if(CMAKE_HOST_WIN32)
        execute_process(COMMAND cmd /c for /r %%i in (CMakeCache.*) do del "%%i" WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
        execute_process(COMMAND cmd /c for /d /r %%i in (*CMakeFiles*) do rd /s /q "%%i" WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
    else()
        execute_process(COMMAND find . -name "CMakeCache.*" -delete WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
        execute_process(COMMAND "rm -rf `find . -type d -name CMakeFiles`" WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
    endif()
endfunction()

P
Peter Mortensen

我成功使用 zsxwing's answer 解决了以下问题:

我有在多个主机上构建的源代码(在 Raspberry Pi Linux 板上、在 VMware Linux 虚拟机上等)

我有一个 Bash 脚本,它根据机器的主机名创建临时目录,如下所示:

# Get hostname to use as part of directory names
HOST_NAME=`uname -n`

# Create a temporary directory for cmake files so they don't
# end up all mixed up with the source.

TMP_DIR="cmake.tmp.$HOSTNAME"

if [ ! -e $TMP_DIR ] ; then
  echo "Creating directory for cmake tmp files : $TMP_DIR"
  mkdir $TMP_DIR
else
  echo "Reusing cmake tmp dir : $TMP_DIR"
fi

# Create makefiles with CMake
#
# Note: switch to the temporary dir and build parent 
#       which is a way of making cmake tmp files stay
#       out of the way.
#
# Note 2: to clean up cmake files, it is OK to
#        "rm -rf" the temporary directories

echo
echo Creating Makefiles with cmake ...

cd $TMP_DIR

cmake ..

# Run makefile (in temporary directory)

echo
echo Starting build ...

make

P
Peter Mortensen

创建一个临时构建目录,例如 build_cmake。因此,您的所有构建文件都将位于此文件夹中。

然后在您的主 CMake 文件中添加以下命令。

add_custom_target(clean-all
    rm -rf *
)

因此在编译时做

cmake ..

并清洁:

make clean-all

如果有人不小心会在源代码中构建而不是在源代码之外构建,那么删除所有项目的好方法
是的。此方法应仅用于“out of source build”
糟糕的推荐。不应该作为答案存在。
@AnnevanRossum 同意

关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅