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 all
viene chiamata digitando make
e invoca la destinazione ./build/Makefile
.
La prima cosa che la destinazione ./build/Makefile
fa è creare la build
directory usando $(MKDIR)
, che è una variabile per mkdir -p
. La directory build
è dove eseguiremo la nostra build out-of-source. Forniamo l'argomento -p
per garantire che mkdir
non ci urli per aver cercato di creare una directory che potrebbe già esistere.
La seconda cosa che la destinazione ./build/Makefile
fa è cambiare le directory nella build
directory e invocare cmake
.
Tornando al all
target, invochiamo $(MAKE) -C build
, dove $(MAKE)
viene generata automaticamente una variabile Makefile make
. make -C
cambia la directory prima di fare qualsiasi cosa. Pertanto, l'utilizzo $(MAKE) -C build
equivale a fare cd build; make
.
Per riassumere, chiamare questo wrapper Makefile con make all
o make
equivale a fare:
mkdir build
cd build
cmake ..
make
Il target distclean
invoca cmake ..
, quindi make -C build clean
, e infine, rimuove tutto il contenuto dalla build
directory. 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 build
prima 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 build
directory.
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 rm
come parte della distclean
destinazione, 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 cmake
un 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 ++ .