Mam następujący plik makefile, którego używam do budowania programu (właściwie jądra), nad którym pracuję. To jest od zera i uczę się o tym procesie, więc nie jest doskonały, ale myślę, że w tym momencie jest wystarczająco potężny, jak na mój poziom doświadczenia w pisaniu makefile.
AS = nasm
CC = gcc
LD = ld
TARGET = core
BUILD = build
SOURCES = source
INCLUDE = include
ASM = assembly
VPATH = $(SOURCES)
CFLAGS = -Wall -O -fstrength-reduce -fomit-frame-pointer -finline-functions \
-nostdinc -fno-builtin -I $(INCLUDE)
ASFLAGS = -f elf
#CFILES = core.c consoleio.c system.c
CFILES = $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
SFILES = assembly/start.asm
SOBJS = $(SFILES:.asm=.o)
COBJS = $(CFILES:.c=.o)
OBJS = $(SOBJS) $(COBJS)
build : $(TARGET).img
$(TARGET).img : $(TARGET).elf
c:/python26/python.exe concat.py stage1 stage2 pad.bin core.elf floppy.img
$(TARGET).elf : $(OBJS)
$(LD) -T link.ld -o $@ $^
$(SOBJS) : $(SFILES)
$(AS) $(ASFLAGS) $< -o $@
%.o: %.c
@echo Compiling $<...
$(CC) $(CFLAGS) -c -o $@ $<
#Clean Script - Should clear out all .o files everywhere and all that.
clean:
-del *.img
-del *.o
-del assembly\*.o
-del core.elf
Moim głównym problemem związanym z tym plikiem makefile jest to, że kiedy modyfikuję plik nagłówkowy, który zawiera jeden lub więcej plików C, pliki C nie są odbudowywane. Mogę to dość łatwo naprawić, mając wszystkie moje pliki nagłówkowe jako zależności dla wszystkich moich plików C, ale to skutecznie spowodowałoby całkowitą przebudowę projektu za każdym razem, gdy zmieniłem / dodałem plik nagłówkowy, co nie byłoby zbyt wdzięczne.
To, czego chcę, to tylko pliki C. zawierają zmieniony przeze mnie plik nagłówkowy, zostały odbudowane, a cały projekt został ponownie połączony. Mogę wykonać linkowanie, powodując, że wszystkie pliki nagłówkowe są zależnościami celu, ale nie mogę dowiedzieć się, jak unieważnić pliki C, gdy dołączone pliki nagłówkowe są nowsze.
Słyszałem, że GCC ma kilka poleceń, które to umożliwiają (więc plik makefile może w jakiś sposób dowiedzieć się, które pliki należy odbudować), ale nie mogę za całe życie znaleźć rzeczywistego przykładu implementacji do obejrzenia. Czy ktoś może opublikować rozwiązanie, które umożliwi takie zachowanie w pliku makefile?
EDYCJA: Powinienem wyjaśnić, jestem zaznajomiony z koncepcją umieszczania poszczególnych celów i posiadania każdego celu. Aby wymagać plików nagłówkowych. To wymaga ode mnie edytowania pliku makefile za każdym razem, gdy umieszczam gdzieś plik nagłówkowy, co jest trochę uciążliwe. Szukam rozwiązania, które może samodzielnie wyprowadzić zależności pliku nagłówkowego, co jestem pewien, że widziałem w innych projektach.
źródło
Mógłbyś dodać polecenie `` make depend '', jak powiedzieli inni, ale dlaczego nie uzyskać gcc do tworzenia zależności i kompilacji w tym samym czasie:
Parametr „-MF” określa plik, w którym mają być przechowywane zależności.
Myślnik na początku „-include” mówi programowi Make, aby kontynuował, gdy plik .d nie istnieje (np. Przy pierwszej kompilacji).
Zauważ, że wydaje się, że w gcc jest błąd dotyczący opcji -o. Jeśli ustawisz nazwę pliku obiektu, aby powiedzieć,
obj/_file__c.o
wygenerowany_file_.d
nadal będzie zawierał_file_.o
, a nieobj/_file_c.o
.źródło
g++ -c -Wall -Werror -MM -MF main.d -o main.o main.cpp
Plik makefile wygenerował i uruchomił to: Otrzymałem plik main.d, ale main.o miał 0 bajtów. Jednak flaga -MMD wydaje się robić dokładnie to, co było wymagane. Tak więc moja robocza reguła plików stała się następująca:$(CC) -c $(CFLAGS) -MMD -o $@ $<
Jest to odpowiednik odpowiedzi Chrisa Dodda , ale używa innej konwencji nazewnictwa (i przypadkowo nie wymaga
sed
magii. Skopiowano z późniejszego duplikatu) .Jeśli używasz kompilatora GNU, kompilator może utworzyć dla Ciebie listę zależności. Fragment pliku Makefile:
Jest też narzędzie
makedepend
, ale nigdy nie podobało mi się tak bardzogcc -MM
źródło
SRCS
iOBJS
. Zwykle się z tym zgadzam, ale każdy powinien wiedzieć, co to jest.Będziesz musiał określić indywidualne cele dla każdego pliku C, a następnie wyświetlić plik nagłówkowy jako zależność. Nadal możesz używać swoich ogólnych celów, a
.h
potem po prostu umieścić zależności, na przykład:źródło
Zasadniczo musisz dynamicznie tworzyć reguły makefile, aby odbudować pliki obiektowe, gdy zmienią się pliki nagłówkowe. Jeśli używasz gcc i gnumake, jest to dość łatwe; po prostu wpisz coś takiego:
$(OBJDIR)/%.d: %.c $(CC) -MM -MG $(CPPFLAGS) $< | sed -e 's,^\([^:]*\)\.o[ ]*:,$(@D)/\1.o $(@D)/\1.d:,' >$@ ifneq ($(MAKECMDGOALS),clean) include $(SRCS:%.c=$(OBJDIR)/%.d) endif
w swoim pliku makefile.
źródło
Oprócz tego, co powiedział @mipadi, możesz również zbadać użycie opcji „
-M
” w celu wygenerowania rekordu zależności. Możesz nawet wygenerować je w osobnym pliku (np. „Depend.mk”), który następnie umieścisz w pliku makefile. Możesz też znaleźćmake depend
regułę „ ”, która edytuje plik makefile z poprawnymi zależnościami (hasła Google: „nie usuwaj tej linii” i zależą).źródło
Żadna z odpowiedzi nie pomogła. Np. Odpowiedź Martina Fido sugeruje, że gcc może utworzyć plik zależności, ale kiedy próbowałem, generował dla mnie puste (zero bajtów) pliki obiektowe bez żadnych ostrzeżeń ani błędów. To może być błąd gcc. jestem na
Oto mój kompletny plik Makefile, który działa dla mnie; jest to kombinacja rozwiązań + coś, o czym nikt inny nie wspominał (np. „reguła zastępowania sufiksów” określona jako .cc.o :):
CC = g++ CFLAGS = -Wall -g -std=c++0x INCLUDES = -I./includes/ # LFLAGS = -L../lib # LIBS = -lmylib -lm # List of all source files SRCS = main.cc cache.cc # Object files defined from source files OBJS = $(SRCS:.cc=.o) # # define the executable file MAIN = cache_test #List of non-file based targets: .PHONY: depend clean all ## .DEFAULT_GOAL := all # List of dependencies defined from list of object files DEPS := $(OBJS:.o=.d) all: $(MAIN) -include $(DEPS) $(MAIN): $(OBJS) $(CC) $(CFLAGS) $(INCLUDES) -o $(MAIN) $(OBJS) $(LFLAGS) $(LIBS) #suffix replacement rule for building .o's from .cc's #build dependency files first, second line actually compiles into .o .cc.o: $(CC) $(CFLAGS) $(INCLUDES) -c -MM -MF $(patsubst %.o,%.d,$@) $< $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $< clean: $(RM) *.o *~ $(MAIN) *.d
Zauważ, że użyłem .cc .. Powyższy plik Makefile można łatwo dostosować do plików .c.
Zwróć także uwagę na znaczenie tych dwóch linii:
tak więc gcc jest wywoływane raz, aby najpierw zbudować plik zależności, a następnie faktycznie kompiluje plik .cc. I tak dalej dla każdego pliku źródłowego.
źródło
Prostsze rozwiązanie: po prostu użyj Makefile, aby reguła kompilacji .c do .o była zależna od plików nagłówkowych i wszystkiego innego, co jest istotne w twoim projekcie jako zależność.
Np. W pliku Makefile gdzieś:
DEPENDENCIES=mydefs.h yourdefs.h Makefile GameOfThrones.S07E01.mkv ::: (your other Makefile statements like rules ::: for constructing executables or libraries) # Compile any .c to the corresponding .o file: %.o: %.c $(DEPENDENCIES) $(CC) $(CFLAGS) -c -o $@ $<
źródło
Wierzę, że
mkdep
polecenie jest tym, czego chcesz. W rzeczywistości skanuje pliki .c w poszukiwaniu#include
wierszy i tworzy dla nich drzewo zależności. Uważam, że projekty Automake / Autoconf używają tego domyślnie.źródło