Eine Lösung, die ich kürzlich gefunden habe, ist die Kombination des Out-of-Source-Build-Konzepts mit einem Makefile-Wrapper.
In meiner CMakeLists.txt-Datei auf oberster Ebene füge ich Folgendes ein, um In-Source-Builds zu verhindern:
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()
Dann erstelle ich ein Makefile auf oberster Ebene und füge Folgendes ein:
# -----------------------------------------------------------------------------
# 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
Das Standardziel all
wird aufgerufen durch Eingabe von make
und ruft das Ziel auf ./build/Makefile
.
Das erste, was das Ziel ./build/Makefile
ist die Erstellung des build
Verzeichnis mit $(MKDIR)
die eine Variable ist für mkdir -p
. Das Verzeichnis build
ist der Ort, an dem wir unseren Out-of-Source-Build durchführen werden. Wir geben das Argument -p
um sicherzustellen, dass mkdir
schreit uns nicht an, weil wir versuchen, ein Verzeichnis zu erstellen, das vielleicht schon existiert.
Die zweite Sache, die das Ziel ./build/Makefile
ist es, die Verzeichnisse in die build
Verzeichnis und rufen Sie cmake
.
Zurück zum all
Ziel, wir rufen auf $(MAKE) -C build
donde $(MAKE)
ist eine Makefile-Variable, die automatisch für make
. make -C
ändert das Verzeichnis, bevor Sie etwas tun. Daher ist die Verwendung von $(MAKE) -C build
ist gleichbedeutend mit cd build; make
.
Zusammenfassend lässt sich sagen, dass der Aufruf dieses Makefile-Wrappers mit make all
o make
ist gleichbedeutend mit tun:
mkdir build
cd build
cmake ..
make
Das Ziel distclean
ruft auf. cmake ..
dann make -C build clean
und löscht schließlich alle Inhalte aus dem Ordner build
Verzeichnis. Ich glaube, das ist genau das, was Sie in Ihrer Frage gefordert haben.
Der letzte Teil des Makefiles prüft, ob das vom Benutzer angegebene Ziel ein Ziel ist oder nicht distclean
. Wenn nicht, werden die Verzeichnisse in build
bevor sie aufgerufen wird. Dies ist sehr leistungsfähig, weil der Benutzer zum Beispiel eingeben kann, make clean
und das Makefile wandelt dies in eine Entsprechung von cd build; make clean
.
Zusammenfassend lässt sich sagen, dass dieser Makefile-Wrapper in Kombination mit einer obligatorischen CMake-Konfiguration zur Erstellung von Out-of-Source-Dateien dafür sorgt, dass der Benutzer nie mit dem Befehl cmake
. Diese Lösung bietet auch eine elegante Methode zum Entfernen aller CMake-Ausgabedateien aus dem build
Verzeichnis.
P.S. Im Makefile verwenden wir das Präfix @
um die Ausgabe eines Shell-Befehls zu unterdrücken, und das Präfix @-
um Fehler eines Shell-Befehls zu ignorieren. Bei der Verwendung von rm
als Teil der distclean
Ziel, gibt der Befehl einen Fehler zurück, wenn die Dateien nicht existieren (sie wurden möglicherweise bereits über die Befehlszeile mit rm -rf build
oder sie wurden gar nicht erst erzeugt). Dieser Rückgabefehler zwingt unser Makefile zum Beenden. Wir verwenden das Präfix @-
um das zu verhindern. Es ist akzeptabel, wenn eine Datei bereits entfernt wurde; wir wollen, dass unser Makefile weiterläuft und den Rest entfernt.
Ein weiterer Hinweis: Dieses Makefile funktioniert möglicherweise nicht, wenn Sie z.B. eine variable Anzahl von CMake-Variablen verwenden, um Ihr Projekt zu bauen, cmake .. -DSOMEBUILDSUSETHIS:STRING="foo" -DSOMEOTHERBUILDSUSETHISTOO:STRING="bar"
. Dieses Makefile geht davon aus, dass Sie CMake auf eine konsistente Weise aufrufen, entweder durch Eingabe von cmake ..
oder durch die Bereitstellung cmake
eine konsistente Anzahl von Argumenten (die Sie in Ihr Makefile aufnehmen können).
Abschließend möchte ich noch erwähnen, dass Anerkennung fällig ist. Dieser Makefile-Wrapper wurde an das Makefile angepasst, das von der C++ Anwendung Projektvorlage .