tgt := calc.so obj := calc.o CFLAGS := -Wall -Wextra -g -fPIC LDFLAGS := -shared all: $(tgt) $(tgt): $(obj) $(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS) clean: $(RM) $(tgt) $(obj) Lühidalt: Makefile on tekstifail, mis määratleb reeglid (targets) kuidas lähtekoodi kompileerida ja ülesandeid automatiseerida (nt käivitamine, puhastus). Make töötab reeglite ja sõltuvuste põhjal: kui sõltuvused on uuemad kui sihtfail, käivitatakse vastavad käsud. Põhikomponendid: target: nimi (nt all, run, clean) dependencies: failid, mille alusel otsustatakse uuendamine commands: shell-käsud, mida make täidab (alguses tabiga) Näide: lihtne C projekt koos Python-skriptiga, mis genereerib faili enne kompileerimist. Failistruktuur: main.c util.c util.h preprocess.py Makefile main.c: #include #include "util.h" int main(void) { printf("Sum: %d\n", add(3, 4)); print_message(); return 0; } util.c: #include #include "util.h" int add(int a, int b) { return a + b; } void print_message(void) { // genereeritud.txt võetakse preprocess.py-st FILE *f = fopen("genereeritud.txt", "r"); if (f) { char buf[100]; if (fgets(buf, sizeof buf, f)) printf("From Python: %s", buf); fclose(f); } else { printf("No generated file.\n"); } } util.h: int add(int a, int b); void print_message(void); preprocess.py (näide, genereerib faili enne kompileerimist): #!/usr/bin/env python3 with open("genereeritud.txt", "w") as f: f.write("Tere, maailm!\n") Makefile: CC = gcc CFLAGS = -Wall -O2 OBJS = main.o util.o EXEC = myprog .PHONY: all run clean gen all: gen $(EXEC) Käivita Python eelprotsess (genereeri fail) gen: \tpython3 preprocess.py Kompileerimine ja linkimine $(EXEC): $(OBJS) \t$(CC) $(CFLAGS) -o $@ $^ %.o: %.c util.h \t$(CC) $(CFLAGS) -c $< -o $@ run: all \t./$(EXEC) clean: \trm -f $(OBJS) $(EXEC) genereeritud.txt Kasutamine: make — käivitab vaikimisi targeti (siin all), mis teeb gen ja kompileerib programmi make run — genereerib faili, kompileerib ja käivitab programmi make clean — kustutab binaarfailid ja genereeritud faili make gen — ainult Python-skript käivitatakse (kasulik kui tahad uuendada sisendit ilma kogu projekti kompileerimata) Märkused: Tab on Makefile’is oluline käsurea alguses. .PHONY ütleb, et need targetid ei ole tegelikud failid. Võid lisada test-targeti, mis käivitab Pythoniga kirjutatud testid (nt pytest) või kasutab Pythonit sisendi genereerimiseks staatiliste testide jaoks. Kui tahad, teen sulle sama näite täidetava GitHub-i projektina või selgitan, kuidas lisada sõltuvusi automaatselt (gcc -M või pattern rules). palun tee, kuidas lisada gcc -M Hea — siin lühike ja konkreetne juhend, kuidas lisada automaatne sõltuvuste genereerimine Makefile’i kasutades gcc (-M*-variandid). Näide eeldab .c ja .h faile, genereerib .o ja .d faile ning lisab .d failid Makefile’i kaudu. Selgitus lühidalt: Kasutame gcc lippe -MMD -MP -MF, mis genereerivad .d failid (make-sõbralikud sõltuvused) ilma süsteemipealkirjade sõltuvusi kaasamata. Lisame .d failid make’i kaudu: -include $(DEPS) Puhastame ka .d failid clean-targetis. Makefile näide: CC = gcc CFLAGS = -Wall -O2 SRCS = main.c util.c OBJS = $(SRCS:.c=.o) DEPS = $(SRCS:.c=.d) EXEC = myprog .PHONY: all clean run all: $(EXEC) Linkimine $(EXEC): $(OBJS) \t$(CC) $(CFLAGS) -o $@ $^ Compile: genereeri .o ja .d fail korraga -MMD -> genereerib sõltuvused .d faili (v.a. süsteemi-headers) -MP -> lisab phony sihid, et vältida 'file missing' errorit, kui header eemaldatakse -MF -> määrab väljundi .d faili nimele %.o: %.c \t$(CC) $(CFLAGS) -MMD -MP -MF $(@:.o=.d) -c $< -o $@ Lisa kõik .d failid kui need olemas (vaigista vead, kui neid pole) -include $(DEPS) run: all \t./$(EXEC) clean: \trm -f $(OBJS) $(DEPS) $(EXEC) Kasutus: make — kompileerib ja genereerib sõltuvused automaatselt make clean — kustutab .o, .d ja binaari make run — kompileerib ja käivitab program