Procurando por um comando 'cmake clean' para limpar a saída do CMake


419

Assim como make cleanexclui todos os arquivos que um makefile produziu, eu gostaria de fazer o mesmo com o CMake. Com demasiada frequência, eu me pego examinando manualmente diretórios, removendo arquivos como cmake_install.cmakee CMakeCache.txt, e as CMakeFilespastas.

Existe um comando como cmake cleanremover todos esses arquivos automaticamente? Idealmente, isso deve seguir a estrutura recursiva definida no CMakeLists.txtarquivo do diretório atual .

Respostas:


487

Não existe cmake clean.

Normalmente, construo o projeto em uma única pasta como "build". Então, se eu quiser make clean, posso apenas rm -rf build.

A pasta "build" no mesmo diretório da raiz "CMakeLists.txt" é geralmente uma boa opção. Para criar seu projeto, basta fornecer ao cmake a localização do CMakeLists.txt como argumento. Por exemplo: cd <location-of-cmakelists>/build && cmake ... (De @ComicSansMS)


101
Isso é chamado de "compilação fora da fonte" e deve ser o caminho preferido. Evita conflitos de nome e similares
Arne

17
+1 para compilações fora da fonte. Isso se torna vital ao criar várias arquiteturas. Por exemplo, você não pode construir binários de 64 bits e 32 bits com uma compilação na fonte, pois isso requer duas hierarquias de cache CMake separadas.
ComicSansMS

9
Você pode colocar a pasta em qualquer lugar que desejar, mas uma pasta de compilação no mesmo diretório que o CMakeLists.txt raiz geralmente é uma boa opção. Para criar você simplesmente dê ao cmake a localização do CMakeLists.txt como argumento. Por exemplo:cd <location-of-cmakelists>/build && cmake ..
ComicSansMS

64
Realmente deveria haver uma limpeza. Todo mundo que já usou o cmake, mesmo que tenha o hábito de criar versões fora do código-fonte, executou o cmake acidentalmente no diretório errado e é uma grande dor de cabeça limpar isso manualmente.
Pavon 19/05/2015

24
@ DevSolar Mas o inverso não é verdadeiro; só porque um arquivo não está sob controle de versão não significa que ele é gerado pelo cmake e é seguro removê-lo. Escolher quais arquivos não-versionados são trabalhos em andamento que você precisa manter e quais são cmake cruft é uma dor, especialmente quando muitos dos arquivos cmake são cópias / nomes semelhantes aos seus arquivos.
Pavon 25/08

84

O FAQ oficial do CMake declara:

Algumas árvores de construção criadas com as ferramentas automáticas do GNU têm um destino "make distclean" que limpa a construção e também remove Makefiles e outras partes do sistema de construção gerado. O CMake não gera um destino "make distclean" porque os arquivos CMakeLists.txt podem executar scripts e comandos arbitrários; O CMake não tem como rastrear exatamente quais arquivos são gerados como parte da execução do CMake. O fornecimento de um destino distinto daria aos usuários a falsa impressão de que funcionaria conforme o esperado. (O CMake gera um destino "limpar" para remover os arquivos gerados pelo compilador e vinculador.)

Um destino "make distclean" é necessário apenas se o usuário executar uma compilação na fonte. O CMake suporta compilações na fonte, mas recomendamos fortemente que os usuários adotem a noção de compilação fora da fonte. O uso de uma árvore de compilação separada da árvore de origem impedirá o CMake de gerar arquivos na árvore de origem. Como o CMake não altera a árvore de origem, não há necessidade de um destino distclean. Pode-se iniciar uma nova construção excluindo a árvore de construção ou criando uma árvore de construção separada.


Originalmente, como introduzido e usado pelas ferramentas automáticas do GNU, o destino 'distclean' tem o objetivo de preparar a árvore de origem para tar e criar uma distribuição tar. Os usuários de um arquivo tar podem baixar e descompactar e, em seguida, executar 'configure' e 'make' sem precisar das ferramentas automáticas (aclocal, automake, autoconf, etc). fonte que pode ser criada sem ter o cmake instalado. No entanto, isso não funciona quando o gerador era um gerador de destino único (como é o destino 'make'), porque a configuração com o cmake acontece enquanto
Carlo Wood

... executando o cmake. Fazer uma distribuição que não pode ser configurada, nem faz testes de plataforma etc, é inútil. Portanto, não existe um alvo 'distclean' para cmake. É necessário que o cmake exista na máquina do usuário final.
Carlo Wood

63

Nestes dias do Git em todos os lugares, você pode esquecer o CMake e o uso git clean -d -f -x, que removerá todos os arquivos que não estão sob controle de origem.


14
Essa -xopção embora. Esse é um excelente truque do gitcomércio. Embora eu pessoalmente ainda faça um teste a seco primeiro git clean -d -f -x -n. De vez em quando, mantenho um arquivo de conveniência que uso para um projeto com a pasta do projeto sob gitcontrole, mas não é algo que eu queira compartilhar com outras pessoas, por isso não o faço git addno projeto. Isso explodiria esse tipo de arquivo, se eu não tivesse o cuidado de adicionar uma -e <pattern>opção. Nessa nota, seria bom se gittivesse um .gitcleanignorearquivo. :)
CivFan

1
@CivFan você pode tentar usar chattr +i $filename(precisa de permissões de root, não permite modificar o arquivo depois disso). Dessa forma, o git não será capaz de remover esse arquivo, mesmo que tente fazê-lo dessa maneira rm -f.
Ruslan #

3
Isso pressupõe compilações na fonte, o que deve ser evitado por si só.
Slava

essa foi uma solução simples (e não me lembro o que essas bandeiras significam, mas é apenas uma máquina de desenvolvimento).
matanster

1
Hum, mas e os arquivos adicionados recentemente, que o usuário esqueceu git add?
Yugr 01/05/19

50

Pesquisei no Google por meia hora e a única coisa útil que surgiu foi invocar o findutilitário:

# 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

Além disso, não se esqueça de invocar make clean(ou qualquer outro gerador de CMake que você esteja usando) antes disso.

:)


36
Eu recomendaria não usar essa abordagem se o diretório em que você estiver trabalhando estiver sob controle de versão: quando tentei essa abordagem com o svn, ele removeu alguns arquivos de trabalho dos repositórios.
22613 bcumming

8
Pode haver outros arquivos correspondentes ao cmake, portanto, essa não é realmente uma abordagem universal. Isso deve fazer: rm -rf CMakeFiles; rm -rf CMakeCache.txt; rm -rf cmake_install.cmake;
Honda_p

1
Eu removeria -exec rm -rf {} \ + e apenas usaria -delete.
Edgar Aroutiounian

3
Voto negativo, pois esse comando pode potencialmente excluir alguns arquivos do usuário. Prefiro o comando honza_p, não muito mais longo, mais simples e menos arriscado.
Adrien Descamps

1
@AdrienDescamps: exceto que ainda deixa lixo relacionado ao cmake em subdiretórios. Eu estava fazendo rm -rf CMakeFiles ; rm -rf */CMakeFiles ; rm -rf */*/CMakeFiles ; rm -rf */*/*/CMakeFilese ainda não foi feito ...
SF.

35

Você pode 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, crio um comando "make clean-all" adicionando uma chamada para "make clean" no exemplo anterior:

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

Não tente adicionar o destino "limpo" como uma dependência:

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

Porque "limpo" não é um alvo real no CMake e isso não funciona.

Além disso, você não deve usar esses "arquivos de limpeza limpa" como dependência de qualquer coisa:

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

Porque, se você fizer isso, todos os arquivos do CMake serão apagados antes da limpeza completa, e o make exibirá um erro ao pesquisar "CMakeFiles / clean-all.dir / build.make". Consequentemente, você não pode usar o comando limpar tudo antes de "qualquer coisa" em qualquer contexto:

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

Isso também não funciona.


Existe uma maneira de preencher cmake_generated automaticamente? Talvez, combinando isso com a resposta de yuri.makarevich? Atualmente, isso não remove os arquivos nos subdiretórios de $ {CMAKE_BINARY_DIR}.
foxcub

Não funciona para o Ninja ou Visual studio. Eu não recomendaria essa abordagem.
precisa saber é o seguinte

23

Simplesmente emitir rm CMakeCache.txtobras para mim também.


1
Apenas excluir variáveis ​​relacionadas no CMakeCache.txt também funciona para mim.
Yorkwar

Excluir o CMakeCache.txt e executar 'cmake --build / build-path' causa 'Erro: não foi possível carregar o cache'.
Nenchev 28/10

1
@ nenchev você precisa executar cmake /build-pathnovamente.
Samaursa 29/10

@Samaursa cmake --build executa novamente o cmake quando necessário, esse método quebra o diretório de compilação e o cmake reclama. Minha resposta mais abaixo diz para você excluir o diretório CMakeFiles /, o que faz com que uma reconstrução limpa e o cmake sejam automaticamente executados novamente.
nenchev

2
@ nenchev Entendo o que você quer dizer e eu concordo.
Samaursa 30/10

9

Talvez esteja um pouco desatualizado, mas como esse é o primeiro hit quando você pesquisa no Google cmake clean, adicionarei isso:

Como você pode iniciar uma construção no diretório de construção com um destino especificado com

cmake --build . --target xyz

você pode, é claro, correr

cmake --build . --target clean

para executar o cleandestino nos arquivos de construção gerados.


8

Concordo que a compilação fora da fonte é a melhor resposta. Mas para os momentos em que você apenas precisa fazer uma compilação na fonte, escrevi um script Python disponível aqui , que:

  1. Executa "make clean"
  2. Remove arquivos específicos gerados pelo CMake no diretório de nível superior, como CMakeCache.txt
  3. Para cada subdiretório que contém um diretório CMakeFiles, ele remove CMakeFiles, Makefile, cmake_install.cmake.
  4. Remove todos os subdiretórios vazios.

Obrigado por isso. Gostaria de adicionar uma linha ao seu script que silencia makequando não há um Makefilepresente devido a uma limpeza anterior (ou seja, torna esse script idempotente). Basta adicionar a linha (espaçada corretamente): if os.path.isfile(os.path.join(directory,'Makefile')):logo antes da linha 24: args = [e, é claro, recuar o restante do corpo da função após a linha ter sido adicionada. Isso somente executará a make ... cleanse a Makefileestiver presente no diretório atual que está sendo limpo. Caso contrário, o script é perfeito!
Michael Goldshteyn

4

Uma solução que encontrei recentemente é combinar o conceito de compilação fora da fonte com um wrapper Makefile.

No meu arquivo CMakeLists.txt de nível superior, incluo o seguinte para evitar compilações na fonte:

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

Em seguida, crio um Makefile de nível superior e incluo o seguinte:

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

O destino padrão allé chamado digitando makee chama o destino./build/Makefile .

A primeira coisa que o destino ./build/Makefilefaz é criar o builddiretório usando $(MKDIR), que é uma variável mkdir -p. O diretório buildé onde executaremos nossa compilação fora da fonte. Nós fornecemos o argumento -ppara garantir que mkdirnão nos grite por tentar criar um diretório que já possa existir.

A segunda coisa que o destino ./build/Makefilefaz é alterar os diretórios para o builddiretório e invocar cmake.

De volta ao alldestino, chamamos $(MAKE) -C build, onde $(MAKE)é uma variável Makefile gerada automaticamente make. make -Caltera o diretório antes de fazer qualquer coisa. Portanto, usar $(MAKE) -C buildé equivalente a fazer cd build; make.

Para resumir, chamar esse wrapper Makefile com make allou makeé equivalente a:

mkdir build
cd build
cmake ..
make 

O destino distcleanchama cmake ..e make -C build clean, por fim, remove todo o conteúdo do builddiretório. Acredito que isso é exatamente o que você solicitou na sua pergunta.

A última parte do Makefile avalia se o destino fornecido pelo usuário é ou não distclean. Caso contrário, ele mudará os diretórios para buildantes de invocá-lo. Isso é muito poderoso, porque o usuário pode digitar, por exemplo make clean, eo Makefile transformará isso em um equivalente a cd build; make clean.

Concluindo, esse wrapper Makefile, em combinação com uma configuração obrigatória de CMake de compilação de origem, faz com que o usuário nunca precise interagir com o comando cmake. Essa solução também fornece um método elegante para remover todos os arquivos de saída do CMake do builddiretório.

PS No Makefile, usamos o prefixo @para suprimir a saída de um comando shell, e o prefixo @-para ignorar erros de um comando shell. Ao usarrm como parte do distcleandestino, o comando retornará um erro se os arquivos não existirem (eles podem já ter sido excluídos usando a linha de comando rm -rf buildou nunca foram gerados). Este erro de retorno forçará nosso Makefile a sair. Usamos o prefixo @-para impedir isso. É aceitável se um arquivo já tiver sido removido; queremos que o nosso Makefile continue e remova o resto.

Outro ponto a ser observado: esse Makefile pode não funcionar se você usar um número variável de variáveis ​​do CMake para criar seu projeto, por exemplo, cmake .. -DSOMEBUILDSUSETHIS:STRING="foo" -DSOMEOTHERBUILDSUSETHISTOO:STRING="bar" . Esse Makefile pressupõe que você invoque o CMake de maneira consistente, digitando cmake ..ou fornecendo cmakeum número consistente de argumentos (que você pode incluir no Makefile).

Finalmente, credite onde o crédito é devido. Esse wrapper Makefile foi adaptado do Makefile fornecido pelo C ++ Application Project Template .


4

Obviamente, as compilações fora da fonte são o método obrigatório para Makefiles do Unix, mas se você estiver usando outro gerador como o Eclipse CDT, ele prefere que você construa na fonte. Nesse caso, você precisará limpar os arquivos do CMake manualmente. Tente o seguinte:

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

Ou, se você ativou a globstar shopt -s globstar, tente esta abordagem menos repugnante:

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

Ontem, minha escolha foi clonar repo para uma nova pasta, atualizar CMakeLists.txt para criar a partir da subpasta build. Demorou um tempo pouco mais do que os comandos, mas eu tinha que fazer isso apenas uma vez :)
Tien Do

4

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

--clean-first: constrói o destino limpo primeiro e depois constrói.
(Para limpar apenas, use --target clean.)


Essa captura de tela mostra apenas texto . No entanto, você faz uma captura de tela, quebrando a resposta para quem vem aqui com um leitor de tela. Largue essa imagem, copie / cole o texto e gaste 1 minuto para formatar corretamente essa entrada.
GhostCat

3

No caso em que você passa -D parâmetros para o CMake ao gerar os arquivos de compilação e não deseja excluir o diretório / compilação inteiro:

Simplesmente exclua o diretório CMakeFiles / dentro do diretório de compilação.

rm -rf CMakeFiles/
cmake --build .

Isso faz com que o CMake seja executado novamente e os arquivos do sistema de compilação são regenerados. Sua compilação também começará do zero.


1

Para simplificar a limpeza ao usar a compilação "fora da fonte" (ou seja, você compila no builddiretório), eu uso o seguinte 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

Toda vez que você precisar limpar, você deve obter este script no builddiretório:

. cmake-clean-build

Agradável e seguro. Como você pode ter o diretório de construção aberto no gerenciador de arquivos, sugiro substituir a cd .. ; rm ; mkdir ; cdsequência por cd .. ; rm -rf build/*.
Mostafa Farzán 20/07/19

0

Se você possui definições personalizadas e deseja salvá-las antes da limpeza, execute o seguinte no diretório de construção:

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

Em seguida, crie um novo diretório de construção (ou remova o diretório de construção antigo e recriá-lo) e, finalmente, execute cmakeos argumentos que você obterá com o script acima.


0

Se você correr

cmake .

ele irá regenerar os arquivos do CMake. Isso é necessário se você adicionar um novo arquivo a uma pasta de origem selecionada por * .cc, por exemplo.

Embora isso não seja "limpo", ele "limpa" os arquivos do CMake, regenerando os caches.


Não limpa wrt. o estado da compilação: se 500 dos 1200 arquivos foram compilados, depois de "cmake". continuará apenas com os últimos 700 arquivos.
Peter Mortensen

0

Eu uso o seguinte script de shell para tais propósitos:

#!/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 você estiver usando o Windows, use o Cygwin para este script.


0

É engraçado ver que essa pergunta recebe muitas atenções e soluções complicadas, o que realmente mostra uma dor por não ter um método limpo com o cmake.

Bem, você pode definitivamente cd buildfazer o seu trabalho e depois fazer rm -rf *a limpeza. No entanto, rm -rf *é um comando perigoso, pois muitas pessoas geralmente não sabem em que diretório estão.

Se você cd .., de rm -rf buildvez em mkdir buildquando cd build, é muita digitação.

Portanto, uma boa solução é ficar de fora da pasta de compilação e dizer ao cmake o caminho:
para configurar: cmake -B build
para compilar: cmake --build build
para limpar: rm -rf build
para recriar a pasta de compilação: você nem precisa mkdir build, basta configurá-lo com o cmake -B buildcmake


0

cmakecozinha principalmente a Makefile, pode-se adicionar rmao PHONY limpo .

Por exemplo,

[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

Eu tenho isso no meu arquivo shell rc ( .bashrc, .zshrc):

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

Você deve usá-lo apenas para compilações fora da fonte. Digamos que você tenha um diretório nomeado build/para esse fim. Então você só precisa correr t-cmake-cleande dentro dele.


-3

Eu usei a resposta de zsxwing com sucesso para resolver o seguinte problema:

Tenho uma fonte que construo em vários hosts (em uma placa Raspberry Pi Linux, em uma máquina virtual VMware Linux etc.)

Eu tenho um script Bash que cria diretórios temporários com base no nome do host da 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

-8

Crie um diretório de construção temporário, por exemplo, build_cmake ,. Portanto, todos os seus arquivos de compilação estarão dentro desta pasta.

Em seguida, no seu arquivo principal do CMake, adicione o comando abaixo.

add_custom_target(clean-all
    rm -rf *
)

Portanto, durante a compilação, faça

cmake ..

E para limpar faça:

make clean-all

11
boa maneira de remover todo o seu projeto se alguém acidentalmente vai construir em-fonte em vez de out-of-source

3
sim. este método deve ser usado somente com "fora de construção de origem"
Natesh

6
Terrível recomendação. Não deve existir como resposta.
Anne van Rossum

@AnnevanRossum concorda
zevarito
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.