En kort introduksjon til 'Makefiles' i programvareutvikling med åpen kildekode med GNU Make


GNU Make er et utviklingsverktøy som bestemmer delene av en bestemt kodebase som skal rekompileres og kan gi kommandoer for å utføre disse operasjonene på kodebasen. Dette spesielle make-verktøyet kan brukes med et hvilket som helst programmeringsspråk forutsatt at deres kompilering kan gjøres fra skallet ved å utstede kommandoer.

For å bruke GNU Make, må vi ha et sett med regler som definerer forholdet mellom forskjellige filer i programmet vårt og kommandoer for oppdatering av hver fil. Disse er skrevet inn i en spesiell fil kalt «makefile». «make»-kommandoen bruker «makefile»-databasen og de siste endringstidene for filene for å bestemme som alle filene skal kompileres på nytt.

Innholdet i en Makefile

Generelt inneholder «makefiler» 5 typer ting, nemlig: implisitte regler, eksplisitte regler, variabledefinisjoner , direktiver og kommentarer.

  1. En eksplisitt regel spesifiserer hvordan man lager/gjenskaper én eller flere filer (kalt mål, vil bli forklart senere) og når man skal gjøre det samme.
  2. En implisitt regel spesifiserer hvordan man lager/gjenskaper én eller flere filer basert på navnene deres. Den beskriver hvordan et målfilnavn er relatert til en fil med et navn som ligner på målet.
  3. En variabeldefinisjon er en linje som spesifiserer en strengverdi for en variabel som skal erstattes senere.
  4. Et direktiv er en instruksjon for make å gjøre noe spesielt mens du leser makefilen.
  5. Et «#»-symbol brukes representerer starten på en kommentar inne i makefiler . En linje som begynner med «#» ignoreres ganske enkelt.

Strukturen til Makefiles

Informasjonen som forteller make hvordan man rekompilerer et system kommer fra lesing av en database kalt makefilen. En enkel makefile vil bestå av regler med følgende syntaks:

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

Et mål er definert som utdatafilen som genereres av programmet. Det kan også være falske mål, som vil bli forklart nedenfor. Eksempler på målfiler inkluderer kjørbare, objektfiler eller falske mål som clean, installer, avinstaller osv.

En forutsetning er en fil som brukes som input for å lage målfilene.

En oppskrift er handlingen som make utfører for å lage målfilen basert på forutsetningene. Det er nødvendig å sette tabulatortegn før hver oppskrift i makefilene med mindre vi spesifiserer '.RECIPEPREFIX'-variabelen for å definere et annet tegn som prefiks til oppskrift.

Et eksempel på 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

I eksemplet ovenfor brukte vi 4 C-kildefiler og to overskriftsfiler for å lage den kjørbare final. Her er hver «.o»-fil både et mål og en forutsetning i makefilen. Ta en titt på det siste målnavnet ren. Det er bare en handling i stedet for en målfil.

Siden vi normalt ikke trenger dette under kompilering, er det ikke skrevet som en forutsetning i noen andre regler. Mål som ikke refererer til filer, men bare er handlinger, kalles falske mål. De vil ikke ha noen forutsetninger som andre målfiler.

Hvordan GNU Make behandler en Makefil

Som standard starter make med det første målet i «makefilen» og kalles « standardmål'. Med tanke på vårt eksempel har vi final som vårt første mål. Siden dens forutsetninger inkluderer andre objektfiler, skal disse oppdateres før du oppretter final. Hver av disse forutsetningene behandles i henhold til sine egne regler.

Rekompilering skjer hvis det er gjort endringer i kildefiler eller hodefiler eller hvis objektfilen ikke eksisterer i det hele tatt. Etter å ha rekompilert de nødvendige objektfilene, bestemmer make om du skal koble til på nytt final eller ikke. Dette må gjøres hvis filen final ikke eksisterer, eller hvis noen av objektfilene er nyere enn den.

Så hvis vi endrer filen inter.c, vil den ved å kjøre make rekompilere kildefilen for å oppdatere objektfilen inter.o og lenke deretter final.

Bruke variabler inne i Makefiles

I vårt eksempel måtte vi liste alle objektfilene to ganger i regelen for final som vist nedenfor.

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

For å unngå slike dupliseringer kan vi introdusere variabler for å lagre listen over objektfiler som brukes i makefilen. Ved å bruke variabelen OBJ kan vi omskrive prøven makefile til en lignende som vist nedenfor.

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)

Regler for rengjøring av kildekatalogen

Som vi så i eksempelet makefile, kan vi definere regler for årydde opp i kildekatalogen ved å fjerne de uønskede objektfilene etter kompileringen. Anta at vi tilfeldigvis har en målfil kalt clean. Hvordan kan til å skille de to ovennevnte situasjonene? Her kommer konseptet med falske mål.

Et falsk mål er et som egentlig ikke er navnet på en fil, men det er bare et navn på en oppskrift som skal kjøres når en eksplisitt forespørsel sendes fra makefilen<. En hovedgrunn til å bruke falske mål er å unngå konflikt med en fil med samme navn. En annen grunn er å forbedre ytelsen.

For å forklare dette, vil jeg avsløre en uventet vri. Oppskriften på clean vil ikke bli utført som standard når du kjører make. I stedet er det nødvendig å påkalle det samme ved å gi kommandoen make clean.

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

Prøv nå å lage makefiler for din egen kodebase. Kommenter gjerne her med dine tvil.