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