Thumbnail Automatische dependencies met GNU Make

Door: Thijs Zumbrink
11-06-2011 18:33

Zoals wereldwijd een hoop developers weten, is GNU Make een prachtige development tool. Make wordt vooral ingezet in taken zoals het compileren van programma's of anderszins het genereren van outputfiles. Echter, het kan gebruikt worden voor veel meer taken die je het leven makkelijker maken. Make kan bijvoorbeeld hetzelfde bereiken als met een batch bestand, dat je helpt in het uitvoeren van lange commands, aangestuurd door veel kortere commands.

Een voorbeeld: ik gebruik soms gnuplot om een bergje getallen te visualiseren. Het is ongelooflijk naar om telkens die regel in te moeten typen, dus deze make regel handelt dat voor me af:

plot: depthmap.out
gnuplot -p -e "splot 'depthmap.out' matrix with lines title 'Matrix plot'"


Dit is een regel die ik kan uitvoeren met make plot. Lekker kort dus. De regel kan alleen worden uitgevoerd als het bestand depthmap.out bestaat. Wanneer dit bestand bestaat wordt de tweede regel uitgevoerd en dus het gnuplot programma gedraaid. depthmap.out wordt hier ook wel een dependency genoemd. Dependencies zijn bij het compileren van broncode veel belangrijker dan ze hier zijn, en daar ontstaat dan ook een probleem...

Bij een klein project zijn de dependencies nog wel te overzien. Wanneer je bronbestanden elkaar nodig hebben voor een goede werking van het programma, wijzig je de makefile om de dependencies goed te zetten. Als je project echter begint te groeien in de tientallen bestanden wordt dit een naar klusje. Gelukkig kan gcc ons daarbij helpen in het geval van C++ programma's! Met gcc -MM kun je de C++ compiler vragen om aan de hand van #include statements in je broncode een lijst van dependencies uit te draaien. Hier een voorbeeld van een makefile:

PPROGRAM_OBJECTS = A.o B.o C.o

program: $(PROGRAM_OBJECTS)
gcc -o program $(PROGRAM_OBJECTS)

%.o: %.cc
gcc -c -o $*.o $*.cc

-include $(patsubst %.o, %.d, $(PPROGRAM_OBJECTS))

%.d: %.cc
@set -e; rm -f $@; \
gcc -MM $< > $@.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
rm -f $@.$$$$


De eerste regel beginnend met PROGRAM_OBJECTS geeft aan welke objecten we willen compileren als deel van de executable. A.o, B.o en C.o worden door de %.o regel verderop gegenereerd uit de A.cc, B.cc en C.cc bestanden respectievelijk. De -include regel zorgt ervoor dat we de dependencies van de drie bestanden bekend maken in het proces. Die drie bestanden zijn A.d, B.d en C.d respectievelijk. Deze worden gemaakt door de %.d regel vanuit de bijbehorende .cc files. Hierbij helpt gnu -MM ons door de bronbestanden te scannen voor #include preprocessor directives. En voila, automatische dependency generatie! Het enige dat in dit bestand aangepast dient te worden is PROGRAM_OBJECTS. Een ideale template voor nieuwe projecten.

Een iets nettere makefile waarbij alles ook al in georganiseerde mappen gestopt wordt kun je hier downloaden.

Reacties
Log in of registreer om reacties te plaatsen.