En kort introduktion til Makefiles i open source softwareudvikling med GNU Make


GNU Make er et udviklingsværktøj, der bestemmer de dele af en bestemt kodebase, der skal kompileres igen, og kan udstede kommandoer til at udføre disse operationer på kodebasen. Dette særlige fabrikat -værktøj kan bruges med ethvert programmeringssprog, forudsat at deres kompilering kan udføres fra skallen ved at udstede kommandoer.

For at bruge GNU Make er vi nødt til at have nogle sæt regler, der definerer forholdet mellem forskellige filer i vores program og kommandoer til opdatering af hver fil. Disse skrives på en speciel fil, der hedder ' makefile '. Kommandoen ' make ' bruger databasen ' makefile ' og de sidste ændringer af filerne til at afgøre, hvilke filer der skal kompileres igen.

Indholdet af en Makefile

Generelt indeholder ' makefiles ' 5 slags ting, nemlig: implicitte regler, eksplicitte regler, variable definitioner, direktiver og kommentarer.

  1. En eksplicit regel specificerer, hvordan man laver/genoptager en eller flere filer (kaldet mål, vil blive forklaret senere), og hvornår man skal gøre det samme.
  2. En implicit regel specificerer, hvordan man laver/genoptager en eller flere filer baseret på deres navne. Den beskriver, hvordan et målfilnavn er relateret til en fil med et navn, der ligner målet.
  3. En variabeldefinition er en linje, der angiver en strengværdi for en variabel, der skal erstattes senere.
  4. Et direktiv er en instruktion til, hvordan man laver noget særligt, mens man læser makefilen.
  5. Der bruges et '#' symbol, der repræsenterer starten på en kommentar inden for makefiles . En linje, der starter med '#', ignoreres simpelthen.

De oplysninger, der fortæller make hvordan man kompilerer et system, kommer fra at læse en database kaldet makefile . En simpel makefile vil består af regler for følgende syntaks:

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

Et mål er defineret som den outputfil, der genereres af programmet. Det kan også være falske mål , som forklares nedenfor. Eksempler på målfiler inkluderer eksekverbare filer, objektfiler eller falske mål som clean , install , uninstall etc.

En forudsætning er en fil, der bruges som input til oprettelse af målfilerne.

En opskrift er den handling, som foretager udfører for at oprette målfilen baseret på forudsætningerne. Det er nødvendigt at sætte tabulatortegn foran hver opskrift inde i makefiles , medmindre vi angiver variablen ‘.RECIPEPREFIX’ for at definere et andet tegn som præfiks til opskrift.

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 ovenstående eksempel brugte vi 4 C-kildefiler og to headerfiler til oprettelse af den eksekverbare final . Her er hver '.o' fil både et mål og en forudsætning inde i makefilen . Se nu på det sidste målnavn rens . Det er bare en handling snarere end en målfil.

Da vi normalt ikke har brug for dette under kompilering, er det ikke skrevet som en forudsætning i andre regler. Mål, der ikke refererer til filer, men kun er handlinger kaldes falske mål. De har ikke nogen forudsætninger som andre målfiler.

Som standard starter make med det første mål i ' makefile ' og kaldes som ' standardmål '. I betragtning af vores eksempel har vi final som vores første mål. Da dets forudsætninger inkluderer andre objektfiler, skal de opdateres, før de opretter final . Hver af disse forudsætninger behandles i henhold til deres egne regler.

Genkompilering opstår, hvis der foretages ændringer i kildefiler eller headerfiler, eller hvis objektfilen overhovedet ikke findes. Efter genkompilering af de nødvendige objektfiler beslutter make om de skal linke igen final eller ej. Dette skal gøres, hvis filen endelig ikke findes, eller hvis nogen af objektfilerne er nyere end den.

Således hvis vi ændrer filen inter.c , så kører make den kildefilen igen for at opdatere objektfilen inter.o og link derefter endelig .

I vores eksempel måtte vi liste alle objektfilerne to gange i reglen 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 at undgå sådanne duplikationer kan vi introducere variabler til at gemme listen over objektfiler, der bruges i makefile . Ved at bruge variablen OBJ kan vi omskrive prøven makefile til en lignende 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)

Som vi så i eksemplet makefile , kan vi definere regler til oprydning af kildemappen ved at fjerne de uønskede objektfiler efter kompilering. Antag, at vi tilfældigvis har en målfil, der hedder ren . Hvordan kan gøre differentiere ovenstående to situationer? Her kommer begrebet falske mål.

Et falskt mål er et, der egentlig ikke er navnet på en fil, men snarere er det bare et navn til en opskrift, der skal udføres, når der udtrykkeligt foretages en anmodning fra makefilen . En hovedårsag til at bruge falsk mål er at undgå en konflikt med en fil med samme navn. En anden grund er at forbedre ydeevnen.

For at forklare denne ting vil jeg afsløre et uventet twist. Opskriften til clean udføres ikke som standard ved kørsel af make . I stedet er det nødvendigt at påberåbe sig det samme ved at udstede kommandoen gør rent .

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

Prøv nu at oprette makefiles til din egen kodebase. Du er velkommen til at kommentere her med din tvivl.