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 .