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 allwird durch Eingabe aufgerufen makeund ruft das Ziel auf ./build/Makefile.
Das erste, was das Ziel ./build/Makefiletut, ist das Erstellen des buildVerzeichnisses mit $(MKDIR), das eine Variable für ist mkdir -p. In diesem Verzeichnis führen buildwir unseren Out-of-Source-Build durch. Wir liefern das Argument, -pum sicherzustellen, dass mkdirwir nicht angeschrien werden, wenn wir versuchen, ein Verzeichnis zu erstellen, das möglicherweise bereits vorhanden ist.
Das zweite Ziel ./build/Makefiledes buildVerzeichnisses ist das Ändern der Verzeichnisse in das Verzeichnis und das Aufrufen cmake.
Zurück zum allZiel 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 buildgleichbedeutend mit der Ausführung cd build; make.
Zusammenfassend lässt sich sagen, dass das Aufrufen dieses Makefile-Wrappers mit make alloder makegleichbedeutend ist mit:
mkdir build
cd build
cmake ..
make
Das Ziel distcleanruft cmake ..dann auf make -C build cleanund entfernt schließlich alle Inhalte aus dem buildVerzeichnis. 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 buildvor dem Aufrufen in geändert . Dies ist sehr leistungsfähig, da der Benutzer beispielsweise make cleaneingeben 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 buildVerzeichnis.
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 rmals Teil des distcleanZiels 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 buildoder 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 cmakeeiner 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 .