Zoeken op website

Een korte introductie tot 'Makefiles' bij de ontwikkeling van open source software met GNU Make


GNU Make is een ontwikkelingshulpprogramma dat bepaalt welke delen van een bepaalde codebasis opnieuw moeten worden gecompileerd en dat opdrachten kan geven om die bewerkingen op de codebasis uit te voeren. Dit specifieke hulpprogramma make kan met elke programmeertaal worden gebruikt, op voorwaarde dat de compilatie ervan vanuit de shell kan worden gedaan door opdrachten te geven.

Om GNU Make te kunnen gebruiken, hebben we een aantal regels nodig die de relatie tussen verschillende bestanden in ons programma definiëren, en opdrachten voor het bijwerken van elk bestand. Deze worden naar een speciaal bestand geschreven met de naam ‘makefile‘. Het commando 'make' gebruikt de database 'makefile' en de laatste wijzigingstijden van de bestanden om te beslissen waarin alle bestanden opnieuw moeten worden gecompileerd.

Inhoud van een Makefile

Over het algemeen bevatten 'makefiles' 5 soorten dingen, namelijk: impliciete regels, expliciete regels, variabele definities , richtlijnen en opmerkingen.

  1. Een expliciete regel specificeert hoe een of meer bestanden (zogenaamde doelen genoemd, later uitgelegd) gemaakt/opnieuw gemaakt moeten worden en wanneer hetzelfde gedaan moet worden.
  2. Een impliciete regel specificeert hoe een of meer bestanden gemaakt/opnieuw gemaakt moeten worden op basis van hun naam. Het beschrijft hoe een doelbestandsnaam gerelateerd is aan één bestand met een naam die lijkt op het doel.
  3. Een variabeledefinitie is een regel die een tekenreekswaarde specificeert voor een variabele die later moet worden vervangen.
  4. Een richtlijn is een instructie voor make om iets speciaals te doen tijdens het lezen van het makefile.
  5. Er wordt een '#'-symbool gebruikt dat het begin aangeeft van een opmerking in makefiles . Een regel die begint met ‘#’ wordt eenvoudigweg genegeerd.

Structuur van makefiles

De informatie die make vertelt hoe een systeem opnieuw moet worden gecompileerd, komt uit het lezen van een database genaamd de makefile. Een eenvoudige makefile bestaat uit regels met de volgende syntaxis:

target ... : prerequisites ... 
	recipe 
... 
...

Een doel wordt gedefinieerd als het uitvoerbestand dat door het programma wordt gegenereerd. Het kunnen ook nepdoelen zijn, wat hieronder wordt uitgelegd. Voorbeelden van doelbestanden zijn uitvoerbare bestanden, objectbestanden of nepdoelen zoals clean, installeren, verwijderen enz.

Een vereiste is een bestand dat wordt gebruikt als invoer om de doelbestanden te maken.

Een recept is de actie die make uitvoert voor het maken van het doelbestand op basis van de vereisten. Het is noodzakelijk om het tabteken vóór elk recept in de makefiles te plaatsen, tenzij we de variabele '.RECIPEPREFIX' specificeren om een ander teken als voorvoegsel te definiëren naar recept.

Een voorbeeld Makefile

final: main.o end.o inter.o start.o
	gcc -o final main.o end.o inter.o start.o
main.o: main.c global.h
	gcc -c main.c
end.o: end.c local.h global.h
	gcc -c end.c
inter.o: inter.c global.h
	gcc -c inter.c
start.o: start.c global.h
	gcc -c start.c
clean:
	rm -f main.o end.o inter.o start.o

In het bovenstaande voorbeeld hebben we 4 C bronbestanden en twee headerbestanden gebruikt om het uitvoerbare bestand definitief te maken. Hier is elk ‘.o’-bestand zowel een doel als een vereiste binnen de makefile. Kijk nu eens naar de laatste doelnaam clean. Het is slechts een actie en geen doelbestand.

Omdat we dit normaal gesproken niet nodig hebben tijdens het compileren, wordt dit in geen enkele andere regel als voorwaarde geschreven. Doelen die niet naar bestanden verwijzen maar slechts acties zijn, worden nepdoelen genoemd. Ze hebben geen vereisten zoals andere doelbestanden.

Hoe GNU Make een Makefile verwerkt

Standaard begint make met het eerste doel in de 'makefile' en wordt aangeroepen als ' standaarddoel'. Als we ons voorbeeld bekijken, hebben we definitief als ons eerste doel. Omdat de vereisten andere objectbestanden omvatten, moeten deze worden bijgewerkt voordat definitief wordt gemaakt. Elk van deze vereisten wordt verwerkt volgens hun eigen regels.

Opnieuw compileren vindt plaats als er wijzigingen zijn aangebracht in bronbestanden of headerbestanden of als het objectbestand helemaal niet bestaat. Nadat de noodzakelijke objectbestanden opnieuw zijn gecompileerd, beslist make of final opnieuw moet worden gekoppeld of niet. Dit moet worden gedaan als het bestand final niet bestaat, of als een van de objectbestanden nieuwer is.

Dus als we het bestand inter.c wijzigen, zal het bij het uitvoeren van make het bronbestand opnieuw compileren om het bij te werken het objectbestand inter.o en koppel vervolgens final.

Variabelen gebruiken in Makefiles

In ons voorbeeld moesten we alle objectbestanden tweemaal vermelden in de regel voor definitief, zoals hieronder weergegeven.

final: main.o end.o inter.o start.o
	gcc -o final main.o end.o inter.o start.o

Om dergelijke duplicaties te voorkomen, kunnen we variabelen introduceren om de lijst met objectbestanden op te slaan die worden gebruikt in de makefile. Door de variabele OBJ te gebruiken, kunnen we het voorbeeld makefile herschrijven naar een soortgelijk bestand zoals hieronder weergegeven.

OBJ = main.o end.o inter.o start.o
final: $(OBJ)
	gcc -o final $(OBJ)
main.o: main.c global.h
	gcc -c main.c
end.o: end.c local.h global.h
	gcc -c end.c
inter.o: inter.c global.h
	gcc -c inter.c
start.o: start.c global.h
	gcc -c start.c
clean:
	rm -f $(OBJ)

Regels voor het opschonen van de bronmap

Zoals we in het voorbeeld makefile hebben gezien, kunnen we regels definiëren om de bronmap op te schonen door de ongewenste objectbestanden na de compilatie te verwijderen. Stel dat we toevallig een doelbestand hebben met de naam clean. Hoe kan de twee bovengenoemde situaties van elkaar onderscheiden? Hier komt het concept van nepdoelen naar voren.

Een nepdoel is een doel dat niet echt de naam van een bestand is, maar slechts een naam voor een recept dat moet worden uitgevoerd wanneer er een expliciet verzoek wordt gedaan vanuit het makefile. Een van de belangrijkste redenen om nepdoel te gebruiken is om een conflict met een bestand met dezelfde naam te voorkomen. Een andere reden is het verbeteren van de prestaties.

Om dit uit te leggen, zal ik een onverwachte wending onthullen. Het recept voor clean wordt niet standaard uitgevoerd bij het uitvoeren van make. In plaats daarvan is het nodig om hetzelfde aan te roepen door het commando make clean uit te voeren.

.PHONY: clean
clean:
	rm -f $(OBJ)

Probeer nu makefiles te maken voor uw eigen codebasis. Voel je vrij om hier te reageren met je twijfels.


Alle rechten voorbehouden. © Linux-Console.net • 2019-2024