Ищите команду cmake clean для очистки вывода CMake

Так же, как make clean удаляет все файлы, которые создавал make файл, я хотел бы сделать то же самое с CMake. Слишком часто я обнаруживаю, что вручную просматриваю каталоги, удаляя файлы типа cmake_install.cmake и CMakeCache.txt, а также папки CMakeFiles.

Есть ли команда типа cmake clean для автоматического удаления всех этих файлов? В идеале это должно соответствовать рекурсивной структуре, определенной в текущем каталоге CMakeLists.txt.

Ответ 1

Нет cmake clean.

Я обычно создаю проект в одной папке, например "build". Поэтому, если я хочу make clean, я могу просто rm -rf build.

Папка "build" в том же каталоге, что и "CMakeLists.txt", обычно является хорошим выбором. Чтобы создать свой проект, вы просто даете cmake расположение CMakeLists.txt в качестве аргумента. Например: cd <location-of-cmakelists>/build && cmake ... (Из @ComicSansMS)

Ответ 2

Официальный FAQ CMake гласит:

Некоторые деревья сборки, созданные с помощью автоинструментов GNU, имеют цель "make distclean", которая очищает сборку, а также удаляет Makefiles и другие части сгенерированной системы сборки. CMake не генерирует цель "make distclean", потому что файлы CMakeLists.txt могут запускать сценарии и произвольные команды; CMake не имеет возможности точно отслеживать, какие файлы генерируются как часть запуска CMake. Предоставление нечистой цели создало бы у пользователей ложное впечатление, что она будет работать так, как ожидалось. (CMake генерирует цель "make clean" для удаления файлов, созданных компилятором и компоновщиком.)

Цель "make distclean" необходима, только если пользователь выполняет сборку в исходном коде. CMake поддерживает сборки из исходного кода, но мы настоятельно рекомендуем пользователям принять концепцию сборки из исходного кода. Использование дерева сборки, отдельного от дерева исходных текстов, не позволит CMake генерировать любые файлы в дереве исходных текстов. Поскольку CMake не изменяет исходное дерево, нет необходимости в удаленной цели. Начать новую сборку можно, удалив дерево сборки или создав отдельное дерево сборки.

Ответ 3

Я гуглил его примерно полчаса, и единственное полезное, что я придумал, это вызов утилиты 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 вы используете) до этого.

:)

Ответ 4

В наши дни повсюду в Git вы можете забыть CMake и использовать git clean -d -f -x, который удалит все файлы, не находящиеся под контролем исходного кода.

Ответ 5

Вы можете использовать что-то вроде:

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". Следовательно, вы не можете использовать команду clean-all перед "что-нибудь" в любом контексте:

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

Это тоже не работает.

Ответ 6

Простое создание rm CMakeCache.txt работает для меня тоже.

Ответ 7

Я согласен, что сборка вне исходного кода - лучший ответ. Но те времена, когда вы просто должны сделать сборку в истоке, я написал сценарий Python доступного здесь, который:

  1. Бежит "почисти"
  2. Удаляет определенные сгенерированные CMake файлы в каталоге верхнего уровня, таком как CMakeCache.txt
  3. Для каждого подкаталога, содержащего каталог CMakeFiles, он удаляет CMakeFiles, Makefile, cmake_install.cmake.
  4. Удаляет все пустые подкаталоги.

Ответ 8

Решение, которое я нашел недавно, состоит в том, чтобы объединить концепцию сборки вне исходного кода с оболочкой 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

Цель по умолчанию all вызывается, набрав make и вызывая цель ./build/Makefile.

Первое, что делает цель ./build/Makefile, - это создать каталог build, используя $(MKDIR), который является переменной для mkdir -p. Каталог build - это место, где мы выполним сборку вне источника. Мы предоставляем аргумент -p, чтобы mkdir не кричал на нас, пытаясь создать каталог, который может уже существовать.

Во-вторых, цель ./build/Makefile заключается в том, чтобы сменить каталоги на каталог build и вызвать cmake.

Вернемся к цели all, мы вызываем $(MAKE) -C build, где $(MAKE) - это переменная Makefile, автоматически сгенерированная для make. make -C изменяет каталог перед тем, как что-либо сделать. Поэтому использование $(MAKE) -C build эквивалентно выполнению cd build; make.

Подводя итог, вызов этой оболочки Makefile с помощью make all или make эквивалентен выполнению:

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. Это решение также предоставляет элегантный метод для удаления всех выходных файлов CMake из каталога build.

P.S. В Makefile мы используем префикс @ для подавления вывода из команды оболочки, а префикс @- - игнорировать ошибки из команды оболочки. При использовании rm как части цели distclean команда возвращает ошибку, если файлы не существуют (они, возможно, уже были удалены с использованием командной строки с помощью rm -rf build, или они никогда не были сгенерированы в первом место). Эта обратная ошибка заставит наш Makefile выйти. Мы используем префикс @-, чтобы предотвратить это. Это приемлемо, если файл уже был удален; мы хотим, чтобы наш Makefile продолжал идти и удалял остальные.

Еще одно замечание: этот Makefile может не работать, если вы используете переменное число переменных CMake для создания вашего проекта, например cmake .. -DSOMEBUILDSUSETHIS:STRING="foo" -DSOMEOTHERBUILDSUSETHISTOO:STRING="bar". Этот Makefile предполагает, что вы последовательно вызываете CMake, либо набрав cmake .., либо предоставив cmake последовательное количество аргументов (которые вы можете включить в свой Makefile).

Наконец, кредит, в котором должен быть кредит. Эта оболочка Makefile была адаптирована из Makefile, предоставленной С++ Application Project Template.

Ответ 9

В случае, когда вы передаете параметры -D в CMake при генерации файлов сборки и не хотите удалять весь каталог build/:

Просто удалите каталог CMakeFiles/внутри вашего каталога сборки.

rm -rf CMakeFiles/
cmake --build .

Это приводит к повторному запуску CMake, и системные файлы сборки восстанавливаются. Ваша сборка также начнется с нуля.

Ответ 10

Может быть, это немного устарело, но так как это первый хит, когда вы cmake clean Google cmake clean, я добавлю это:

Поскольку вы можете начать сборку в директории сборки с указанной целью с помощью

cmake --build. --target xyz

ты можешь конечно бежать

cmake --build. --target clean

запустить clean цель в сгенерированных файлах сборки.

Ответ 11

Конечно, из -s наших сборок - это метод перехода к Makefile файлам Unix, но если вы используете другой генератор, такой как Eclipse CDT, он предпочитает встраивать в -s нашу работу. В этом случае вам нужно будет удалить файлы CMake вручную. Попробуй это:

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

Или, если вы включили globstar с shopt -s globstar, попробуйте этот менее отвратительный подход:

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

Ответ 12

Если вы бежите

cmake .

это восстановит файлы CMake. Что необходимо, если вы добавляете новый файл в исходную папку, выбранную, например, *.cc.

Хотя это и не "чистый" как таковой, он "очищает" файлы CMake путем регенерации кешей.

Ответ 13

Я использую следующий скрипт для таких целей:

#!/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 для этого скрипта.

Ответ 14

Чтобы упростить очистку при использовании сборки "вне источника" (т.е. вы строите в каталоге 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

Ответ 15

Если у вас есть пользовательские определения и вы хотите сохранить их перед очисткой, запустите следующее в вашей директории сборки:

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

Затем создайте новый каталог сборки (или удалите старый каталог сборки и создайте его заново) и, наконец, запустите cmake с аргументами, которые вы получите с помощью приведенного выше сценария.

Ответ 16

попробуйте использовать: cmake --clean-first path-of-CMakeLists.txt-file -B output-dir

--clean-first: сначала создать мишень, а затем построить.
(Только для очистки используйте --target clean.)

Ответ 17

Во многих случаях полезно использовать make rebuild_cache. Он запускает полный запуск configure, и это приведет к восстановлению всех целей, которые зависят от измененных переменных.

Ответ 18

У меня это в моем файле оболочки rc (.bashrc, .zshrc):

t-cmake-clean() {
    local BUILD=$(basename $(pwd))
    cd ..
    rm -rf $BUILD
    mkdir $BUILD && cd $BUILD
}

Вы должны использовать его только для сборки вне источника. Скажем, для этой цели у вас есть каталог с именем build/. Тогда вам просто нужно запустить t-cmake-clean изнутри.

Ответ 19

Я успешно использовал ответ zsxwing для решения следующей проблемы:

У меня есть источник, который я собираю на нескольких хостах (на плате 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

Ответ 20

Создайте временный каталог сборки, например, build_cmake. Следовательно, все ваши файлы сборки будут в этой папке.

Затем в вашем основном файле CMake добавьте команду ниже.

add_custom_target(clean-all
    rm -rf *
)

Следовательно, при компиляции

cmake ..

И для очистки сделать:

make clean-all