make

Het programma make wordt als sinds eind jaren 70 gebruikt en is voor distributie, bouwen en installeren van UNIX-programma's nog steeds een zeer veel gebruikte manier. Dan zal het wel iets hebben dat het aantrekkelijk maakt, zou je zeggen.

Redenen om make te gebruiken:

Een Makefile bestaat uit een of meer 'targets'. Een target is meestal een file die gemaakt moet worden. Laten we eenvoudig beginnen en wat met text-files doen. We gaan eerst een file 'target' maken uit een file 'source'. Je mag ze ook 'target.txt' en 'source.txt' noemen.

Verder moet make weten op welke manier source bewerkt moet worden om target op te leveren, ofwel: welk programma kan door make aangeroepen worden om dat te doen ? Make heeft zelf namelijk geen idee wat C++ is of JPG of AIFF. Make is ook geen compiler. Het heeft zelfs geen ingebouwde compiler. Make houdt slechts bij wat er gebouwd moet worden en welke programma's daarvoor gebruikt moeten worden. Daar is het goed in en het gebruikt andere programma's die goed zijn in andere dingen.

Voor elke target in de Makefile wordt aangegeven van welke bron of bronnen het afgeleid wordt en welke programma's uitgevoerd moeten worden om het target te bouwen.

In dit voorbeeld maken we target uit source door een kopie te maken:

target: source
	cp source target

De blauwe balk geeft aan dat je daar een TAB-teken moet zetten, dus niet een rijtje spaties. Dat is om aan te geven dat op die regel een commando staat.

Bij uitvoeren probeert make de eerste target te maken. Als eerste wordt daarvoor de hele afhankelijkheidsstructuur in kaart gebracht. Het eerste target kan namelijk afhangen van andere targets die eerst gemaakt moeten en die kunnen op hun beurt weer afhangen van andere targets die eerst gemaakt moeten worden.

Na het construeren van de graph die alle afhankelijkheden (dependencies) duidelijk maakt gaat make vanaf het onderste niveau alle afhankelijkheden oplossen en target voor target construeren tot alle targets gerealiseerd zijn.

Om te weten of een target "gerealiseerd" is kijkt make naar de timestamps van de files. Als een bron nieuwer is dan een target die van die bron afhangt, dan moet er iets gebeuren om de target opnieuw te maken uit die bron. Daarna is de target nieuwer dan de bron en als je tussentijds geen bronnen van die target verandert zal make de eerstvolgende keer besluiten dat -omdat de target nieuwer is dan al zijn bronnen- er niks hoeft te gebeuren.

Om dit te demonstreren breiden we de bovenstaande Makefile uit. Maak ook twee kopietjes van source en noem die source1 en source2.


all: target1 target2


target1: source1
	cp source1 target1

target2: source2
	cp source2 target2

Voer make opnieuw uit. En voer het daarna nog eens uit. Als het goed is wordt bij de tweede keer uitvoeren niets gedaan omdat alle targets nieuwer zijn dan de sources.


Opvallend detail: de target all is geen file. Waarom niet ?

N.B.: In plaats van all zie je ook wel .PHONY omdat dat impliceert dat het niet om een file gaat.


Verander source2 of pas alleen de timestamp aan met "touch source2" en voer make opnieuw uit. Wat zie je ?

Je kunt aan make ook vertellen welke target gebouwd moet worden. Probeer dat eens uit door alle targets te verwijderen en dan te typen "make target2"

Verander de Makefile zo dat een derde target (target3) gemaakt wordt uit source3 en verwijder target 2 uit de eerste dependency.

Stel dat target1 afhankelijk is van target 2. Dan ziet de Makefile er zo uit:


all: target1


target1: source1 target2
	cp source1 target1

target2: source2
	cp source2 target2

Verander source2 of pas alleen de timestamp aan met touch en voer make opnieuw uit. Wat zie je ?