Rozwiązaniem, które ostatnio znalazłem, jest połączenie koncepcji kompilacji out-of-source z opakowaniem Makefile.
W moim pliku CMakeLists.txt najwyższego poziomu, ja zaliczyć do zapobiegać już w źródle buduje:
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()
Następnie tworzę najwyższego poziomu Makefile i zawierać następujące elementy:
# -----------------------------------------------------------------------------
# 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
Domyślny cel all
jest wywoływany przez wpisanie make
i wywołuje obiekt docelowy ./build/Makefile
.
Pierwszą rzeczą cel ./build/Makefile
robi jest stworzenie katalogu build
korzystając $(MKDIR)
, która jest zmienna dla mkdir -p
. Katalog build
jest miejscem, w którym wykonamy naszą kompilację poza źródłem. Podajemy argument -p
, aby upewnić się, że mkdir
nie krzyczy na nas za próbę utworzenia katalogu, który może już istnieć.
Drugą rzeczą, do której zmierza cel ./build/Makefile
, jest zmiana katalogu na katalog build
i wywołanie cmake
.
Wracając do celu all
, wywołujemy $(MAKE) -C build
, gdzie $(MAKE)
jest automatycznie przekształcaną zmienną Makefile dla make
. make -C
zmienia katalog przed zrobieniem czegokolwiek. Dlatego używanie $(MAKE) -C build
jest równoważne wykonaniu cd build; make
.
Podsumowując, nazywając ten Makefile owijkę z make all
lub make
jest równoważna robi:
mkdir build
cd build
cmake ..
make
Cel distclean
wywołuje cmake ..
, następnie make -C build clean
i wreszcie usuwa całą zawartość z katalogu build
. Uważam, że jest to dokładnie to, o co prosiłeś w swoim pytaniu.
Ostatni fragment Makefile ocenia, czy podany przez użytkownika cel jest lub nie jest distclean
. Jeśli nie, zmieni katalogi na build
przed wywołaniem. Jest to bardzo potężne, ponieważ użytkownik może wpisać na przykład make clean
, a plik Makefile przekształci go w odpowiednik cd build; make clean
.
Podsumowując, to opakowanie Makefile, w połączeniu z obowiązkową konfiguracją CMake, nie powoduje interakcji użytkownika z poleceniem cmake
. To rozwiązanie zapewnia również elegancką metodę usuwania wszystkich plików wyjściowych CMake z katalogu build
.
P.S. W pliku Makefile używamy prefiksu @
, aby wyłączyć wyjście z polecenia powłoki, a prefiks @-
zignorować błędy z polecenia powłoki. Podczas korzystania z rm
jako części docelowej distclean
, polecenie zwróci błąd, jeśli pliki nie istnieją (mogły zostać usunięte przy użyciu wiersza polecenia z rm -rf build
lub nigdy nie zostały wygenerowane w pierwszej kolejności). Ten błąd powrotu zmusi nasz plik Makefile do wyjścia. Używamy prefiksu @-
, aby temu zapobiec. Dopuszczalne jest, jeśli plik został już usunięty; chcemy, aby nasz plik Makefile działał dalej i usuwał resztę.
Inna sprawa: ten plik Makefile może nie działać, jeśli do zbudowania projektu używasz zmiennej liczby zmiennych CMake, na przykład cmake .. -DSOMEBUILDSUSETHIS:STRING="foo" -DSOMEOTHERBUILDSUSETHISTOO:STRING="bar"
. Ten plik Makefile zakłada, że wywołujesz CMake w spójny sposób, wpisując cmake ..
lub podając cmake
spójną liczbę argumentów (które możesz uwzględnić w pliku Makefile).
Wreszcie, gdy kredyt jest należny. To opakowanie Makefile zostało zaadaptowane z pliku Makefile dostarczonego przez C++ Application Project Template. Ta wiadomość została oryginalnie opublikowana here. Myślałem, że to odnosi się również do twojej sytuacji.
Mam taką samą architekturę projektu jak ty. Moja "kompilacja" jest zawsze tutaj. Osobiście uważam, że pisanie _cmake .._ nie jest tak wielką sprawą. – Offirmo