Alla ricerca di un comando 'cmake clean' per cancellare l'output di CMake


419

Proprio come make cleancancella tutti i file prodotti da un makefile, vorrei fare lo stesso con CMake. Troppo spesso mi trovo a scorrere manualmente le directory rimozione di file come cmake_install.cmakee CMakeCache.txt, e le CMakeFilescartelle.

Esiste un comando come cmake cleanrimuovere automaticamente tutti questi file? Idealmente, questo dovrebbe seguire la struttura ricorsiva definita all'interno del CMakeLists.txtfile della directory corrente .

Risposte:


487

Non c'è cmake clean.

Di solito costruisco il progetto in una singola cartella come "build". Quindi, se voglio make clean, posso solo rm -rf build.

La cartella "build" nella stessa directory della radice "CMakeLists.txt" è in genere una buona scelta. Per costruire il tuo progetto, dai semplicemente a cmake la posizione di CMakeLists.txt come argomento. Ad esempio: cd <location-of-cmakelists>/build && cmake ... (Da @ComicSansMS)


101
Questo si chiama "build out of source" e dovrebbe essere il modo preferito di procedere. Evita gli scontri con i nomi e simili
arne

17
+1 per build out-of-source. Questo diventa vitale quando si costruiscono più architetture. Ad esempio, non è possibile creare binari a 64 e 32 bit con una build in-source, poiché ciò richiede due gerarchie di cache CMake separate.
ComicSansMS

9
Puoi posizionare la cartella dove vuoi, ma una cartella di build nella stessa directory di CMakeLists.txt di solito è una buona scelta. Per crearti è sufficiente fornire a cmake la posizione di CMakeLists.txt come argomento. Ad esempio:cd <location-of-cmakelists>/build && cmake ..
ComicSansMS

64
Dovrebbe esserci davvero una pulizia pulita. Chiunque abbia mai usato cmake, anche se ha l'abitudine di eseguire build di origine, ha accidentalmente eseguito cmake nella directory sbagliata ed è una seccatura nel culo pulire manualmente.
pavon,

24
@DevSolar Ma il contrario non è vero; solo perché un file non è sotto il controllo della versione non significa che è generato da cmake ed è sicuro da spazzare via. Scegliere quali file non controllati sono lavori in corso che è necessario conservare e quali sono cmake cruft è una seccatura, specialmente quando molti dei file cmake sono copie / nomi simili ai tuoi file.
pavone,

84

La FAQ ufficiale di CMake afferma:

Alcuni alberi di compilazione creati con gli autotools GNU hanno un target "make distclean" che pulisce la build e rimuove anche Makefile e altre parti del sistema di build generato. CMake non genera un target "make distclean" poiché i file CMakeLists.txt possono eseguire script e comandi arbitrari; CMake non ha modo di tracciare esattamente quali file vengono generati durante l'esecuzione di CMake. Fornire un obiettivo distinto darebbe agli utenti la falsa impressione che funzionerebbe come previsto. (CMake genera un obiettivo "Rendi pulito" per rimuovere i file generati dal compilatore e dal linker.)

Un target "make distclean" è necessario solo se l'utente esegue una build in-source. CMake supporta build in-source, ma incoraggiamo fortemente gli utenti ad adottare il concetto di build out-of-source. L'uso di un albero di generazione separato dall'albero di origine impedirà a CMake di generare qualsiasi file nell'albero di origine. Poiché CMake non modifica l'albero dei sorgenti, non è necessario un target distclean. Si può iniziare una nuova build eliminando l'albero di build o creando un albero di build separato.


Inizialmente, come introdotto e utilizzato dagli autotools GNU, l'obiettivo "distclean" ha lo scopo di rendere l'albero dei sorgenti pronto per il tar up e la creazione di una distribuzione tar. Gli utenti di tali file tar possono scaricare e decomprimere e quindi eseguire 'configura' e 'crea' senza la necessità degli autotools (aclocal, automake, autoconf, ecc.) Se estrapolassimo quello per creare, allora un 'make distclean' ci lascerebbe con un clean sorgente che può essere costruita senza aver installato cmake. Tuttavia, questo non funziona quando il generatore era un generatore a target singolo (come lo è il target 'make'), perché la configurazione con cmake avviene mentre
Carlo Wood il

... in esecuzione cmake. Fare una distribuzione che non può essere configurata, non fa nemmeno test della piattaforma ecc., È inutile. Quindi non esiste un obiettivo "distinto" per cmake. cmake deve esistere sulla macchina dell'utente finale.
Carlo Wood,

63

In questi giorni di Git ovunque, potresti dimenticare CMake e usarlo git clean -d -f -x, che rimuoverà tutti i file non sotto il controllo del codice sorgente.


14
Quella -xopzione però. Questo è un trucco eccellente del gitmestiere. Anche se io personalmente ancora fare un dry-run prima, git clean -d -f -x -n. Ogni tanto tengo un file di convenienza che utilizzo per un progetto con la cartella del progetto sotto gitcontrollo, ma non è qualcosa che voglio condividere con gli altri, quindi non git addlo faccio al progetto. Questo spazzerebbe via quel tipo di file se non fossi attento ad aggiungere -e <pattern>un'opzione. In quella nota, sarebbe bello se gitavesse un .gitcleanignorefile. :)
CivFan,

1
@CivFan puoi provare a usare chattr +i $filename(necessita dei permessi di root, dopo non puoi modificare il file). In questo modo git non sarà in grado di rimuovere quel file anche se prova a farlo come piace rm -f.
Ruslan,

3
Ciò presuppone build in-source, che deve essere evitato da solo.
Slava,

questa era una soluzione semplice (e non ricordo cosa significano quelle bandiere, ma è solo una macchina da sviluppo lol).
matanster

1
Ma che dire dei file appena aggiunti che l'utente ha dimenticato git add?
yugr,

50

L'ho cercato su Google per circa mezz'ora e l'unica cosa utile che mi è venuta in mente è stata invocare l' findutilità:

# 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

Inoltre, assicurati di invocare make clean(o qualunque sia il generatore CMake che stai utilizzando) prima di quello.

:)


36
Consiglio di non utilizzare questo approccio se la directory in cui si sta lavorando è sotto il controllo della versione: quando ho provato questo approccio con svn ho rimosso alcuni dei file di lavoro dei repository.
ripresa il

8
Potrebbero esserci altri file corrispondenti a cmake, quindi questo non è un approccio universale. Questo dovrebbe fare: rm -rf CMakeFiles; rm -rf CMakeCache.txt; rm -rf cmake_install.cmake;
honza_p,

1
Vorrei rimuovere -exec rm -rf {} \ + e usare solo -delete.
Edgar Aroutiounian,

3
Sottovalutato, poiché questo comando può potenzialmente eliminare alcuni file utente. Preferisco il comando honza_p, non molto più lungo, più semplice e meno rischioso.
Adrien Descamps

1
@AdrienDescamps: tranne per il fatto che lascia ancora spazzatura correlata a cmake nelle sottodirectory. Stavo facendo rm -rf CMakeFiles ; rm -rf */CMakeFiles ; rm -rf */*/CMakeFiles ; rm -rf */*/*/CMakeFilese non avevo ancora finito ...
SF.

35

Puoi usare qualcosa come:

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)

Di solito creo un comando "make clean-all" aggiungendo una chiamata a "make clean" nell'esempio precedente:

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

Non provare ad aggiungere il target "pulito" come dipendenza:

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

Perché "pulito" non è un vero obiettivo in CMake e questo non funziona.

Inoltre, non dovresti usare questo "clean-cmake-files" come dipendenza da qualsiasi cosa:

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

Perché, se lo fai, tutti i file CMake verranno cancellati prima del completamento di clean-all, e make ti genererà un errore nella ricerca di "CMakeFiles / clean-all.dir / build.make". Di conseguenza, non è possibile utilizzare il comando clean-all prima di "qualunque cosa" in qualsiasi contesto:

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

Neanche questo funziona.


C'è un modo per riempire automaticamente cmake_generated? Forse, combinando questo con la risposta di yuri.makarevich? Attualmente, questo non rimuoverà i file nelle sottodirectory di $ {CMAKE_BINARY_DIR}.
Foxcub,

Non funziona con Ninja o Visual Studio. Non consiglierei un simile approccio.
usr1234567

23

La semplice emissione rm CMakeCache.txtfunziona anche per me.


1
Anche l'eliminazione delle variabili correlate in CMakeCache.txt funziona anche per me.
Yorkwar,

L'eliminazione di CMakeCache.txt e quindi l'esecuzione di "cmake --build / build-path" causa "Errore: impossibile caricare la cache".
nenchev,

1
@nenchev devi correre di cmake /build-pathnuovo.
Samaursa,

@Samaursa cmake --build esegue nuovamente cmake quando necessario, questo metodo rompe la directory di build e cmake si lamenta. La mia risposta più in basso ti dice di eliminare la directory CMakeFiles /, che provoca una ricostruzione pulita e cmake per eseguire nuovamente automaticamente.
nenchev,

2
@nenchev Capisco cosa intendi e sono d'accordo.
Samaursa,

9

Forse è un po 'datato, ma poiché questo è il primo successo quando vai su Google cmake clean, aggiungerò questo:

Dal momento che è possibile avviare una build nella directory build con una destinazione specificata con

cmake --build . --target xyz

puoi ovviamente correre

cmake --build . --target clean

per eseguire la cleandestinazione nei file di build generati.


8

Sono d'accordo che la build out-of-source è la risposta migliore. Ma per le volte in cui devi solo fare una build in-source, ho scritto uno script Python disponibile qui , che:

  1. Esegue "rendere pulito"
  2. Rimuove file specifici generati da CMake nella directory di livello superiore come CMakeCache.txt
  3. Per ogni sottodirectory che contiene una directory CMakeFiles, rimuove CMakeFiles, Makefile, cmake_install.cmake.
  4. Rimuove tutte le sottodirectory vuote.

Grazie per quello Vorrei aggiungere una riga alla tua sceneggiatura che tace makequando non c'è Makefilepresente a causa di una pulizia preliminare (ovvero, rende questa sceneggiatura idempotente). Basta aggiungere la linea (correttamente distanziata): if os.path.isfile(os.path.join(directory,'Makefile')):subito prima della linea 24: args = [e, naturalmente, rientrare il resto del corpo della funzione dopo la linea appena aggiunta. Questo eseguirà un solo make ... cleanse a Makefileè presente nella directory corrente da pulire. Altrimenti, la sceneggiatura è perfetta!
Michael Goldshteyn,

4

Una soluzione che ho trovato di recente è quella di combinare il concetto di build out-of-source con un wrapper Makefile.

Nel mio file CMakeLists.txt di primo livello, includo quanto segue per prevenire build 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()

Quindi, creo un Makefile di livello superiore e includo quanto segue:

# -----------------------------------------------------------------------------
# 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 destinazione predefinita allviene chiamata digitando makee invoca la destinazione ./build/Makefile.

La prima cosa che la destinazione ./build/Makefilefa è creare la builddirectory usando $(MKDIR), che è una variabile per mkdir -p. La directory buildè dove eseguiremo la nostra build out-of-source. Forniamo l'argomento -pper garantire che mkdirnon ci urli per aver cercato di creare una directory che potrebbe già esistere.

La seconda cosa che la destinazione ./build/Makefilefa è cambiare le directory nella builddirectory e invocare cmake.

Tornando al alltarget, invochiamo $(MAKE) -C build, dove $(MAKE)viene generata automaticamente una variabile Makefile make. make -Ccambia la directory prima di fare qualsiasi cosa. Pertanto, l'utilizzo $(MAKE) -C buildequivale a fare cd build; make.

Per riassumere, chiamare questo wrapper Makefile con make allo makeequivale a fare:

mkdir build
cd build
cmake ..
make 

Il target distcleaninvoca cmake .., quindi make -C build clean, e infine, rimuove tutto il contenuto dalla builddirectory. Credo che sia esattamente quello che hai richiesto nella tua domanda.

L'ultima parte del Makefile valuta se la destinazione fornita dall'utente è o meno distclean. In caso contrario, cambierà directory in buildprima di invocarlo. Questo è molto potente perché l'utente può digitare, per esempio make clean, e il Makefile lo trasformerà in un equivalente di cd build; make clean.

In conclusione, questo wrapper Makefile, in combinazione con una configurazione CMake build out-of-source obbligatoria, lo rende in modo che l'utente non debba mai interagire con il comando cmake. Questa soluzione fornisce anche un metodo elegante per rimuovere tutti i file di output di CMake dalla builddirectory.

PS Nel Makefile, usiamo il prefisso @per sopprimere l'output da un comando shell e il prefisso @-per ignorare gli errori da un comando shell. Quando viene utilizzato rmcome parte della distcleandestinazione, il comando restituirà un errore se i file non esistono (potrebbero essere stati eliminati già utilizzando la riga di comando con rm -rf build, o non sono mai stati generati in primo luogo). Questo errore di restituzione forzerà l'uscita del nostro Makefile. Usiamo il prefisso @-per impedirlo. È accettabile se un file è già stato rimosso; vogliamo che il nostro Makefile continui e rimuova il resto.

Un'altra cosa da notare: questo Makefile potrebbe non funzionare se si utilizza un numero variabile di variabili CMake per creare il proprio progetto, ad esempio cmake .. -DSOMEBUILDSUSETHIS:STRING="foo" -DSOMEOTHERBUILDSUSETHISTOO:STRING="bar". Questo Makefile presuppone che invochi CMake in modo coerente, digitando cmake ..o fornendo cmakeun numero coerente di argomenti (che puoi includere nel tuo Makefile).

Infine, credito dove è dovuto il credito. Questo wrapper Makefile è stato adattato dal Makefile fornito dal modello di progetto di applicazione C ++ .


4

Naturalmente, le build out-of-source sono il metodo di partenza per Unix Makefile, ma se si utilizza un altro generatore come Eclipse CDT, si preferisce creare in-source. In tal caso, dovrai eliminare manualmente i file CMake. Prova questo:

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

O se hai abilitato globstar con shopt -s globstar, prova invece questo approccio meno disgustoso:

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

La mia scelta di ieri è stata la clonazione del repository in una nuova cartella, aggiornare CMakeLists.txt per creare dalla sottocartella build. Ci è voluto un po 'più di tempo rispetto a quei comandi, ma ho dovuto farlo una volta sola :)
Tien Do

4

prova ad usare: cmake --clean-first path-of-CMakeLists.txt-file -B output-dir

--clean-first: costruisci prima il bersaglio, poi costruisci.
(Per pulire solo, usare --target clean.)


Quella schermata mostra solo il testo . Eppure ne fai uno screenshot, rompendo la risposta per chiunque venga qui con uno screen reader. Rilascia l'immagine, copia e incolla il testo e impiega 1 minuto per formattare correttamente l'input.
GhostCat,

3

Nel caso in cui si passino i -Dparametri in CMake durante la generazione dei file di build e non si desideri eliminare l'intera directory build /:

Basta eliminare la directory CMakeFiles / all'interno della directory di compilazione.

rm -rf CMakeFiles/
cmake --build .

Ciò provoca la riesecuzione di CMake e la rigenerazione dei file di sistema di compilazione. Anche la tua build inizierà da zero.


1

Per semplificare la pulizia quando si utilizza la build "out of source" (ovvero la compilazione nella builddirectory), utilizzo il seguente 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

Ogni volta che devi ripulire, dovresti procurarti questo script dalla builddirectory:

. cmake-clean-build

Bello e sicuro. Dato che potresti avere la directory di build aperta nel file manager, ti suggerisco di sostituire la cd .. ; rm ; mkdir ; cdsequenza con cd .. ; rm -rf build/*.
Mostafa Farzán,

0

Se si dispone di definizioni personalizzate e si desidera salvarle prima della pulizia, eseguire quanto segue nella directory di generazione:

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

Quindi crea una nuova directory di build (o rimuovi la vecchia directory di build e ricreala) ed infine esegui cmakecon gli argomenti che otterrai con lo script sopra.


0

Se corri

cmake .

rigenera i file CMake. Ciò è necessario se si aggiunge un nuovo file a una cartella di origine selezionata da * .cc, ad esempio.

Anche se questo non è un "clean" di per sé, "ripulisce" i file CMake rigenerando le cache.


Non pulisce wrt. lo stato della compilazione: se sono stati compilati 500 file su 1200, dopo "cmake". continuerà con gli ultimi 700 file.
Peter Mortensen,

0

Uso il seguente script di shell per tali scopi:

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

Se si utilizza Windows, utilizzare Cygwin per questo script.


0

È divertente vedere che questa domanda ottiene così tante attenzioni e soluzioni complicate, il che in effetti mostra un dolore a non avere un metodo pulito con Cmake.

Bene, puoi sicuramente cd buildfare il tuo lavoro, quindi farlo rm -rf *quando devi pulirlo. Tuttavia, rm -rf *è un comando pericoloso dato che molte persone spesso non sono consapevoli della directory in cui si trovano.

Se tu cd .., rm -rf builde poi mkdir builde poi cd build, è semplicemente troppa digitazione.

Quindi una buona soluzione è quella di rimanere fuori dalla cartella build e dire a cmake il percorso:
configurare: cmake -B build
costruire: cmake --build build
pulire: rm -rf build
ricreare la cartella build: non è nemmeno necessario mkdir build, basta configurarlo con cmake -B builde cmake lo creerà


0

cmakeprincipalmente cucina a Makefile, si potrebbe aggiungere rmal PHONY pulito .

Per esempio,

[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

-1

Ho questo nel mio file rc shell ( .bashrc, .zshrc):

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

Dovresti usarlo solo per build out-of-source. Supponiamo che tu abbia una directory chiamata build/per questo scopo. Quindi devi solo scappare t-cmake-cleanda esso.


-3

Ho usato la risposta di zsxwing con successo per risolvere il seguente problema:

Ho una fonte che costruisco su più host (su una scheda Raspberry Pi Linux, su una macchina virtuale VMware Linux, ecc.)

Ho uno script Bash che crea directory temporanee basate sul nome host della macchina in questo modo:

# 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

-8

Creare una directory di build temporanea, ad esempio build_cmake. Quindi tutti i tuoi file di build saranno all'interno di questa cartella.

Quindi nel tuo file CMake principale aggiungi il comando seguente.

add_custom_target(clean-all
    rm -rf *
)

Quindi durante la compilazione fare

cmake ..

E per pulire fai:

make clean-all

11
bel modo di rimuovere tutto il tuo progetto se qualcuno costruirà accidentalmente in-source anziché out-of-source

3
sì. questo metodo dovrebbe essere usato solo con "build out of source"
Natesh,

6
Terribile raccomandazione. Non dovrebbe esistere come risposta.
Anne van Rossum,

@AnnevanRossum d'accordo
zevarito
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.