make

A Wikipédiából, a szabad enciklopédiából
Ugrás a navigációhoz Ugrás a kereséshez

A make egy programfordításra kifejlesztett segédprogram: a forrásprogramokból előállítja a végrehajtható programo(ka)t. Csak a szükséges műveleteket végzi el: azokat a forrásprogramokat fordítja le, melyeket még nem fordított le, vagy melyek az utolsó fordítás óta változtak.

A make nemcsak programfordításra használható, hanem minden olyan feladatra, ahol fájlokból más fájlokat kell előállítani. Unix operációs rendszerre fejlesztették ki, de azóta más rendszerekben is megtalálható.

A make a fájlok dátumából állapítja meg, hogy szükséges-e a fordítás. Tartalmaz beépített szabályokat az ismert programnyelvek számára, de saját szabályok is megadhatók, ill. a beépítettek helyettesíthetők saját szabályokkal.

A make programot rendszerint paraméter nélkül hívjuk. A fordításhoz szükséges tennivalók az aktuális könyvtárban, a Makefile nevű fájlban vannak.

Formai szabályok[szerkesztés]

Makefile-ban

  • a #-sel kezdődő sorok megjegyzések
  • a sor végi \ folytatósort jelöl
  • a szabály utasításainak első karaktere kötelezően tabulátor. Nem helyettesíthető egy vagy több helyközzel.
  • a $ lefoglalt karakter a make változói számára. Ha a $ nem a make-nek szól (hanem pl. a shellnek), meg kell kettőzni: $$.

A make működése[szerkesztés]

Példa Makefile-ra:

proba	: proba.c
	gcc -o proba proba.c

A fenti példa egyetlen szabályt tartalmaz. A szabály első sorában a kettősponttól balra álló szó a cél, a jobbra álló az előfeltétel. Több cél és több előfeltétel adható meg helyközzel elválasztva.[1] A szabály következő sora(i) a célt előállító utasítás(ok). Fontos, hogy az utasítások tabulátorral (és nem helyközökkel) kezdődnek: a make innen tudja, mely sorok tartoznak a szabályhoz.

Az utasítások elmaradhatnak, ha van olyan implicit szabály, mely a célt elő tudja állítani (pl. a kiterjesztése alapján). Az előfeltételek is elmaradhatnak: ilyenkor az utasítások mindenképpen végrehajtódnak.

A make hívósorában cél(ok) adható(k) meg paraméterként. Ha nincs paraméter, az első szabály hajtódik végre, ami tipikus esetben az összes célt előállítja.

A célok fájlok (hacsak mást nem adunk meg: lásd a .PHONY utasítást). Az előfeltételek más szabályok célfájljai, ill. ha nem létezik ilyen szabály, akkor normál fájlok.

Az előfeltétel ellenőrzéséhez a make végrehajtja az előfeltétel-fájlt létrehozó szabályt (hogy ellenőrizze, nem kell-e újra létrehozni), ill. ha nincs ilyen szabály, de normál fájl igen, akkor összehasonlítja a célfájl és az előfeltétel-fájl dátumát. Ha a cél régebbi, mint a fájl, akkor a célt újra létre kell hozni, azaz végre kell hajtani az utasításait, ellenkező esetben nincs tennivaló: a cél az adott előfeltétel szempontjából naprakész. Ha sem szabálya, sem normál fájlja nincs az előfeltételnek, akkor a szabály befejeződik, és hibával visszatér az őt hívó szabályhoz.

A make a fenti módon egymás után ellenőrzi a szabály összes előfeltételét.

Egy szabálynak háromféle végeredménye lehet:

  • a szabály sikeresen végrehajtódott: a szabály utasításait végre kellett hajtani, mert valamelyik előfeltétele nem volt naprakész, és a végrehajtás sikeres volt
  • a szabály utasításait nem kellett végrehajtani, mert a cél naprakész valamennyi előfeltétel szempontjából
  • a szabály végrehajtása sikertelen, ha legalább egy előfeltétele vagy utasítása sikertelen.

Utasítások[szerkesztés]

Fontos, hogy a make a szabály utasításait soronként külön-külön shellben hajtja végre. Pl. a külön sorba írt cd könyvtár utasítás hatástalan, mivel a shellből való kilépés után megszűnik a hatása, így a következő sorban levő make-utasítást sem befolyásolja. Pontosvesszővel elválasztva viszont lehet több utasítást adni ugyanannak a shellnek.

A make minden utasítássor után ellenőrzi a shelltől visszakapott értéket, és ha az nem 0, vagyis a sor végrehajtása sikertelen, félbeszakítja az utasítások végrehajtását, és hibával visszatér a hívó szabályhoz, ami ugyancsak hibával visszatér az őt hívóhoz, stb., végül a make is hibával tér vissza a shellbe.

Változók[szerkesztés]

A make-ben háromféle típusú változó van:

  • implicit változó: a make beépített változói. Pl. a CC nevű változó tartalmazza az adott rendszerben a C-fordító nevét.[2]
  • automatikus változó:[3] a szabály végrehajtásakor jön létre. A két legfontosabb automatikus változó:
    • $@ a cél neve
    • $^ az előfeltételek helyközzel elválasztott listája.
  • a Makefile-ban a programozó által definiált saját változó.

A változó értékére a $(változónév) kifejezéssel lehet hivatkozni (az automatikus változók kivételével, ahol nem kell zárójel).

Saját változó a változónév = érték alakban definiálható. Az érték bármilyen szöveg lehet.

Az implicit és automatikus változó az utasításokban használható, a saját változó bárhol a szabályban.

Példa:

MIND = proba proba.gz

all	: $(MIND)

proba	: proba.c proba1.c
	$(CC) -o $@ $^

proba.gz : proba.1
	gzip -c <$^ >$@

A MIND saját változó, mely a célok nevét (a végrehajtható programét és a tömörített manuálét) tartalmazza helyközzel elválasztva.

Az all a Makefile első szabálya, ez hajtódik végre, ha paraméter nélkül hívjuk a make parancsot.[4] Miután utasítása nincs, csak az előfeltételeket ellenőrzi, de ezzel le is fordítja a programot ill. újratömöríti a manuált, ha valamelyik megváltozott. Az automatikus változók lehetővé teszik, hogy minden fájlnevet csak egyszer kelljen leírni, a CC implicit változó pedig azt, hogy Makefile-lal ne csak linuxban lehessen a programot lefordítani.

Implicit szabályok[szerkesztés]

A fenti példában mindkét C-program lefordul, ha bármelyik forrásfájl megváltozik. Ez nem előnyös, különösen sok forrásprogramból álló programok esetén. Az alábbi Makefile-részlet megoldja a problémát:

...
proba	: proba.o proba1.o
	$(CC) -o $@ $^

proba.o : proba.c
	$(CC) -c $^

proba1.o : proba1.c
	$(CC) -c $^
...

Ebben az a kényelmetlen, hogy kétszer kell felsorolni a forrásfájlokat, és kétszer kell leírni a .c.o fordítás utasítását is. Ezt lehet elkerülni implicit szabállyal:

...
.c.o:
	$(CC) -Wall -c $^
...

A fenti implicit szabály azt adja meg, hogyan kell .c kiterjesztésű fájlból .o-t előállítani. Ez helyettesíti a két .o kiterjesztésű cél szabályát. Amikor a proba cél előfeltételeiben a make találkozik proba.o-val, és nem talál ezt előállító szabályt, megpróbál olyan implicit szabályt keresni, mely előállít ilyen kiterjesztésű fájlt.

Háromféle implicit szabály létezik:

  • mintaillesztéses[5]
  • kiterjesztéses, más néven hagyományos (fenti példa)
  • beépített.

A mintaillesztéses implicit szabály a hagyományos kiterjesztése.

A make-nek vannak beépített implicit szabályai, pl. a .c.o átalakításra is. Ezek törölhetők, de a törlés hátránya, hogy a Makefile nem lesz hordozható különböző operációs rendszerek között.

.SUFFIXES:
.SUFFIXES: .c .o .1 .gz

Az első sor törli az összes beépített szabályt, de a törléssel a beépített kiterjesztések táblázata is törlődik. A második sor pótolja azt a négy kiterjesztést, melyre a példában szükség van.

Hamis célok[szerkesztés]

A fenti példában az all célú szabállyal probléma lehet, ha az aktuális könyvtárban véletlenül létezik all nevű fájl. Miután nem ritka az ehhez hasonló cél,[6] a probléma elkerülésére külön utasítás szolgál:

.PHONY: all

A .PHONY után írt szavakat céloknak tekinti a make, és előfeltétel ellenőrzésekor végrehajtja a szabályaikat, de nem ellenőrzi, léteznek-e ilyen nevű fájlok.

Példa Makefile-ra[szerkesztés]

.SUFFIXES:
.SUFFIXES: .c .o .1 .gz
.PHONY: all clean
 
.c.o:
	$(CC) -c -Wall $^
 
.1.gz:
	gzip -c <$^ >$@
 
MIND = proba proba.gz
 
all	: $(MIND)
 
proba	: proba.o proba1.o
	$(CC) -o $@ $^
 
clean:
	rm -f $(MIND) *.o

A -WaLL a C-fordító kapcsolója: bekapcsolja az összes figyelmeztetést.

Az rm parancsban fontos a -f: az rm – következésképp a make is – hibát jelez, ha nem létezik valamelyik törlendő fájl. A hibajelzést szünteti meg a kapcsoló.

Jegyzetek[szerkesztés]

  1. A make nem tudja kezelni a helyközt tartalmazó fájlneveket, és linuxban szimbolikus link esetén az eredeti (helyközös) néven dolgozza fel a fájlokat. Hard linkkel lehet áthidalni a problémát.
  2. GNU make implicit változóinak listája (GNU operating system)
  3. Automatikus változók (GNU operating system)
  4. Az all nem fenntartott szó; szokás így nevezni az összes célt előállító szabályt.
  5. Defining and Redefining Pattern Rules (GNU operating system)
  6. Pl. általánosan elterjedt a clean cél használata a make által létrehozott fájlok törlésére, ami után a paraméter nélküli make újrafordítja a teljes programot.

Forrás[szerkesztés]

Kapcsolódó szócikkek[szerkesztés]