Gör (programvara) - Make (software)

Göra
Paradigm makro , deklarativ
Designad av Stuart Feldman
Första gången dök upp April 1976 ; 45 år sedan ( 1976-04 )
Implementeringsspråk C
OS Unix-liknande , Inferno
Filformat Makefile
Stora implementeringar
BSD, GNU, nmake
Dialekter
BSD -märke, GNU -märke, Microsoft nmake
Påverkad
Ant , Rake , MSBuild och andra

Inom mjukvaruutveckling är Make ett automatiseringsverktyg för build som automatiskt bygger körbara program och bibliotek från källkoden genom att läsa filer som kallas Makefiles som anger hur man ska härleda målprogrammet. Även integrerade utvecklingsmiljöer och språkspecifika kompilatorfunktioner kan också användas för att hantera en byggprocessen, göra resterna i stor utsträckning, särskilt i Unix och Unix-liknande operativsystem .

Förutom att bygga program kan Make användas för att hantera alla projekt där vissa filer måste uppdateras automatiskt från andra när de andra ändras.

Ursprung

Det finns nu ett antal beroendeverktygsspårningsverktyg, men Make är ett av de mest utbredda, främst på grund av dess inkludering i Unix , med början från PWB/UNIX 1.0, som innehöll en mängd olika verktyg som är inriktade på programutvecklingsuppgifter. Det skapades ursprungligen av Stuart Feldman i april 1976 på Bell Labs . Feldman fick ACM Software System Award 2003 för att ha skapat detta utbredda verktyg.

Feldman inspirerades att skriva Make av en kollegas erfarenhet av att omöjligt felsöka ett program där hans körbara fil av misstag inte uppdaterades med ändringar:

Make härstammade från ett besök av Steve Johnson (författare till yacc, etc.), stormade in på mitt kontor, förbannade öden som hade fått honom att slösa bort en morgonfelsökning av ett korrekt program (bugg hade åtgärdats, filen hade inte sammanställts, cc *.ovar därför opåverkad). Eftersom jag hade tillbringat en del av föregående kväll med att hantera samma katastrof på ett projekt som jag arbetade med, kom idén om ett verktyg för att lösa det. Det började med en genomarbetad idé om en beroendeanalysator, kokade ner till något mycket enklare och blev till Make den helgen. Användning av verktyg som fortfarande var våta var en del av kulturen. Makefiles var textfiler, inte magiskt kodade binärer, eftersom det var Unix -etos: utskrivbara, felsökbara, begripliga saker.

-  Stuart Feldman, The Art of Unix Programming , Eric S. Raymond 2003

Innan Make introducerades bestod Unix build -systemet oftast av operativsystemberoende "make" och "install" shell -skript som medföljer programmets källa. Att kunna kombinera kommandona för de olika målen i en enda fil och att kunna abstrahera beroende -spårning och arkivhantering var ett viktigt steg i riktning mot moderna byggmiljöer.

Derivat

Skärmdump av GNU Make, en implementering av Make

Make har gått igenom ett antal omskrivningar , inklusive ett antal från-början-varianter som använde samma filformat och grundläggande algoritmiska principer och också tillhandahållit ett antal egna icke-standardiserade förbättringar. Några av dem är:

  • Sun DevPro Make dök upp 1986 med SunOS-3.2. Med SunOS-3.2 levererades det som valfritt program; med SunOS-4.0 gjordes SunPro Make till standardprogrammet Make. I december 2006 gjordes Sun DevPro Make till öppen källkod som en del av ansträngningarna att öppna Solaris med öppen källkod .
  • dmake eller Distributed Make som följde med Sun Solaris Studio som standardmärke, men inte som standard på Solaris -operativsystemet (SunOS). Det krävdes ursprungligen för att bygga OpenOffice, men 2009 skrevs byggsystemet om för att använda GNU Make. Även om Apache OpenOffice fortfarande innehåller en blandning av båda byggsystemen använder den mycket mer aktivt utvecklade LibreOffice bara det moderniserade "gbuild" nu.
  • BSD Make ( pmake , bmake eller fmake ), som härrör från Adam de Boors arbete med en version av Make som kan bygga mål parallellt , och överlever med varierande grad av modifiering i FreeBSD , NetBSD och OpenBSD . Distinktivt har den villkor och iterativa slingor som tillämpas i analysfasen och kan användas för att villkorligt och programmatiskt konstruera makefilen, inklusive generering av mål vid körning.
  • GNU Make (kort gmake ) är standardimplementeringen av Make för Linux och macOS. Det ger flera tillägg över det ursprungliga märket, till exempel villkor. Det ger också många inbyggda funktioner som kan användas för att eliminera behovet av shell-scripting i makefile-reglerna samt för att manipulera de variabler som ställts in och används i makefilen. Till exempel kan foreach -funktionen användas för att iterera över en lista med värden, till exempel namnen på filer i en given katalog. GNU Make krävs för att bygga många programvarusystem, inklusive GCC (sedan version 3.4), Linux -kärnan, Apache OpenOffice, LibreOffice och Mozilla Firefox .
  • Rocky Bernsteins Remake är en gaffel av GNU Make och ger flera tillägg över GNU Make, till exempel bättre plats- och felplatsrapportering, körningsspårning, körningsprofilering, och den innehåller en felsökare.
  • Glenn Fowlers nmake är inte relaterat till Microsoft -programmet med samma namn. Dess ingång liknar Make, men är inte kompatibel. Detta program ger genvägar och inbyggda funktioner, som enligt dess utvecklare minskar storleken på makefiler med en faktor 10.
  • Microsoft nmake , ett kommandoradsverktyg som normalt ingår i Visual Studio . Den stöder förbehandlingsdirektiv som inkluderar och villkorliga uttryck som använder variabler som är inställda på kommandoraden eller i makefilerna. Slutsatsregler skiljer sig från Make; till exempel kan de inkludera sökvägar. Verktyget Make som levereras med Embarcadero- produkter har ett kommandoradsalternativ som "får MAKE att efterlikna Microsofts NMAKE.". Qt Project 's Jom verktyg är en klon av Nmake.
  • Mk ersatte Make in Research Unix , från version 9. En omdesign av det ursprungliga verktyget av Bell Labs programmerare Andrew G. Hume, den har en annan syntax. Mk blev standardbyggnadsverktyget i Plan 9 , Bell Labs avsedda efterträdare till Unix.
  • Kati är Googles ersättare av GNU Make, som används i Android OS -versioner. Det översätter makefilen till ninja för snabbare inkrementella byggnader.

POSIX inkluderar standardisering av de grundläggande funktionerna och driften av verktyget Make, och implementeras med varierande grad av fullständighet i Unix-baserade versioner av Make. I allmänhet kan enkla makefiler användas mellan olika versioner av Make med rimlig framgång. GNU Make, Makepp och vissa versioner av BSD Gör som standard att först leta efter filer som heter "GNUmakefile", "Makeppfile" respektive "BSDmakefile", vilket gör att man kan lägga till makefiler som använder implementeringsdefinierat beteende på separata platser.

Beteende

Make används vanligtvis för att bygga körbara program och bibliotek från källkod. Generellt gäller dock att Make är tillämplig på alla processer som innebär att exekvera godtyckliga kommandon för att omvandla en källfil till ett målresultat. Till exempel kan Make användas för att upptäcka en ändring av en bildfil (källan) och omvandlingsåtgärderna kan vara att konvertera filen till ett visst format, kopiera resultatet till ett innehållshanteringssystem och sedan skicka e-post till en fördefinierad uppsättning användare som anger att åtgärderna ovan utfördes.

Make aktiveras med en lista över målfilnamn som ska byggas som kommandoradsargument :

make [TARGET ...]

Utan argument bygger Make det första målet som visas i sin makefile, som traditionellt är ett symboliskt "falskt" mål med namnet alla .

Make bestämmer om ett mål behöver regenereras genom att jämföra filändringstider. Detta löser problemet med att undvika att bygga filer som redan är uppdaterade, men det misslyckas när en fil ändras men dess ändringstid förblir i det förflutna. Sådana ändringar kan orsakas av att en äldre version av en källfil återställs, eller när ett nätverksfilsystem är en filkälla och dess klocka eller tidszon inte synkroniseras med maskinen som kör Make. Användaren måste hantera denna situation genom att tvinga fram en komplett konstruktion. Omvänt, om en källfils modifieringstid ligger i framtiden, utlöser det onödig ombyggnad, vilket kan orsaka besvär för användare.

Makefiler används traditionellt för att kompilera kod ( *.c, *.cc, *.C, etc.), men de kan också användas för att tillhandahålla kommandon för att automatisera vanliga uppgifter. En sådan makefil anropas från kommandoraden:

make            # Without argument runs first TARGET
make help       # Show available TARGETS
make dist       # Make a release archive from current dir

Makefile

Gör sökningar i den aktuella katalogen efter makefilen som ska användas, t.ex. GNU Skapa sökfiler för en fil som heter en av GNUmakefile , makefile eller Makefile och kör sedan de (eller standard) mål (erna) från (endast) den filen.

Makefile -språket liknar deklarativ programmering . Denna språkklass, där nödvändiga slutförhållanden beskrivs men ordningen i vilken åtgärder ska vidtas inte är viktig, är ibland förvirrande för programmerare som är vana vid nödvändig programmering .

Ett problem i byggautomatisering är att skräddarsy en byggprocess till en given plattform . Till exempel kanske kompilatorn som används på en plattform inte accepterar samma alternativ som den som används på en annan. Detta hanteras inte väl av Make. Detta problem hanteras vanligtvis genom att generera plattformsspecifika bygginstruktioner, som i sin tur behandlas av Make. Vanliga verktyg för denna process är Autoconf , CMake eller GYP (eller mer avancerad NG ).

Makefiles kan innehålla fem typer av saker:

  1. En uttrycklig regel säger när och hur man gör om en eller flera filer, kallade regelns mål. Den listar de andra filerna som målen är beroende av, kallade målets förutsättningar, och kan också ge ett recept att använda för att skapa eller uppdatera målen.
  2. En implicit regel säger när och hur man gör om en klass med filer baserat på deras namn. Den beskriver hur ett mål kan bero på en fil med ett namn som liknar målet och ger ett recept för att skapa eller uppdatera ett sådant mål.
  3. En variabeldefinition är en rad som anger ett textsträngvärde för en variabel som kan ersättas med texten senare.
  4. Ett direktiv är en instruktion för att göra något speciellt när du läser makefilen, till exempel att läsa en annan filfil.
  5. Rader som börjar med #används för kommentarer .

Regler

En makefile består av regler . Varje regel börjar med en textberoende rad som definierar ett mål följt av ett kolon (:) och eventuellt en uppräkning av komponenter (filer eller andra mål) som målet beror på. Beroendelinjen är ordnad så att målet (kolonns vänstra hand) beror på komponenter (kolonens högra hand). Det är vanligt att hänvisa till komponenter som förutsättningar för målet.

target [target ...]: [component ...]
Tab ↹[command 1]
	   .
	   .
	   .
Tab ↹[command n]

Vanligtvis har varje regel ett enda unikt mål, snarare än flera mål.

Till exempel skapas en C .o -objektfil från .c -filer, så .c -filer kommer först (dvs. specifikt objektfilmål beror på en C -källfil och rubrikfiler ). Eftersom Make själv inte förstår, känner igen eller skiljer olika typer av filer, öppnas detta för en möjlighet till mänskliga misstag. En bortglömd eller ett extra beroende är kanske inte direkt uppenbart och kan resultera i subtila buggar i den genererade programvaran. Det är möjligt att skriva makefiler som genererar dessa beroenden genom att ringa till tredjepartsverktyg, och vissa makefile-generatorer, till exempel Automake- verktygskedjan som tillhandahålls av GNU-projektet , kan göra det automatiskt.

Varje beroenderad kan följas av en serie TAB -indragna kommandorader som definierar hur komponenterna (vanligtvis källfiler) ska omvandlas till målet (vanligtvis "utdata"). Om någon av förutsättningarna har en nyare modifieringstid än målet körs kommandoraderna. GNU Make -dokumentationen hänvisar till de kommandon som är associerade med en regel som ett "recept".

Det första kommandot kan visas på samma rad efter förutsättningarna, separerade med ett semikolon,

targets : prerequisites ; command

till exempel,

hello: ; @echo "hello"

Make kan bestämma var man ska börja genom topologisk sortering .

Varje kommandorad måste börja med ett tabbtecken för att kunna identifieras som ett kommando. Fliken är ett blankstegstecken , men mellanslagstecknet har inte samma speciella betydelse. Detta är problematiskt, eftersom det kanske inte finns någon visuell skillnad mellan en flik och en serie mellanslagstecken. Denna aspekt av syntaxen för makefiles är ofta föremål för kritik; det har beskrivits av Eric S. Raymond som "en av de sämsta designflaskorna i Unix historia" och The Unix-Haters Handbook sa "att använda flikar som en del av syntaxen är som en av de pungee-fällorna i The Green Berets ". Feldman förklarar valet som orsakas av en lösning för en tidig implementeringssvårighet bevarad av en önskan om bakåtkompatibilitet med de allra första användarna:

Varför fliken i kolumn 1? Yacc var ny, Lex var helt ny. Jag hade inte heller försökt, så jag tänkte att det här skulle vara en bra ursäkt för att lära mig. Efter att ha fått mig att bli upprörd med mitt första hugg på Lex gjorde jag bara något enkelt med mönstret newline-tab. Det fungerade, det stannade. Och sedan några veckor senare hade jag en användarpopulation på ungefär ett dussin, de flesta av dem, och jag ville inte skruva upp min inbäddade bas. Resten är tyvärr historia.

-  Stuart Feldman

Med GNU Make sedan version 3.82 kan du dock välja valfri symbol (ett tecken) som receptprefix med specialvariabeln .RECIPEPREFIX, till exempel:

.RECIPEPREFIX := :
all:
:@echo "recipe prefix symbol is set to '$(.RECIPEPREFIX)'"

Varje kommando körs av ett separat skal eller en kommandorads tolkinstans. Eftersom operativsystem använder olika kommandoradstolkar kan detta leda till oportabla makefiler. Till exempel utför GNU Make (alla POSIX Makes) som standard kommandon med /bin /sh , där Unix -kommandon som cp normalt används. I motsats till det, är Microsoft Nmake kör kommandon med cmd.exe där batch kommandon som kopia finns men inte nödvändigtvis cp.

En regel får inte ha några kommandorader definierade. Beroendelinjen kan enbart bestå av komponenter som refererar till mål, till exempel:

realclean: clean distclean

Kommandoraderna i en regel är vanligtvis ordnade så att de genererar målet. Ett exempel: om file.html är nyare, konverteras den till text. Innehållet i makefilen:

file.txt: file.html
	lynx -dump file.html > file.txt

Regeln ovan utlöses när Gör uppdateringar "file.txt". I följande anrop skulle Make normalt använda denna regel för att uppdatera "file.txt" -målet om "file.html" var nyare.

make file.txt

Kommandorader kan ha ett eller flera av följande tre prefix:

  • en bindestreck-minus (-), som anger att fel ignoreras
  • ett at -tecken (@), som anger att kommandot inte skrivs ut till standardutmatning innan det körs
  • ett plustecken (+), kommandot körs även om Make åberopas i ett "inte kör" -läge

Ignorera fel och tysta eko kan alternativt erhållas via specialmålen .IGNOREoch .SILENT.

Microsofts nKontrollera har fördefinierade regler som kan utelämnas från dessa Makefilerna, t.ex. . c.obj $(CC)$(CFLAGS)

Makron

En makefile kan innehålla definitioner av makron. Makron brukar kallas variabler när de innehåller enkla strängdefinitioner, som {{{1}}}. Makron i makefiler kan åsidosättas i kommandoradsargumenten som skickas till verktyget Make. Miljövariabler finns också som makron.

Makron tillåter användare att ange vilka program som anropas och annat anpassat beteende under byggprocessen. Till exempel används makrot CCofta i makefiler för att hänvisa till platsen för en C -kompilator, och användaren kanske vill ange en viss kompilator som ska användas.

Nya makron (eller enkla "variabler") definieras traditionellt med stora bokstäver:

MACRO = definition

Ett makro används genom att expandera det. Traditionellt görs detta genom att omsluta sitt namn inuti $(). (Att utelämna parentesen leder till Tolkning av nästa bokstav efter $hela variabelnamnet.) En ekvivalent form använder lockiga hängslen snarare än parenteser, det vill ${}säga den stil som används i BSD: erna .

NEW_MACRO = $(MACRO)-$(MACRO2)

Makron kan bestå av skalkommandon med hjälp av kommandosubstitutionsoperatorn , markerad med backticks ( `).

YYYYMMDD  = ` date `

Definitionens innehåll lagras "som det är". Lat utvärdering används, vilket innebär att makron normalt bara utökas när deras utökningar faktiskt krävs, till exempel när de används i kommandoraderna i en regel. Ett utökat exempel:

PACKAGE   = package
VERSION   = ` date +"%Y.%m.%d" `
ARCHIVE   = $(PACKAGE)-$(VERSION)

dist:
	#  Notice that only now macros are expanded for shell to interpret:
	#    tar -cf package-`date +"%Y.%m.%d"`.tar

	tar -cf $(ARCHIVE).tar .

Den generiska syntaxen för att åsidosätta makron på kommandoraden är:

make MACRO="value" [MACRO="value" ...] TARGET [TARGET ...]

Makefiles kan komma åt vilket som helst av ett antal fördefinierade interna makron , med ?och @är de vanligaste.

target: component1 component2
	# contains those components which need attention (i.e. they ARE YOUNGER than current TARGET).
	echo $? 
	# evaluates to current TARGET name from among those left of the colon.
	echo $@

En något vanligt syntax expansion är att använda + = , ? = Och ! = I stället för likhetstecknet. Det fungerar på BSD och GNU gör lika.

Suffix regler

Tilläggsregler har "mål" med namn i formuläret .FROM.TOoch används för att starta åtgärder baserade på filtillägg. I kommandoraderna i suffixreglerna anger POSIX att det interna makrot $<refererar till den första förutsättningen och $@refererar till målet. I det här exemplet, som konverterar alla HTML -filer till text, är skalomdirigeringstoken en >del av kommandoraden medan $<ett makro refererar till HTML -filen:

.SUFFIXES: .txt .html

# From .html to .txt
.html.txt:
	lynx -dump $<   >   $@

När det anropas från kommandoraden expanderar exemplet ovan.

$ make -n file.txt
lynx -dump file.html > file.txt

Mönsterregler

Tilläggsregler kan inte ha några egna förutsättningar. Om de har några behandlas de som vanliga filer med ovanliga namn, inte som suffixregler. GNU Make stöder tilläggsregler för kompatibilitet med gamla makefiler men uppmuntrar annars användning av mönsterregler .

En mönsterregel ser ut som en vanlig regel, förutom att dess mål innehåller exakt ett %tecken i strängen. Målet anses vara ett mönster för matchande filnamn: det %kan matcha alla delsträngar med noll eller fler tecken, medan andra tecken bara matchar sig själva. Förutsättningarna används också för %att visa hur deras namn relaterar till målnamnet.

Exemplet ovan på en suffixregel skulle se ut som följande mönsterregel:

# From %.html to %.txt
%.txt : %.html 
	lynx -dump $< > $@

Andra element

Enradiga kommentarer startas med hash-symbolen (#).

Vissa direktiv i makefiler kan inkludera andra makefiler.

Radens fortsättning indikeras med ett snedstreck \i slutet av en rad.

   target: component \
           component
   Tab ↹command ;          \
   Tab ↹command |          \
   Tab ↹piped-command

Exempel på makefiler

Makefilen:

PACKAGE	 = package
VERSION	 = ` date "+%Y.%m%d%" `
RELEASE_DIR  = ..
RELEASE_FILE = $(PACKAGE)-$(VERSION)

# Notice that the variable LOGNAME comes from the environment in
# POSIX shells.
#
# target: all - Default target. Does nothing.
all:
	echo "Hello $(LOGNAME), nothing to do by default"
		# sometimes: echo "Hello ${LOGNAME}, nothing to do by default"
	echo "Try 'make help'"

# target: help - Display callable targets.
help:
	egrep "^# target:" [Mm]akefile

# target: list - List source files
list:
	# Won't work. Each command is in separate shell
	cd src
	ls

	# Correct, continuation of the same shell
	cd src; \
	ls

# target: dist - Make a release.
dist:
	tar -cf  $(RELEASE_DIR)/$(RELEASE_FILE) && \
	gzip -9  $(RELEASE_DIR)/$(RELEASE_FILE).tar

Nedan finns en mycket enkel makefil som som standard ("alla" -regeln listas först) sammanställer en källfil som heter "helloworld.c" med systemets C -kompilator och också tillhandahåller ett "rent" mål för att ta bort de genererade filerna om användaren vill börja om igen. De $@och $<är två av de så kallade interna makron (även kända som automatiska variabler) och står för målnamn respektive "implicit" källa. I exemplet nedan $^expanderar den till en mellanrum avgränsad lista över förutsättningarna. Det finns ett antal andra interna makron.

CFLAGS ?= -g

all: helloworld

helloworld: helloworld.o
	# Commands start with TAB not spaces
	$(CC) $(LDFLAGS) -o $@ $^

helloworld.o: helloworld.c
	$(CC) $(CFLAGS) -c -o $@ $<

clean: FRC
	$(RM) helloworld helloworld.o

# This pseudo target causes all targets that depend on FRC
# to be remade even in case a file with the name of the target exists.
# This works with any make implementation under the assumption that
# there is no file FRC in the current directory.
FRC:

Många system har fördefinierade regler och makron för att ange vanliga uppgifter som kompilering baserat på filtillägg. Detta låter användarna utelämna de faktiska (ofta oportabla) instruktionerna om hur de ska generera målet från källorna. På ett sådant system kan makefilen ovan ändras enligt följande:

all: helloworld

helloworld: helloworld.o
	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^

clean: FRC
	$(RM) helloworld helloworld.o

# This is an explicit suffix rule. It may be omitted on systems
# that handle simple rules like this automatically.
.c.o:
	$(CC) $(CFLAGS) -c $<

FRC:
.SUFFIXES: .c


Att "helloworld.o" beror på "helloworld.c" hanteras nu automatiskt av Make. I ett så enkelt exempel som det som illustreras här spelar det knappast någon roll, men suffixreglernas verkliga kraft blir tydlig när antalet källfiler i ett mjukvaruprojekt börjar växa. Man behöver bara skriva en regel för länkningssteget och deklarera objektfilerna som förutsättningar. Make bestämmer sedan implicit hur man gör alla objektfiler och letar efter ändringar i alla källfiler.

Enkla suffixregler fungerar bra så länge källfilerna inte är beroende av varandra och av andra filer, till exempel huvudfiler. En annan väg för att förenkla byggprocessen är att använda så kallade mönstermatchningsregler som kan kombineras med kompilatorassisterat beroendegenerering. Som ett sista exempel som kräver gcc -kompilatorn och GNU Make, här är en generisk makefil som sammanställer alla C -filer i en mapp till motsvarande objektfiler och sedan länkar dem till den slutliga körbara filen. Innan kompilering sker samlas beroenden i makefilvänligt format till en dold fil ".depend" som sedan ingår i makefilen. Bärbara program bör undvika konstruktioner som används nedan.

# Generic GNUMakefile

# Just a snippet to stop executing under other make(1) commands
# that won't understand these lines
ifneq (,)
This makefile requires GNU Make.
endif

PROGRAM = foo
C_FILES := $(wildcard *.c)
OBJS := $(patsubst %.c, %.o, $(C_FILES))
CC = cc
CFLAGS = -Wall -pedantic
LDFLAGS =
LDLIBS = -lm

all: $(PROGRAM)

$(PROGRAM): .depend $(OBJS)
	$(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) -o $(PROGRAM) $(LDLIBS)

depend: .depend

.depend: cmd = gcc -MM -MF depend $(var); cat depend >> .depend;
.depend:
	@echo "Generating dependencies..."
	@$(foreach var, $(C_FILES), $(cmd))
	@rm -f depend

-include .depend

# These are the pattern matching rules. In addition to the automatic
# variables used here, the variable $* that matches whatever % stands for
# can be useful in special cases.
%.o: %.c
	$(CC) $(CFLAGS) -c $< -o $@

%: %.o
	$(CC) $(CFLAGS) -o $@ $<

clean:
	rm -f .depend $(OBJS)

.PHONY: clean depend

Se även

Referenser

externa länkar