Buscando un comando 'cmake clean' para limpiar la salida de CMake

419

Al igual que make cleanelimina todos los archivos que ha producido un archivo MAKE, me gustaría hacer lo mismo con CMake. Con demasiada frecuencia, me encuentro revisando manualmente directorios que eliminan archivos como cmake_install.cmakey CMakeCache.txt, y las CMakeFilescarpetas.

¿Existe un comando cmake cleanpara eliminar todos estos archivos automáticamente? Idealmente, esto debería seguir la estructura recursiva definida dentro del CMakeLists.txtarchivo del directorio actual .

Bill Cheatham
fuente

Respuestas:

487

No existe cmake clean.

Normalmente construyo el proyecto en una sola carpeta como "compilar". Entonces, si quiero make clean, puedo simplemente rm -rf build.

La carpeta "build" en el mismo directorio que la raíz "CMakeLists.txt" suele ser una buena opción. Para construir su proyecto, simplemente proporcione a cmake la ubicación de CMakeLists.txt como argumento. Por ejemplo: cd <location-of-cmakelists>/build && cmake ... (De @ComicSansMS)

zsxwing
fuente
101
Esto se denomina "compilación fuera de la fuente" y debería ser la forma preferida de hacerlo. Evita los conflictos de nombres y similares
arne
17
+1 para compilaciones fuera de la fuente. Esto se vuelve vital cuando se construyen múltiples arquitecturas. Por ejemplo, no puede compilar binarios de 64 bits y 32 bits con una compilación en fuente, ya que esto requiere dos jerarquías de caché CMake separadas.
ComicSansMS
99
Puede colocar la carpeta en cualquier lugar que desee, pero una carpeta de compilación en el mismo directorio que la raíz CMakeLists.txt suele ser una buena opción. Para compilar, simplemente proporcione a cmake la ubicación de CMakeLists.txt como argumento. Por ejemplo:cd <location-of-cmakelists>/build && cmake ..
ComicSansMS
64
Realmente debería haber un cmake clean. Todos los que alguna vez han usado cmake, incluso si tienen la costumbre de hacer compilaciones fuera de la fuente, accidentalmente han ejecutado cmake en el directorio incorrecto y es muy difícil limpiarlo manualmente.
Pavón
24
@DevSolar Pero lo contrario no es cierto; el hecho de que un archivo no esté bajo control de versiones no significa que sea generado por cmake y que sea seguro eliminarlo. Elegir qué archivos no versionados son trabajos en progreso que necesita mantener y cuáles son cruzados es una molestia, especialmente cuando gran parte de los archivos cmake son copias / nombres similares a sus archivos.
Pavón
84

Las preguntas frecuentes oficiales de CMake dicen :

Algunos árboles de compilación creados con herramientas automáticas GNU tienen un objetivo "make distclean" que limpia la compilación y también elimina los Makefiles y otras partes del sistema de compilación generado. CMake no genera un objetivo "make distclean" porque los archivos CMakeLists.txt pueden ejecutar scripts y comandos arbitrarios; CMake no tiene forma de rastrear exactamente qué archivos se generan como parte de la ejecución de CMake. Proporcionar un objetivo disclean daría a los usuarios la falsa impresión de que funcionaría como se esperaba. (CMake genera un objetivo de "limpieza" para eliminar los archivos generados por el compilador y el vinculador).

Un objetivo "make distclean" solo es necesario si el usuario realiza una compilación en la fuente. CMake admite compilaciones en la fuente, pero recomendamos a los usuarios que adopten la noción de una compilación fuera de la fuente. El uso de un árbol de compilación separado del árbol de origen evitará que CMake genere archivos en el árbol de origen. Como CMake no cambia el árbol de origen, no hay necesidad de un objetivo distclean. Uno puede comenzar una nueva compilación eliminando el árbol de compilación o creando un árbol de compilación separado.

Peter
fuente
Originalmente, tal como lo introdujeron y utilizaron las herramientas automáticas GNU, el objetivo 'distclean' está destinado a preparar el árbol de origen para poner en marcha y crear una distribución de alquitrán. Tales usuarios de archivos tar pueden descargar y descomprimir y luego ejecutar 'configure' y 'make' sin necesidad de las herramientas automáticas (aclocal, automake, autoconf, etc.) Si extrapolamos eso para hacer cmake, entonces un 'make distclean' nos dejaría limpios fuente que se puede construir sin tener instalado cmake. Sin embargo, esto no funciona cuando el generador era un generador de un solo objetivo (como lo es el objetivo 'make'), porque la configuración con cmake ocurre mientras que
Carlo Wood
... ejecutando cmake. Hacer una distribución que no se puede configurar, ni siquiera hace pruebas de plataforma, etc., es inútil. Por lo tanto, no existe un objetivo 'distclean' para cmake. Se requiere que cmake exista en la máquina del usuario final.
Carlo Wood
63

En estos días de Git en todas partes, puede olvidarse de CMake y su uso git clean -d -f -x, que eliminará todos los archivos que no estén bajo el control de la fuente.

Jean Davy
fuente
14
Sin -xembargo, esa opción. Ese es un excelente truco del gitoficio. Aunque me gustaría personalmente todavía lo hacen a-seca ejecutar primero, git clean -d -f -x -n. De vez en cuando mantengo un archivo de conveniencia que uso para un proyecto con la carpeta del proyecto bajo gitcontrol, pero no es algo que quiera compartir con otros, así que no lo git addincluyo en el proyecto. Esto eliminaría ese tipo de archivo si no tuviera cuidado de agregar una -e <pattern>opción. En esa nota, sería bueno si gittuviera un .gitcleanignorearchivo. :)
CivFan
1
@CivFan puede intentar usar chattr +i $filename(necesita permisos de root, no permite modificar el archivo después de esto). De esta manera, git no podrá eliminar ese archivo, incluso si intenta hacerlo de la misma manera rm -f.
Ruslan
3
Eso supone compilaciones en la fuente, lo que debe evitarse por sí mismo.
Slava
esta fue una solución simple (y no recuerdo lo que significan esas banderas, pero es solo una máquina de desarrollo lol).
matanster
1
Um, pero ¿qué pasa con los archivos recién agregados que el usuario olvidó git add?
yugr
50

Lo busqué en Google durante media hora y lo único útil que se me ocurrió fue invocar la findutilidad:

# 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

Además, asegúrese de invocar make clean(o cualquier generador CMake que esté usando) antes de eso.

:)

Peter Mortensen
fuente
36
Recomendaría no usar este enfoque si el directorio en el que está trabajando está bajo control de versión: cuando probé este enfoque con svn, eliminó algunos de los archivos de trabajo de los repositorios.
bumum
8
Puede haber otros archivos que coincidan con cmake, por lo que este no es un enfoque universal. Esto debería hacer: rm -rf CMakeFiles; rm -rf CMakeCache.txt; rm -rf instalación_cmake.cmake;
honza_p
1
Quitaría -exec rm -rf {} \ + y solo usaría -delete.
Edgar Aroutiounian
3
Votado negativamente, ya que este comando puede potencialmente eliminar algunos archivos de usuario. Prefiero el comando honza_p, no realmente más largo, más simple y menos arriesgado.
Adrien Descamps
1
@AdrienDescamps: excepto que todavía deja basura relacionada con cmake en subdirectorios. Estaba haciendo rm -rf CMakeFiles ; rm -rf */CMakeFiles ; rm -rf */*/CMakeFiles ; rm -rf */*/*/CMakeFilesy aún no había terminado ...
SF.
35

Puedes usar algo como:

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)

Normalmente creo un comando "make clean-all" agregando una llamada a "make clean" al ejemplo anterior:

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

No intente agregar el objetivo "limpio" como una dependencia:

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

Porque "limpio" no es un objetivo real en CMake y esto no funciona.

Además, no debe usar este "clean-cmake-files" como dependencia de nada:

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

Porque, si hace eso, todos los archivos CMake se borrarán antes de que se complete la limpieza, y make le arrojará un error al buscar "CMakeFiles / clean-all.dir / build.make". En consecuencia, no puede usar el comando clean-all antes de "nada" en ningún contexto:

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

Eso tampoco funciona.

Peregring-lk
fuente
¿Hay alguna manera de llenar cmake_generated automáticamente? ¿Quizás, combinando esto con la respuesta de yuri.makarevich? Actualmente, esto no eliminará archivos en los subdirectorios de $ {CMAKE_BINARY_DIR}.
foxcub
No funciona para Ninja o Visual Studio. No recomendaría tal enfoque.
usr1234567
23

Simplemente emitir rm CMakeCache.txttrabajos para mí también.

usuario1480788
fuente
1
Solo eliminar variables relacionadas en CMakeCache.txt también funciona para mí.
Yorkwar
Eliminar CMakeCache.txt y luego ejecutar 'cmake --build / build-path' provoca 'Error: no se pudo cargar el caché'.
nenchev
1
@nenchev necesitas correr de cmake /build-pathnuevo.
Samaursa
@Samaursa cmake --build vuelve a ejecutar cmake cuando es necesario, este método rompe el directorio de compilación y cmake se queja. Mi respuesta más abajo le dice que elimine el directorio CMakeFiles /, lo que hace que una reconstrucción limpia y cmake se vuelvan a ejecutar automáticamente.
nenchev
2
@nenchev Entiendo lo que quieres decir y estoy de acuerdo.
Samaursa
9

Tal vez esté un poco desactualizado, pero como este es el primer éxito cuando buscas en Google cmake clean, agregaré esto:

Como puede comenzar una compilación en el directorio de compilación con un objetivo especificado con

cmake --build . --target xyz

por supuesto puedes correr

cmake --build . --target clean

para ejecutar el cleanobjetivo en los archivos de compilación generados.

pierna roja
fuente
8

Estoy de acuerdo en que la compilación fuera de la fuente es la mejor respuesta. Pero para los momentos en que solo debe hacer una compilación en el código fuente, he escrito un script de Python disponible aquí , que:

  1. Ejecuta "hacer limpio"
  2. Elimina archivos específicos generados por CMake en el directorio de nivel superior, como CMakeCache.txt
  3. Para cada subdirectorio que contiene un directorio CMakeFiles, elimina CMakeFiles, Makefile, cmake_install.cmake.
  4. Elimina todos los subdirectorios vacíos.
tschutter
fuente
Gracias por eso. Me gustaría agregar una línea a su script que se silencie makecuando no haya Makefilepresente debido a una limpieza previa (es decir, hace que este script sea idempotente). Simplemente agregue la línea (correctamente espaciada): if os.path.isfile(os.path.join(directory,'Makefile')):justo antes de la línea 24: args = [y, por supuesto, sangra el resto del cuerpo de la función después de la línea recién agregada. Esto solo realizará un a make ... cleansi Makefileestá presente en el directorio actual que se está limpiando. De lo contrario, el guión es perfecto!
Michael Goldshteyn
4

Una solución que encontré recientemente es combinar el concepto de compilación fuera del código fuente con un contenedor Makefile.

En mi archivo CMakeLists.txt de nivel superior, incluyo lo siguiente para evitar compilaciones en la fuente:

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

Luego, creo un Makefile de nivel superior e incluyo lo siguiente:

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

El objetivo predeterminado allse llama escribiendo makee invoca el objetivo./build/Makefile .

Lo primero que hace el objetivo ./build/Makefilees crear el builddirectorio usando $(MKDIR), que es una variable para mkdir -p. El directorio buildes donde realizaremos nuestra compilación fuera de la fuente. Proporcionamos el argumento -ppara asegurarnos de que mkdirno nos grite por intentar crear un directorio que ya puede existir.

La segunda cosa que hace el objetivo ./build/Makefilees cambiar los directorios al builddirectorio e invocar cmake.

Volvemos al allobjetivo, invocamos $(MAKE) -C build, donde $(MAKE)se genera automáticamente una variable Makefile para make. make -Ccambia el directorio antes de hacer nada. Por lo tanto, usar $(MAKE) -C buildes equivalente a hacer cd build; make.

Para resumir, llamar a este contenedor Makefile con make allo makees equivalente a hacerlo:

mkdir build
cd build
cmake ..
make 

El destino distcleaninvoca cmake .., luego make -C build clean, y finalmente, elimina todo el contenido del builddirectorio. Creo que esto es exactamente lo que solicitó en su pregunta.

La última parte del Makefile evalúa si el objetivo proporcionado por el usuario es o no distclean. Si no, cambiará los directorios a buildantes de invocarlo. Esto es muy poderoso porque el usuario puede escribir, por ejemplo make clean, y el Makefile lo transformará en un equivalente de cd build; make clean.

En conclusión, este contenedor Makefile, en combinación con una configuración de CMake de compilación obligatoria fuera de la fuente, hace que el usuario nunca tenga que interactuar con el comando cmake. Esta solución también proporciona un método elegante para eliminar todos los archivos de salida CMake del builddirectorio.

PD En el Makefile, usamos el prefijo @para suprimir la salida de un comando de shell y el prefijo @-para ignorar los errores de un comando de shell. Cuando se usa rmcomo parte del distcleandestino, el comando devolverá un error si los archivos no existen (es posible que ya se hayan eliminado con la línea de comando rm -rf buildo que nunca se hayan generado). Este error de retorno obligará a nuestro Makefile a salir. Usamos el prefijo @-para evitar eso. Es aceptable si ya se eliminó un archivo; queremos que nuestro Makefile continúe y elimine el resto.

Otra cosa a tener en cuenta: este Makefile puede no funcionar si usa un número variable de variables CMake para construir su proyecto, por ejemplo cmake .. -DSOMEBUILDSUSETHIS:STRING="foo" -DSOMEOTHERBUILDSUSETHISTOO:STRING="bar",. Este Makefile asume que invocas CMake de manera consistente, ya sea escribiendo cmake ..o proporcionando cmakeun número consistente de argumentos (que puedes incluir en tu Makefile).

Finalmente, crédito donde se debe. Este contenedor Makefile se adaptó del Makefile proporcionado por la Plantilla de proyecto de aplicación C ++ .

Hernan Villanueva
fuente
4

Por supuesto, las compilaciones fuera de la fuente son el método de referencia para los Makefiles de Unix, pero si está utilizando otro generador como Eclipse CDT, prefiere que construya en la fuente. En ese caso, deberá purgar los archivos CMake manualmente. Prueba esto:

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

O si ha habilitado globstar con shopt -s globstar, pruebe este enfoque menos desagradable:

rm -rf **/CMakeCache.txt **/*.cmake **/Makefile **/CMakeFiles
Chris Watts
fuente
Mi elección ayer fue clonar el repositorio en una nueva carpeta, actualizar CMakeLists.txt para compilar desde una subcarpeta build. Tomó un poco más de tiempo que esos comandos, pero tuve que hacerlo solo una vez :)
Tien Do
4

intente usar: cmake --clean-first path-of-CMakeLists.txt-file -B output-dir

--clean-first: Construye el objetivo limpio primero, luego construye.
(Para limpiar solamente, use --target clean.)

赏心悦目
fuente
Esa captura de pantalla muestra solo texto . Sin embargo, tomas una captura de pantalla, rompiendo la respuesta para cualquiera que venga aquí con un lector de pantalla. Suelte esa imagen, copie / pegue el texto y dedique el minuto a formatear correctamente esa entrada.
GhostCat
3

En el caso de que pase -Dparámetros a CMake al generar los archivos de compilación y no desee eliminar todo el directorio build /:

Simplemente elimine el directorio CMakeFiles / dentro de su directorio de compilación.

rm -rf CMakeFiles/
cmake --build .

Esto hace que CMake se vuelva a ejecutar, y los archivos del sistema de construcción se regeneran. Su construcción también comenzará desde cero.

nenchev
fuente
1

Para simplificar la limpieza al usar la compilación "fuera de la fuente" (es decir, compila en el builddirectorio), utilizo el siguiente script:

$ 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

Cada vez que necesite limpiar, debe obtener este script del builddirectorio:

. cmake-clean-build
Alexander Lobov
fuente
Agradable y seguro. Como puedo tener abierto el directorio de compilación en el administrador de archivos, sugiero reemplazar la cd .. ; rm ; mkdir ; cdsecuencia con cd .. ; rm -rf build/*.
Mostafa Farzán
0

Si tiene definiciones personalizadas y desea guardarlas antes de limpiarlas, ejecute lo siguiente en su directorio de compilación:

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

Luego cree un nuevo directorio de compilación (o elimine el antiguo directorio de compilación y cmakevuelva a crearlo) y finalmente ejecute con los argumentos que obtendrá con el script anterior.

Zouppen
fuente
0

Si tu corres

cmake .

regenerará los archivos CMake. Lo cual es necesario si agrega un nuevo archivo a una carpeta de origen seleccionada por * .cc, por ejemplo.

Si bien esto no es una "limpieza" per se, "limpia" los archivos CMake al regenerar los cachés.

Homero6
fuente
No limpia wrt. el estado de compilación: si se compilaron 500 de 1200 archivos, después de "cmake". solo continuará con los últimos 700 archivos.
Peter Mortensen
0

Utilizo el siguiente script de shell para tales fines:

#!/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

Si está utilizando Windows, use Cygwin para este script.

yanpas
fuente
0

Es divertido ver que esta pregunta recibe tantas atenciones y soluciones complicadas, lo que de hecho muestra un dolor por no tener un método limpio con cmake.

Bueno, definitivamente cd buildpuedes hacer tu trabajo, luego hacer rm -rf *cuando necesites limpiar. Sin embargo, rm -rf *es un comando peligroso dado que muchas personas a menudo no saben en qué directorio se encuentran.

Si usted cd .., rm -rf buildy luego mkdir buildy luego cd build, eso es demasiado escribir.

Entonces, una buena solución es permanecer fuera de la carpeta de compilación y decirle a cmake la ruta:
para configurar: cmake -B build
para compilar: cmake --build build
para limpiar: rm -rf build
para recrear la carpeta de compilación: ni siquiera necesita mkdir build, simplemente configúrela con cmake -B buildy cmake la creará

franco
fuente
0

cmakeen su mayoría cocina a Makefile, uno podría agregar rma la PHONY limpia .

Por ejemplo,

[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
LinconFive
fuente
-1

Tengo esto en mi archivo rc de shell ( .bashrc, .zshrc):

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

Se supone que debe usarlo solo para compilaciones fuera de la fuente. Digamos que tiene un directorio llamado build/para este propósito. Entonces solo tienes que corrert-cmake-clean desde dentro.

thiagowfx
fuente
-3

Solía respuesta de zsxwing éxito para resolver el siguiente problema:

Tengo una fuente que construyo en varios hosts (en una placa Raspberry Pi Linux, en una máquina virtual VMware Linux, etc.)

Tengo un script Bash que crea directorios temporales basados ​​en el nombre de host de la máquina como este:

# 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
asantanna
fuente
-8

Cree un directorio de compilación temporal, por ejemplo, build_cmake ,. Por lo tanto, todos sus archivos de compilación estarán dentro de esta carpeta.

Luego, en su archivo CMake principal, agregue el siguiente comando.

add_custom_target(clean-all
    rm -rf *
)

Por lo tanto, mientras compilamos

cmake ..

Y para limpiar hacer:

make clean-all
Natesh
fuente
11
buena manera de eliminar todo su proyecto si alguien construye accidentalmente dentro de la fuente en lugar de fuera de la fuente
3
si. este método debe usarse solo con "compilación fuera de la fuente"
Natesh
66
Terrible recomendación. No debe existir como respuesta.
Anne van Rossum
@AnnevanRossum de acuerdo
zevarito