descarga - cmake vs make
Buscando un comando ''cmake clean'' para borrar la salida de CMake (18)
Busqué en Google durante media hora y lo único útil que se me ocurrió fue invocar la utilidad de 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
Además, asegúrese de invocar make clean
(o cualquier generador CMake que esté usando) antes de eso.
:)
Del mismo modo que make clean
elimina todos los archivos que ha producido un makefile, me gustaría hacer lo mismo con CMake. Muy a menudo me encuentro recorriendo directorios manualmente eliminando archivos como cmake_install.cmake
y CMakeCache.txt
, y las carpetas CMakeFiles
.
¿Hay un comando como cmake clean
para eliminar todos estos archivos automáticamente? Idealmente, esto debería seguir la estructura recursiva definida dentro del archivo CMakeLists.txt
del directorio actual.
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 principal CMake agregue el siguiente comando.
add_custom_target(clean-all
rm -rf *
)
Por lo tanto, mientras compilamos
cmake ..
Y para limpiar hacer:
make clean-all
En el caso de que pase los parámetros -D
a CMake al generar los archivos de compilación y no desea eliminar todo el directorio de compilación:
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 compilación se regeneran. Su construcción también comenzará desde cero.
En estos días de Git en todas partes, puede olvidarse de CMake y usar git clean -d -f -x
, que eliminará todos los archivos que no estén bajo el control de código fuente.
Estoy de acuerdo en que la construcción fuera de la fuente es la mejor respuesta. Pero para los momentos en que solo debes hacer una compilación en la fuente, he escrito un script de Python disponible here , que:
- Corre "hacer limpio"
- Elimina archivos específicos generados por CMake en el directorio de nivel superior, como CMakeCache.txt
- Para cada subdirectorio que contiene un directorio CMakeFiles, elimina CMakeFiles, Makefile, cmake_install.cmake.
- Elimina todos los subdirectorios vacíos.
No hay cmake clean
.
Por lo general construyo el proyecto en una sola carpeta como "construir". Por lo tanto, si quiero make clean
, solo puedo 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 dé a cmake la ubicación de CMakeLists.txt como un argumento. Por ejemplo: cd <location-of-cmakelists>/build && cmake ..
(De @ComicSansMS)
Para simplificar la limpieza cuando se usa la compilación "fuera de la fuente" (es decir, la compilación en el directorio de build
), uso 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 esta secuencia de comandos desde el directorio de build
:
. cmake-clean-build
Por supuesto, las compilaciones fuera de la fuente son el método a seguir para los archivos Makefile de Unix, pero si estás usando otro generador como Eclipse CDT, prefieres que lo hagas en la fuente. En cuyo caso, deberá purgar los archivos de 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 asqueroso:
rm -rf **/CMakeCache.txt **/*.cmake **/Makefile **/CMakeFiles
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)
Por lo general, creo un comando "make clean-all" agregando una llamada a "make clean" en el 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.
Por otra parte, no debes usar estos "archivos limpios de cmake" como dependencia de nada:
add_custom_target(clean-all
COMMAND ${CMAKE_BUILD_TOOL} clean
DEPENDS clean-cmake-files
)
Porque, si lo hace, todos los archivos de CMake se borrarán antes de que se complete el proceso de limpieza de todo, y se producirá un error al buscar "CMakeFiles / clean-all.dir / build.make". En consecuencia, no puede utilizar el comando clean-all antes de "nada" en cualquier contexto:
add_custom_target(clean-all
COMMAND ${CMAKE_BUILD_TOOL} clean
COMMAND ${CMAKE_COMMAND} -P clean-all.cmake
)
Eso tampoco funciona.
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 directorio de compilación anterior y cmake
a cmake
) y finalmente ejecute cmake
con los argumentos que obtendrá con el script anterior.
Si tu corres
cmake .
se regenerarán los archivos de CMake. Lo cual es necesario si agrega un nuevo archivo a una carpeta de origen que está seleccionada por * .cc, por ejemplo.
Si bien esto no es un proceso "limpio", sí "limpia" los archivos CMake al regenerar los cachés.
Simplemente emitir rm CMakeCache.txt
funciona para mí.
Tal vez esté un poco desactualizado, pero como este es el primer éxito cuando cmake clean
Google cmake clean
Google, cmake clean
esto:
Ya que puede iniciar una compilación en el directorio de compilación con un objetivo específico con
cmake --build . --target xyz
puedes por supuesto correr
cmake --build . --target clean
para ejecutar el destino clean
en los archivos de compilación generados.
Tengo esto en mi archivo shell rc ( .bashrc
, .zshrc
):
t-cmake-clean() {
local BUILD=$(basename $(pwd))
cd ..
rm -rf $BUILD
mkdir $BUILD && cd $BUILD
}
Se supone que debes usarlo solo para compilaciones fuera de la fuente. Digamos que tienes un directorio llamado build/
para este propósito. Entonces solo tienes que ejecutar t-cmake-clean
desde dentro.
Una solución que encontré recientemente es combinar el concepto de compilación fuera de la fuente con un envoltorio Makefile.
En mi archivo CMakeLists.txt de nivel superior, incluyo lo siguiente para evitar compilaciones en origen:
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 destino predeterminado se llama a todo al escribir make
e invoca el destino ./build/Makefile
.
Lo primero que hace el destino ./build/Makefile
es crear el directorio de build
usando $(MKDIR)
, que es una variable para mkdir -p
. La build
directorio es donde realizaremos nuestra compilación fuera de la fuente. Proporcionamos el argumento -p
para garantizar que mkdir
no nos grite por intentar crear un directorio que ya exista.
Lo segundo que hace el destino ./build/Makefile
es cambiar los directorios al directorio de build
e invocar a cmake
.
De vuelta a all
destinos, invocamos $(MAKE) -C build
, donde $(MAKE)
es una variable de Makefile generada automáticamente para make
. make -C
cambia el directorio antes de hacer nada. Por lo tanto, usar $(MAKE) -C build
es equivalente a hacer cd build; make
cd build; make
Para resumir, llamar a este contenedor Makefile con make all
o make
es equivalente a hacer:
mkdir build
cd build
cmake ..
make
El destino distclean
invoca a cmake ..
, luego make -C build clean
, y finalmente, elimina todos los contenidos del directorio de build
. Creo que esto es exactamente lo que pidió en su pregunta.
La última parte de Makefile evalúa si el objetivo proporcionado por el usuario está o no está distclean
. Si no, cambiará los directorios para build
antes de invocarlo. Esto es muy poderoso porque el usuario puede escribir, por ejemplo, make clean
, y el Makefile transformará eso en un equivalente de cd build; make clean
de cd build; make clean
cd build; make clean
En conclusión, este envoltorio Makefile, en combinación con una configuración obligatoria CMake de compilación 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 de CMake del directorio de build
.
PS 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 rm
como parte del destino distclean
, el comando devolverá un error si los archivos no existen (es posible que ya se hayan eliminado utilizando la línea de comandos con rm -rf build
, o nunca se generaron en primer lugar). Este error de retorno obligará a nuestro Makefile a salir. Usamos el prefijo @-
para evitar eso. Es aceptable si un archivo ya fue eliminado; 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 invoca CMake de una manera consistente, ya sea escribiendo cmake ..
o proporcionando cmake
un número consistente de argumentos (que puede incluir en su Makefile).
Finalmente, crédito donde el crédito es debido. Esta envoltura de Makefile se adaptó del Makefile proporcionado por la Plantilla de Proyecto de Aplicación de C ++ .
Yo uso 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.
Usé la respuesta de zsxwing exitosamente 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 una secuencia de comandos 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
Las preguntas oficiales oficiales de CMake dicen :
Algunos árboles de compilación creados con los autotools de GNU tienen un objetivo "make distclean" que limpia la compilación y también elimina Makefiles y otras partes del sistema de compilación generado. CMake no genera un destino "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 ejecutar CMake. Proporcionar un objetivo distclean 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 enlazador).
Un objetivo "make distclean" solo es necesario si el usuario realiza una compilación en origen. CMake admite compilaciones en la fuente, pero recomendamos encarecidamente a los usuarios que adopten la noción de una compilación fuera de la fuente. El uso de un árbol de compilación que esté separado del árbol de origen evitará que CMake genere cualquier archivo en el árbol de origen. Debido a que CMake no cambia el árbol de origen, no es necesario un destino distclean. Uno puede comenzar una compilación nueva eliminando el árbol de compilación o creando un árbol de compilación separado.