Tout comme make clean
supprime tous les fichiers produits par un makefile, j'aimerais faire la même chose avec CMake. Trop souvent, je me retrouve à parcourir manuellement des répertoires en supprimant des fichiers tels que cmake_install.cmake
et CMakeCache.txt
et les dossiers CMakeFiles
.
Existe-t-il une commande telle que cmake clean
pour supprimer automatiquement tous ces fichiers? Idéalement, cela devrait suivre la structure récursive définie dans le fichier CMakeLists.txt
du répertoire en cours.
Il n'y a pas de cmake clean
.
Je construis habituellement le projet dans un seul dossier comme "build". Donc, si je veux make clean
, je peux simplement rm -rf build
.
Le dossier "build" dans le même répertoire que la racine "CMakeLists.txt" est généralement un bon choix. Pour construire votre projet, il vous suffit de donner à cmake l'emplacement de CMakeLists.txt sous forme d'argument. Par exemple: cd <location-of-cmakelists>/build && cmake ..
. (De @ComicSansMS)
CMake officiel FAQ déclare:
Certains arbres de compilation créés avec GNU autotools ont un "make distclean" cible qui nettoie la construction et supprime également les Makefiles et autres parties du système de construction généré. CMake ne génère pas de cible "make Distclean" car les fichiers CMakeLists.txt peuvent exécuter des scripts et commandes arbitraires; CMake n'a aucun moyen de suivre exactement quels fichiers sont générés dans le cadre de l'exécution de CMake. Fournir une cible distclean donnerait aux utilisateurs la fausse impression que cela fonctionnerait comme prévu . (CMake génère une cible "make clean" pour supprimer les fichiers générés Par le compilateur et l'éditeur de liens.)
Une cible "make distclean" est seulement nécessaire si l'utilisateur effectue une construction in-source. CMake soutient versions in-source, mais nous encourageons vivement les utilisateurs à adopter la notion d'une construction hors source. Utilisation d'un arbre de compilation distinct de l’arborescence source empêchera CMake de générer des fichiers dans le fichier arbre source. Parce que CMake ne change pas l’arbre source, il y a pas besoin d'une cible distclean. On peut commencer une nouvelle construction par supprimer l'arbre de construction ou créer un arbre de construction distinct.
Je l'ai googlé pendant une demi-heure et la seule chose utile que j'ai trouvée est d'invoquer l'utilitaire 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
Assurez-vous également d’appeler make clean
(ou le générateur CMake que vous utilisez) avant that.
:)
En ces jours de Git, vous pouvez oublier CMake et utiliser git clean -d -f -x
, qui supprimera tous les fichiers qui ne sont pas sous contrôle de source.
Vous pouvez utiliser quelque chose comme:
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)
Je crée généralement une commande "make clean-all" en ajoutant un appel à "make clean" à l'exemple précédent:
add_custom_target(clean-all
COMMAND ${CMAKE_BUILD_TOOL} clean
COMMAND ${CMAKE_COMMAND} -P clean-all.cmake
)
N'essayez pas d'ajouter la cible "propre" comme dépendance:
add_custom_target(clean-all
COMMAND ${CMAKE_COMMAND} -P clean-all.cmake
DEPENDS clean
)
Parce que "nettoyer" n'est pas une vraie cible dans CMake et que cela ne fonctionne pas.
De plus, vous ne devriez pas utiliser ces "fichiers propres de cmake" comme dépendances:
add_custom_target(clean-all
COMMAND ${CMAKE_BUILD_TOOL} clean
DEPENDS clean-cmake-files
)
Parce que, si vous faites cela, tous les fichiers CMake seront effacés avant la fin du nettoyage de tout, et make vous lancera une erreur en recherchant "CMakeFiles/clean-all.dir/build.make". En conséquence, vous ne pouvez pas utiliser la commande clean-all avant "rien" dans aucun contexte:
add_custom_target(clean-all
COMMAND ${CMAKE_BUILD_TOOL} clean
COMMAND ${CMAKE_COMMAND} -P clean-all.cmake
)
Cela ne fonctionne pas non plus.
Émettre simplement rm CMakeCache.txt
fonctionne aussi pour moi.
Je conviens que la compilation hors source est la meilleure solution. Mais pour les moments où vous devez juste faire une construction in-source, j'ai écrit un script Python disponible ici , qui:
Une solution que j'ai trouvée récemment consiste à combiner le concept de construction hors source avec un wrapper Makefile.
Dans mon fichier CMakeLists.txt de niveau supérieur, j'inclus les éléments suivants pour empêcher les versions in-source:
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()
Ensuite, je crée un Makefile de niveau supérieur et j'inclus ce qui suit:
# -----------------------------------------------------------------------------
# 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
La cible par défaut all
est appelée en tapant make
et appelle le ./build/Makefile
cible.
La première chose que le ./build/Makefile
cible fait est de créer le répertoire build
en utilisant $(MKDIR)
, qui est une variable pour mkdir -p
. Le répertoire build
est l'endroit où nous allons effectuer notre construction hors source. Nous fournissons l’argument -p
pour nous assurer que mkdir
ne nous crie pas après avoir tenté de créer un répertoire qui existe peut-être déjà.
La deuxième chose que le ./build/Makefile
cible fait est de changer de répertoire pour le répertoire build
et d’appeler cmake
.
De retour à la cible all
, nous appelons $(MAKE) -C build
, où $(MAKE)
est une variable Makefile générée automatiquement pour make
. make -C
change le répertoire avant de faire quoi que ce soit. Donc, utiliser $(MAKE) -C build
équivaut à faire cd build; make
.
Pour résumer, appeler cette enveloppe Makefile avec make all
ou make
équivaut à faire:
mkdir build
cd build
cmake ..
make
La cible distclean
appelle cmake ..
, puis make -C build clean
et, enfin, supprime tout le contenu du répertoire build
. Je crois que c'est exactement ce que vous avez demandé dans votre question.
La dernière partie du Makefile évalue si la cible fournie par l'utilisateur est ou n'est pas distclean
. Sinon, il changera de répertoire en build
avant de l'invoquer. C'est très puissant parce que l'utilisateur peut taper, par exemple, make clean
, et le Makefile le transformera en un équivalent de cd build; make clean
.
En conclusion, cet encapsuleur Makefile, associé à une configuration CMake de génération hors source obligatoire, permet à l'utilisateur de ne jamais interagir avec la commande cmake
. Cette solution fournit également une méthode élégante pour supprimer tous les fichiers de sortie CMake du répertoire build
.
P.S. Dans le Makefile, nous utilisons le préfixe @
pour supprimer la sortie d'une commande Shell et le préfixe @-
pour ignorer les erreurs d'une commande Shell. Si vous utilisez rm
avec la cible distclean
, la commande renverra une erreur si les fichiers n'existent pas (ils ont peut-être déjà été supprimés à l'aide de la ligne de commande avec rm -rf build
ou n'ont jamais été générés à l'origine). Cette erreur de retour forcera notre Makefile à se fermer. Nous utilisons le préfixe @-
pour empêcher cela. Il est acceptable si un fichier a déjà été supprimé. nous voulons que notre Makefile continue et supprime le reste.
Autre chose à noter: Ce Makefile peut ne pas fonctionner si vous utilisez un nombre variable de variables CMake pour construire votre projet, par exemple, cmake .. -DSOMEBUILDSUSETHIS:STRING="foo" -DSOMEOTHERBUILDSUSETHISTOO:STRING="bar"
. Ce Makefile suppose que vous appelez CMake de manière cohérente, en tapant cmake ..
ou en fournissant à cmake
un nombre cohérent d’arguments (que vous pouvez inclure dans votre Makefile).
Enfin, crédit lorsque le crédit est dû. Ce wrapper Makefile a été adapté à partir du Makefile fourni par Modèle de projet d'application C++ .
C’est peut-être un peu dépassé, mais comme c’est le premier hit de Google cmake clean
, je vais ajouter ceci:
Puisque vous pouvez démarrer une construction dans le répertoire de construction avec une cible spécifiée avec
cmake --build . --target xyz
vous pouvez bien sûr courir
cmake --build . --target clean
pour exécuter la cible clean
dans les fichiers de génération générés.
Bien sûr, les constructions hors source sont la méthode de choix pour Unix Makefiles, mais si vous utilisez un autre générateur tel que Eclipse CDT, il préfère que vous construisiez in-source. Dans ce cas, vous devrez purger les fichiers CMake manuellement. Essaye ça:
find . -name 'CMakeCache.txt' -o -name '*.cmake' -o -name 'Makefile' -o -name 'CMakeFiles' -exec rm -rf {} +
Ou si vous avez activé globstar avec shopt -s globstar
, essayez plutôt cette approche moins dégoûtante:
rm -rf **/CMakeCache.txt **/*.cmake **/Makefile **/CMakeFiles
Dans le cas où vous transmettez des paramètres -D
à CMake lors de la génération des fichiers de construction sans vouloir supprimer le répertoire de construction/entier:
Supprimez simplement le répertoire CMakeFiles/dans votre répertoire de construction.
rm -rf CMakeFiles/
cmake --build .
Cela entraîne la réexécution de CMake et la régénération des fichiers système. Votre construction commencera également à partir de zéro.
Si vous courez
cmake .
il va régénérer les fichiers CMake. Ce qui est nécessaire si vous ajoutez un nouveau fichier à un dossier source sélectionné par * .cc, par exemple.
Bien que ce ne soit pas un nettoyage en soi, il nettoie les fichiers CMake en régénérant les caches.
Pour simplifier le nettoyage lorsque vous utilisez une génération "hors source" (c’est-à-dire que vous construisez dans le répertoire build
), j’utilise le script suivant:
$ 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
Chaque fois que vous devez nettoyer, vous devez source ce script à partir du répertoire build
:
. cmake-clean-build
essayez d'utiliser: cmake --clean-first path-of-CMakeLists.txt-file -B output-dir
--clean-first: Construit d'abord la cible clean, puis build.
(Pour nettoyer uniquement, utilisez --target clean.)
Si vous avez des définitions personnalisées et souhaitez les enregistrer avant le nettoyage, exécutez la procédure suivante dans votre répertoire de construction:
sed -ne '/variable specified on the command line/{n;s/.*/-D \0 \\/;p}' CMakeCache.txt
Créez ensuite un nouveau répertoire de construction (ou supprimez l’ancien répertoire de construction et recréez-le), puis exécutez cmake
avec les arguments que vous obtiendrez avec le script ci-dessus.
J'utilise le script shell suivant à ces fins:
#!/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 vous utilisez Windows, utilisez Cygwin pour ce script.