makefileAan de slag met makefile


Opmerkingen

Een makefile is een tekstbestand dat de werking van het make programma bestuurt. Het make programma wordt meestal gebruikt om het maken van programma's vanuit hun bronbestanden te beheren, maar het kan meer in het algemeen worden gebruikt om elk proces te verwerken waarbij bestanden (of doelen ) opnieuw moeten worden gegenereerd nadat andere bestanden (of vereisten ) zijn gewijzigd. De makefile beschrijft de relatie tussen doelen en vereisten, en specificeert ook de opdrachten die nodig zijn om het doel up-to-date te brengen wanneer een of meer van de vereisten zijn gewijzigd. De enige manier waarop make bepaalt "out of date-ness" is door de modificatie tijd van target bestanden en hun voorwaarden te vergelijken.

Makefiles zijn enigszins uniek op een paar manieren die aanvankelijk verwarrend kunnen zijn.

Ten eerste bestaat een makefile uit twee volledig verschillende programmeertalen in hetzelfde bestand. Het grootste deel van het bestand is geschreven in een taal die make kan begrijpen: dit levert variabeletoekenning en expansie, sommige preprocessor mogelijkheden (met inbegrip van andere bestanden, voorwaardelijke parsing secties van het bestand, enz.), Alsmede de definitie van de doelstellingen en hun vereisten. Bovendien kan aan elk doel een recept worden gekoppeld dat aangeeft welke opdrachten moeten worden aangeroepen om ervoor te zorgen dat dat doel wordt bijgewerkt. Het recept is geschreven als een shellscript (standaard POSIX sh). Het make programma ontleedt dit script niet: het draait een shell en geeft het script door aan de uit te voeren shell. Het feit dat recepten niet per make worden ontleed, maar in plaats daarvan door een afzonderlijk shell-proces worden verwerkt, staat centraal bij het begrijpen van makefiles.

Ten tweede is een makefile geen procedurele taal zoals een script: aangezien make het makefile ontleedt, construeert het intern een gerichte grafiek waarbij doelen de knooppunten van de grafiek zijn en de randvereisten de randen zijn. Pas nadat alle makefiles volledig zijn ontleed en de grafiek is voltooid zal make kiezen het ene knooppunt (doel) en proberen om het up to date te brengen. Om ervoor te zorgen dat een doelwit up-to-date is, moet het er eerst voor zorgen dat alle vereisten van dat doel up-to-date zijn, enzovoort, recursief.

versies

Naam Ook gekend als Eerste versie Versie Publicatiedatum
POSIX maken 1992 IEEE Std 1003.1-2008, 2016-editie 2016/09/30
NetBSD maken BLet 1988 20160926 2016/09/26
GNU maken gmake 1988 4.2.1 2016/06/10
SunPro maken DMaak 2006 2015/07/13
MSVS nmake 2003 2015p3 2016/06/27

Basis Makefile

Overweeg het schrijven van een "hallo wereld!" programma in c. Laten we zeggen dat onze broncode zich in een bestand met de naam source.c bevindt. Om ons programma te kunnen uitvoeren, moeten we het compileren, meestal op Linux (met gcc) moeten we $> gcc source.c -o output waar output is de naam van het te genereren uitvoerbare bestand. Voor een basisprogramma werkt dit goed, maar naarmate programma's complexer worden, kan onze compilatieopdracht ook complexer worden. Dit is waar een Makefile binnenkomt, met makefiles kunnen we een vrij complexe set regels schrijven voor het compileren van een programma en het vervolgens eenvoudig compileren door make op de opdrachtregel te typen. Hier is bijvoorbeeld een mogelijk voorbeeld Makefile voor het hallo wold voorbeeld hierboven.

Basis Makefile

Laten we een basis Makefile maken en opslaan op ons systeem in dezelfde map als onze broncode met de naam Makefile . Merk op dat dit bestand de naam Makefile moet hebben, maar de hoofdstad M is optioneel. Dat gezegd hebbende, het is relatief standaard om een capitol M te gebruiken.

output: source.c
    gcc source.c -o output
 

Merk op dat er precies één tabblad is vóór de opdracht gcc op de tweede regel (dit is belangrijk in makefiles). Zodra dit Makefile is geschreven, elke keer dat de gebruikerstypes make (in dezelfde map als de Makefile) make zal controleren of source.c is gewijzigd (controleert de tijdstempel) of het recenter is gewijzigd dan de uitvoer zal uitvoeren de compilatieregel op de volgende regel.

Variabelen in Makefiles

Afhankelijk van het project wilt u misschien enkele variabelen aan uw make-bestand toevoegen. Hier is een voorbeeld van Makefile met aanwezige variabelen.

CFLAGS = -g -Wall

output: source.c
    gcc $< $(CFLAGS) -o $@
 

Laten we nu eens kijken wat hier is gebeurd. In de eerste regel hebben we een variabele met de naam CFLAGS aangegeven die verschillende veelvoorkomende vlaggen bevat die je mogelijk aan de compiler wilt doorgeven. Houd er rekening mee dat je zoveel vlaggen kunt opslaan als je wilt in deze variabele. Dan hebben we dezelfde regel als voorheen aan make vertellen om source.c te controleren om te zien of het recenter is gewijzigd dan output, zo ja, dan wordt de compilatieregel uitgevoerd. Onze compilatieregel is meestal dezelfde als voorheen, maar deze is ingekort met behulp van variabelen, de variabele $< is ingebouwd in make (aangeduid als een automatische variabele zie https://www.gnu.org/software/make/manual/ html_node / Automatic-Variables.html ) en het staat altijd voor de bron, dus in dit geval source.c . $(CFLAGS) is onze variabele die we eerder hebben gedefinieerd, maar merk op dat we de variabele tussen haakjes moesten plaatsen met een $ vooraan zoals deze $(someVariable) . Dit is de syntaxis om Make te vertellen de variabele uit te breiden naar wat u eerder hebt getypt. Eindelijk hebben we het $ @ symbool, wederom is dit een variabele ingebouwd in make, en het staat gewoon voor het doel van de compilatiestap, dus in dit geval staat het voor output .

Schoon

Maak schoon is een ander handig concept om te leren over het maken van bestanden. Laat het Makefile van bovenaf wijzigen

CFLAGS = -g -Wall
TARGETS = output

output: source.c
    gcc $< $(CFLAGS) -o $@

clean:
    rm $(TARGETS)
 

Zoals u kunt zien, hebben we eenvoudig nog een regel toegevoegd aan onze Makefile en een extra variabele die al onze doelen bevat. Dit is een enigszins gebruikelijke regel in makefiles, omdat je hiermee snel alle door jou geproduceerde binaire bestanden kunt verwijderen door $> make clean typen. Door make clean te typen, laat u het make-programma de schoonregel uitvoeren en maakt make vervolgens de opdracht rm om al uw doelen te verwijderen.

Ik hoop dat dit korte overzicht van het gebruik van make u helpt uw workflow te versnellen, Makefiles kan erg complex worden, maar met deze ideeën moet u aan de slag kunnen gaan met make en een beter begrip hebben van wat er gaande is in andere Makefiles- programmeurs. Voor meer informatie over het gebruik van make a excellent resource is https://www.gnu.org/software/make/manual/ .

Regels definiëren

Snelle start

Een regel beschrijft wanneer en hoe bepaalde bestanden ( doelen van de regel) worden gemaakt. Het kan ook dienen om een doelbestand bij te werken als een van de bestanden die nodig zijn voor het maken ervan (de vereisten van het doel) nieuwer is dan het doel.

Regels volgen de onderstaande syntaxis: (Houd er rekening mee dat opdrachten die een regel volgen, worden ingesprongen door een tabblad )

targets: prerequisites
        <commands>
 

waarbij doelen en vereisten bestandsnamen of speciale gereserveerde namen zijn en commando's (indien aanwezig) worden uitgevoerd door een shell om doelen te bouwen / opnieuw op te bouwen die verouderd zijn.

Om een regel uit te voeren, kunt u eenvoudig de opdracht make in de terminal uitvoeren vanuit dezelfde map waar de Makefile zich bevindt. Als u make uitvoert zonder het doel op te geven, wordt de eerste regel uitgevoerd die is gedefinieerd in de Makefile . Volgens afspraak wordt de eerste regel in de Makefile vaak alles of standaard genoemd , waarbij gewoonlijk alle geldige builddoelen als voorwaarden worden vermeld.

make voert de regel alleen uit als het doel verouderd is, wat betekent dat het niet bestaat of dat de wijzigingstijd ouder is dan een van de vereisten. Als de lijst met vereisten leeg is, wordt de regel alleen uitgevoerd wanneer deze voor het eerst wordt opgeroepen om de doelen op te bouwen. Als de regel echter geen bestand maakt en het doel een dummy-variabele is, wordt de regel altijd uitgevoerd.

GNU maken

Patroonregels

Patroonregels worden gebruikt om meerdere doelen op te geven en vereiste namen uit doelnamen samen te stellen. Ze zijn algemener en krachtiger in vergelijking met gewone regels, omdat elk doelwit zijn eigen vereisten kan hebben. In patroonregels wordt een relatie tussen een doel en een voorwaarde opgebouwd op basis van voorvoegsels, inclusief padnamen en achtervoegsels, of beide.

Stel je voor dat we de doelen foo.o en bar.o willen bouwen, door respectievelijk C-scripts, foo.c en bar.c compileren. Dit kan worden gedaan met behulp van de onderstaande gewone regels:

foo.o: foo.c
    cc -c $< -o $@

bar.o: bar.c
    cc -c $< -o $@

 

waar de automatische variabele $< is de naam van de eerste vereiste en $@ de naam van het doel (Een volledige lijst van de automatische variabelen kunnen worden gevonden hier ).

Omdat de doelen hetzelfde achtervoegsel delen, kunnen de bovenstaande twee regels nu worden vervangen door de volgende patroonregel:

%.o: %.c
    cc -c $< -o $@
 

Impliciete regels

Impliciete regels vertellen make hoe gebruikelijke methoden gebruiken om bepaalde types van target bestanden, die vaak worden gebruikt op te bouwen. make gebruikt de doelbestandsnaam om te bepalen welke impliciete regel moet worden aangeroepen.

Het voorbeeld van de patroonregel dat we in de vorige sectie hebben gezien, hoeft eigenlijk niet in een Makefile te worden gedeclareerd omdat make een impliciete regel voor C-compilatie heeft. In de volgende regel worden dus de vereisten foo.o en bar.o gebouwd met behulp van de impliciete regel voor C-compilatie, voordat foo .

foo : foo.o bar.o
    cc -o foo foo.o bar.o $(CFLAGS) $(LDFLAGS)
 

Een catalogus van impliciete regels en de door hen gebruikte variabelen vindt u hier .

generieke regel om een bestand te gzipen

als een map 2 bestanden bevat:

$ ls
makefile
example.txt
 

en makefile bevatten de volgende tekst

%.gz: %
    gzip $<
 

dan kun je example.txt.gz verkrijgen door de shell in te typen

$ make -f makefile example.txt.gz
 

de makefile bestaan uit slechts één regel die instrueren maken hoe u een bestand waarvan de naam eindigen met .gz te maken als er een bestand met dezelfde naam, maar de .gz suffix.

makefile Hallo wereld

C: \ makefile:

helloWorld :
[TAB]echo hello world
 

resultaten uitvoeren:

C:\>make
echo hello world
hello world
 

Opmerking: [TAB] moet worden vervangen door een echt tabblad, stackoverflow vervangt tabbladen door spaties en spaties worden niet hetzelfde gebruikt als tabbladen in een maakbestand.