Eine Lösung, die ich kürzlich gefunden habe, besteht darin, das Out-of-Source-Build-Konzept mit einem Makefile-Wrapper zu kombinieren.
In meiner CMakeLists.txt-Datei der obersten Ebene füge ich Folgendes hinzu, 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 der obersten Ebene und füge Folgendes hinzu:
# -----------------------------------------------------------------------------
# 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 durch Eingabe aufgerufen make
und ruft das Ziel auf ./build/Makefile
.
Das erste, was das Ziel ./build/Makefile
tut, ist das Erstellen des build
Verzeichnisses mit $(MKDIR)
, das eine Variable für ist mkdir -p
. In diesem Verzeichnis führen build
wir unseren Out-of-Source-Build durch. Wir liefern das Argument, -p
um sicherzustellen, dass mkdir
wir nicht angeschrien werden, wenn wir versuchen, ein Verzeichnis zu erstellen, das möglicherweise bereits vorhanden ist.
Das zweite Ziel ./build/Makefile
des build
Verzeichnisses ist das Ändern der Verzeichnisse in das Verzeichnis und das Aufrufen cmake
.
Zurück zum all
Ziel rufen wir auf $(MAKE) -C build
, wo $(MAKE)
eine Makefile-Variable automatisch für generiert wird make
. make -C
ändert das Verzeichnis, bevor Sie etwas tun. Daher ist die Verwendung $(MAKE) -C build
gleichbedeutend mit der Ausführung cd build; make
.
Zusammenfassend lässt sich sagen, dass das Aufrufen dieses Makefile-Wrappers mit make all
oder make
gleichbedeutend ist mit:
mkdir build
cd build
cmake ..
make
Das Ziel distclean
ruft cmake ..
dann auf make -C build clean
und entfernt schließlich alle Inhalte aus dem build
Verzeichnis. Ich glaube, genau das haben Sie in Ihrer Frage gefordert.
Der letzte Teil des Makefiles bewertet, ob das vom Benutzer bereitgestellte Ziel ist oder nicht distclean
. Wenn nicht, werden die Verzeichnisse build
vor dem Aufrufen in geändert . Dies ist sehr leistungsfähig, da der Benutzer beispielsweise make clean
eingeben kann und das Makefile dies in ein Äquivalent von umwandelt cd build; make clean
.
Zusammenfassend lässt sich sagen, dass dieser Makefile-Wrapper in Kombination mit einer obligatorischen Out-of-Source-Build-CMake-Konfiguration dafür sorgt, dass der Benutzer nie mit dem Befehl interagieren muss cmake
. Diese Lösung bietet auch eine elegante Methode zum Entfernen aller CMake-Ausgabedateien aus dem build
Verzeichnis.
PS 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 Verwendung rm
als Teil des distclean
Ziels gibt der Befehl einen Fehler zurück, wenn die Dateien nicht vorhanden sind (sie wurden möglicherweise bereits über die Befehlszeile mit gelöscht rm -rf build
oder wurden überhaupt nicht generiert). Dieser Rückgabefehler zwingt unser Makefile zum Beenden. Wir verwenden das Präfix @-
, um dies zu verhindern. Es ist akzeptabel, wenn eine Datei bereits entfernt wurde. Wir möchten, dass unser Makefile weitergeht und den Rest entfernt.
Beachten Sie außerdem Folgendes: Dieses Makefile funktioniert möglicherweise nicht, wenn Sie beispielsweise eine variable Anzahl von CMake-Variablen zum Erstellen Ihres Projekts verwenden cmake .. -DSOMEBUILDSUSETHIS:STRING="foo" -DSOMEOTHERBUILDSUSETHISTOO:STRING="bar"
. Bei diesem Makefile wird davon ausgegangen, dass Sie CMake auf konsistente Weise aufrufen, entweder durch Eingabe cmake ..
oder durch Bereitstellung cmake
einer konsistenten Anzahl von Argumenten (die Sie in Ihr Makefile aufnehmen können).
Schließlich Kredit, wo Kredit fällig ist. Dieser Makefile-Wrapper wurde aus dem Makefile angepasst, das von der C ++ - Anwendungsprojektvorlage bereitgestellt wird .