Jestem bardzo nowy w makefile i chcę tworzyć katalogi za pomocą makefile. Mój katalog projektu wygląda tak
+--Project
+--output
+--source
+Testfile.cpp
+Makefile
Chcę umieścić wszystkie obiekty i dane wyjściowe w odpowiednim folderze wyjściowym. Chcę stworzyć strukturę folderów, która będzie taka po kompilacji.
+--Project
+--output
+--debug (or release)
+--objs
+Testfile.o
+Testfile (my executable file)
+--source
+Testfile.cpp
+Makefile
Próbowałem z kilkoma opcjami, ale nie udało mi się. Proszę, pomóż mi tworzyć katalogi za pomocą make file. Przesyłam do rozważenia mój plik Makefile.
#---------------------------------------------------------------------
# Input dirs, names, files
#---------------------------------------------------------------------
OUTPUT_ROOT := output/
TITLE_NAME := TestProj
ifdef DEBUG
TITLE_NAME += _DEBUG
else
ifdef RELEASE
TITLE_NAME += _RELEASE
endif
endif
# Include all the source files here with the directory tree
SOURCES := \
source/TestFile.cpp \
#---------------------------------------------------------------------
# configs
#---------------------------------------------------------------------
ifdef DEBUG
OUT_DIR := $(OUTPUT_ROOT)debug
CC_FLAGS := -c -Wall
else
ifdef RELEASE
OUT_DIR := $(OUTPUT_ROOT)release
CC_FLAGS := -c -Wall
else
$(error no build type defined)
endif
endif
# Put objects in the output directory.
OUT_O_DIR := $(OUT_DIR)/objs
#---------------------------------------------------------------------
# settings
#---------------------------------------------------------------------
OBJS = $(SOURCES:.cpp=.o)
DIRS = $(subst /,/,$(sort $(dir $(OBJS))))
DIR_TARGET = $(OUT_DIR)
OUTPUT_TARGET = $(OUT_DIR)/$(TITLE_NAME)
CC_FLAGS +=
LCF_FLAGS :=
LD_FLAGS :=
#---------------------------------------------------------------------
# executables
#---------------------------------------------------------------------
MD := mkdir
RM := rm
CC := g++
#---------------------------------------------------------------------
# rules
#---------------------------------------------------------------------
.PHONY: all clean title
all: title
clean:
$(RM) -rf $(OUT_DIR)
$(DIR_TARGET):
$(MD) -p $(DIRS)
.cpp.o:
@$(CC) -c $< -o $@
$(OBJS): $(OUT_O_DIR)/%.o: %.cpp
@$(CC) -c $< -o $@
title: $(DIR_TARGET) $(OBJS)
Z góry dziękuję. Proszę, prowadź mnie, jeśli popełniłem jakieś błędy.
output/debug', needed by
katalogów docelowych . Stop.” Ale teraz nie mam zamiaru się tym martwić. będzie przestrzegać podstawowych zasad. :). Dziękuję za przewodnictwo. Uruchamiam "make" tylko z katalogu najwyższego poziomu.directories
bez powodowania, że będą zawsze przebudowywać ..Moim zdaniem katalogi nie powinny być traktowane jako cele twojego pliku makefile, ani w sensie technicznym, ani projektowym. Powinieneś utworzyć pliki i jeśli tworzenie pliku wymaga nowego katalogu, po cichu utwórz katalog w ramach reguły dla odpowiedniego pliku.
Jeśli celujesz w zwykły lub „wzorzysty” plik, po prostu użyj
make
wewnętrznej zmiennej$(@D)
, co oznacza „katalog, w którym znajduje się bieżący cel” (patrz z$@
określeniem celu). Na przykład,Następnie skutecznie robisz to samo: twórz katalogi dla wszystkich
$(OBJS)
, ale zrobisz to w mniej skomplikowany sposób.Ta sama polityka (pliki są celami, katalogi nigdy nie są) jest używana w różnych aplikacjach. Na przykład
git
system kontroli wersji nie przechowuje katalogów.Uwaga: jeśli zamierzasz go używać, może być przydatne wprowadzenie wygodnej zmiennej i wykorzystanie
make
reguł rozszerzania.źródło
Albo KISS.
Spowoduje to utworzenie wszystkich katalogów po przeanalizowaniu pliku Makefile.
źródło
$(info $(shell mkdir -p $(DIRS)))
bez polecenia$(info ...)
wynikmkdir
polecenia zostanie wklejony do pliku Makefile , co w najlepszym przypadku prowadzi do błędów składniowych. Do$(info ...)
połączenia zapewnia, że) błędy (jeśli w ogóle) są widoczne dla użytkownika, oraz b) że rozszerza wywołanie funkcji do niczego.make
in i poza sobą, obsługuje katalogi docelowe tak samo, jak cele plików. Tak więc łatwo jest napisać takie zasady:Jedynym problemem jest to, że sygnatura czasowa katalogów zależy od tego, co zostanie zrobione z plikami wewnątrz. W przypadku powyższych reguł prowadzi to do następującego wyniku:
To zdecydowanie nie jest to, czego chcesz. Za każdym razem, gdy dotykasz pliku, dotykasz również katalogu. A ponieważ plik zależy od katalogu, w konsekwencji plik wydaje się być nieaktualny, co wymusza jego odbudowę.
Możesz jednak łatwo przerwać tę pętlę, nakazując make ignorować sygnaturę czasową katalogu . Odbywa się to poprzez zadeklarowanie katalogu jako wymaganie wstępne tylko do zamówienia:
To poprawnie daje:
TL; DR:
Napisz regułę, aby utworzyć katalog:
A cele dla zawartości zależą tylko od kolejności katalogu:
źródło
touch
modyfikację jakichkolwiek danych statystycznych w katalogu nadrzędnym? To nie ma dla mnie sensu. Czas m katalogu zależy tylko od nazw plików, które zawiera. Nie udało mi się odtworzyć Twojego problemu.Wszystkie rozwiązania, w tym zaakceptowane, mają pewne problemy, zgodnie z ich komentarzami. Akceptowane odpowiedź przez @ jonathan-Leffler jest już dość dobre, ale nie bierze pod wynika, że wymagania są niekoniecznie muszą być zbudowany w kolejności (w czasie
make -j
na przykład). Jednak po prostu przeniesieniedirectories
warunku wstępnego zall
naprogram
prowokuje odbudowę przy każdym przebiegu AFAICT. Poniższe rozwiązanie nie ma tego problemu, a AFAICS działa zgodnie z przeznaczeniem.źródło
Właśnie wymyśliłem dość rozsądne rozwiązanie, które pozwala zdefiniować pliki do zbudowania i automatycznie tworzyć katalogi. Najpierw zdefiniuj zmienną,
ALL_TARGET_FILES
która przechowuje nazwę każdego pliku, który będzie tworzony przez makefile. Następnie użyj następującego kodu:Oto jak to działa. Definiuję funkcję,
depend_on_dir
która przyjmuje nazwę pliku i generuje regułę, która uzależnia plik od katalogu, który go zawiera, a następnie definiuje regułę tworzenia tego katalogu, jeśli to konieczne. Następnie używamforeach
docall
tej funkcji na każdej nazwy pliku ieval
wynik.Zauważ, że będziesz potrzebować wersji GNU make, która obsługuje
eval
, która moim zdaniem jest wersją 3.81 i wyższą.źródło
biorąc pod uwagę, że jesteś nowicjuszem, powiedziałbym, że nie próbuj jeszcze tego robić. jest to zdecydowanie możliwe, ale niepotrzebnie skomplikuje twój plik Makefile. trzymaj się prostych sposobów, dopóki nie poczujesz się bardziej komfortowo z marką.
to powiedziawszy, jednym ze sposobów budowania w katalogu innym niż katalog źródłowy jest VPATH ; wolę zasady wzorców
źródło
Niezależność systemu operacyjnego jest dla mnie krytyczna, więc
mkdir -p
nie wchodzi w grę. Stworzyłem tę serię funkcji, które służąeval
do tworzenia docelowych katalogów z wymaganiem wstępnym w katalogu nadrzędnym. Ma to tę zaletę, żemake -j 2
będzie działać bez problemu, ponieważ zależności są poprawnie określone.Na przykład uruchomienie powyższego spowoduje:
źródło
Zobacz https://www.oreilly.com/library/view/managing-projects-with/0596006101/ch12.html
Ponieważ używam Ubuntu, musiałem również dodać to na górze mojego pliku Makefile:
źródło