web-dev-qa-db-fra.com

Recherche d'une commande 'cmake clean' pour nettoyer la sortie de CMake

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.

311
Bill Cheatham

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)

378
zsxwing

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.

61
Peter

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.

:)

45
user1614309

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.

44
Jean Davy

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.

29
Peregring-lk

Émettre simplement rm CMakeCache.txt fonctionne aussi pour moi.

18
user1480788

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:

  1. S'exécute "nettoie"
  2. Supprime des fichiers spécifiques générés par CMake dans le répertoire de niveau supérieur, tels que CMakeCache.txt
  3. Pour chaque sous-répertoire contenant un répertoire CMakeFiles, il supprime CMakeFiles, Makefile, cmake_install.cmake.
  4. Supprime tous les sous-répertoires vides.
7
tschutter

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++ .

4
Hernan Villanueva

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.

3
redleg

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
2
CJxD

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.

2
nenchev

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.

0
Homer6

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
0
Alexander

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

0
赏心悦目

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.

0
Zouppen

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.

0
yanpas