正如 make clean
删除 makefile 生成的所有文件一样,我想对 CMake 做同样的事情。我经常发现自己手动浏览删除 cmake_install.cmake
和 CMakeCache.txt
等文件的目录以及 CMakeFiles
文件夹。
是否有像 cmake clean
这样的命令可以自动删除所有这些文件?理想情况下,这应该遵循当前目录的 CMakeLists.txt
文件中定义的递归结构。
cmake --build <build-dir> --target clean
。
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)
一些使用 GNU 自动工具创建的构建树有一个“make distclean”目标,用于清理构建并删除 Makefile 和生成的构建系统的其他部分。 CMake 不会生成“make distclean”目标,因为 CMakeLists.txt 文件可以运行脚本和任意命令; CMake 无法准确跟踪作为运行 CMake 的一部分生成的文件。提供 distclean 目标会给用户一种错误的印象,即它会按预期工作。 (CMake 确实会生成一个“make clean”目标来删除编译器和链接器生成的文件。)只有当用户执行源内构建时,才需要“make distclean”目标。 CMake 支持源内构建,但我们强烈鼓励用户采用源外构建的概念。使用与源代码树分离的构建树将阻止 CMake 在源代码树中生成任何文件。因为 CMake 不会更改源代码树,所以不需要 distclean 目标。可以通过删除构建树或创建单独的构建树来开始新的构建。
we strongly encourage users to adopt the notion of an out-of-source build
- 可惜他们当时将其设为默认行为。 (说真的,让默认行为成为你不鼓励用户做的事情是一个愚蠢的设计决定。)
在 Git 无处不在的这些日子里,您可能会忘记 CMake 并使用 git clean -d -f -x
,这将删除所有不受源代码控制的文件。
-x
选项。这是 git
交易的绝妙伎俩。虽然我个人仍然会先进行试运行,git clean -d -f -x -n
。每隔一段时间,我都会将用于项目的便利文件保存在项目文件夹中,并在 git
控制下,但我不想与其他人共享它,因此我不会将它git add
用于项目。如果我不小心添加了一个 -e <pattern>
选项,就会把这种文件吹走。在这方面,如果 git
有一个 .gitcleanignore
文件会很好。 :)
chattr +i $filename
(需要root权限,此后不允许修改文件)。这样 git 将无法删除该文件,即使它尝试像 rm -f
那样执行它。
git add
的新添加文件呢?
git clean -dfx
。这也依赖于一个好的 .gitignore btw
我用谷歌搜索了大约半个小时,我想出的唯一有用的东西是调用 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 生成器)。
:)
rm -rf CMakeFiles ; rm -rf */CMakeFiles ; rm -rf */*/CMakeFiles ; rm -rf */*/*/CMakeFiles
,但还没有完成......
你可以使用类似的东西:
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
)
那也行不通。
CMakeCache.txt
也对我没有帮助,但我发现这种类似的方法可以在每次构建中更新变量,因此无需删除 CMakeCache.txt
:stackoverflow.com/questions/53159371/…
简单地发出 rm CMakeCache.txt
也适用于我。
cmake /build-path
。
也许它有点过时了,但由于这是您在谷歌 cmake clean
时的第一次点击,我将添加以下内容:
由于您可以使用指定的目标在构建目录中启动构建
cmake --build . --target xyz
你当然可以跑
cmake --build . --target clean
在生成的构建文件中运行 clean
目标。
我同意外源构建是最好的答案。但是在您必须进行源代码构建的时候,我编写了一个可用的 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
。否则,脚本是完美的!
ExternalProject
一起使用是一件苦差事(需要 BUILD_IN_SOURCE
,隐含山羊牺牲),我什至不确定它是否可以使用 FetchContent
,因为它缺少类似的选项。
有趣的是,这个问题得到了如此多的关注和复杂的解决方案,这确实表明没有使用 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
到clean:rm -rf build_work
重新创建构建文件夹:您甚至不需要 mkdir build_work
,只需使用 cmake -B build_work
配置它。
如果您在生成构建文件时将 -D
参数传递到 CMake 并且不想删除整个 build/ 目录:
只需删除构建目录中的 CMakeFiles/ 目录即可。
rm -rf CMakeFiles/
cmake --build .
这会导致 CMake 重新运行,并重新生成构建系统文件。您的构建也将从头开始。
当然,源代码外构建是 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
build
构建。它比那些命令花费了更长的时间,但我只需要执行一次 :)
尝试使用:cmake --clean-first path-of-CMakeLists.txt-file -B output-dir
--clean-first:先构建目标clean,然后再构建。 (仅清洁,使用 --target clean。)
我最近发现的一个解决方案是将外源构建概念与 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 all
或 make
调用此 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
)
我为此目的使用以下 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 编写此脚本。
为了在使用“外源”构建(即在 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/*
。
如果您有自定义定义并希望在清理之前保存它们,请在构建目录中运行以下命令:
sed -ne '/variable specified on the command line/{n;s/.*/-D \0 \\/;p}' CMakeCache.txt
然后创建一个新的构建目录(或删除旧的构建目录并重新创建它),最后使用上面脚本获得的参数运行 cmake
。
如果你跑
cmake .
它将重新生成 CMake 文件。例如,如果您将新文件添加到由 *.cc 选择的源文件夹,则这是必需的。
虽然这本身不是“干净”的,但它确实通过重新生成缓存来“清理”CMake 文件。
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
这已经很老了,但是如果您完全删除 cmake-build-debug 文件夹,当您使用 cmake 编译时,它应该会自动创建一个新的 cmake-build-debug 文件夹,其中包含您需要的所有内容。在 CLion 中效果特别好。
这是我使用的。它包含在一个函数中,它是跨平台的,它演示了如何查找匹配的文件名或文件夹名称,以防您想进行任何简单的调整。这个函数在我每次构建脚本时都会运行,并且可以完美地满足我的需求。
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()
我成功使用 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
创建一个临时构建目录,例如 build_cmake
。因此,您的所有构建文件都将位于此文件夹中。
然后在您的主 CMake 文件中添加以下命令。
add_custom_target(clean-all
rm -rf *
)
因此在编译时做
cmake ..
并清洁:
make clean-all
cd <location-of-cmakelists>/build && cmake ..