Urobme niečo s `make` 2.

make je skvelý nástroj na zostavovanie projektov v Linuxe. Miestami je síce značne obskúrny, ale čuduj-sa-svete, dá sa použiť aj veľmi jednoduchým spôsobom, a to aj v prípade, že chceme zostavoať len smiešne zápočtoidné súbory.

Ukážeme si, ako možno ľahko vytvoriť zopár zostavovacích súborov (makefileov) pre tieto prípady, ba dokonca, že si možno veľmi dlho vystačiť aj bez nich a napriek tomu kompilovať céčka.

Do práce!

Vzorový súbor

Na veselenie sa s makeom použime klasický “Ahoj svet” súbor:

#include<stdio.h>

int main(void) {
  printf("Hello World!");
  return 0;
}

Zostavenie len tak, bez nastavení

Mnohí si ani nevedia predstaviť, že make funguje aj bez špeci nastavení. Ale súbor hello.c môžeme naozaj zmakeovať len tak!

make hello

Zo zostavenia automaticky vypadne súbor hello, ktorý môžeme spustiť:

./hello

Čo sa vlastne stalo? Na mnohých moderných systémoch sa uskutočnilo toto:

gcc hello.c -o hello

Pre pokročilých: čo sa stalo na pozadí?

Make sme spustili s cieľom hello. Vďaka zabudovaným nastaveniam sa na základe mena cieľa hello vyhľadá súbor hello.c, skompiloval sa kompilátorom cc a vypadla z neho binárka s názvom hello.

V skutočnosti sa vykoná:

cc     hello.c   -o hello

Na vzorovom Debiane je cc nalinkovaný na gcc:

novotnyr@s:~/$ which cc
/usr/bin/cc

novotnyr@s:~/$ ls /usr/bin/cc -l
lrwxrwxrwx 1 root root 20 Sep 29  2011 /usr/bin/cc -> /etc/alternatives/cc

novotnyr@s:~/$ ls /etc/alternatives/cc
lrwxrwxrwx 1 root root 12 Sep 29  2011 /etc/alternatives/cc -> /usr/bin/gcc

Pre veľmi pokročilých: Ako prebehne vyhľadávanie?

Nahliadnime do špecifikácie POSIX:

Ak cieľ, ktorý sa má zostaviť, neobsahuje príponu a pre tento cieľ neexistuje žiadne pravidlo, overia sa jednopríponové odvodzovacie pravidlá. […] Jednopríponové pravidlá určujú ako zostaviť cieľ, za predpokladu, že existuje súbor s menom tvoreným z mena cieľa a prípony z pravidla.

Pri našom make hello máme cieľ, ktorý naozaj neobsahuje príponu a dokonca preň neexistuje žiadne pravidlo (písali sme ho niekde? nie). Prejdú sa tak všetky zabudované odvodzovacie pravidlá (inference rules), pre ktoré existuje v systéme súbor s menom hello a príponou definovanou v pravidle. Jediný kandidát je pravidlo pre céčkarské súbory:

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

Vďaka tomuto pravidlu:

  • zavolá sa štandardný kompilátor cc, čo je hodnota premennej CC.
  • využijú sa štandardné parametre kompilátora definované v premennej CFLAGS. V GNU kompilátore je táto premenná prázdna, v POSIXovej verzii má hodnotu -O.
  • využijú sa štandardné hodnoty pre linker, definované v premennej LDFLAGS, ktorá je v POSIXovej verzii prázdna
  • premenná < obsahuje názov súboru, vďaka ktorému sa vybralo toto pravidlo, čiže hello.c
  • premenná $@ obsahuje zase meno aktuálneho cieľa (teda hello). Podľa neho sa teda určí meno binárky na výstupe z kompilátora.

Zmena kompilátora v makefile

Čo ak chceme doladiť nastavenia kompilátora? Napríklad chceme vždy a zakaždým používať gcc a nespoliehať sa na fakt, že zhodou okolností bude v systéme gcc aliasom cc?

Vytvorme si makefile, teda súbor popisujúci zostavenie projektu. Aká náhoda, bude sa volať makefile a bude obsahovať jediný riadok:

CC=gcc

Skúsme opäť spustiť:

make hello

Môžeme vidieť dva prípady. Asi už existuje binárka z predošlého zostavenia a dostaneme hlášku, že nie je čo zostavovať, lebo všetko je už hotové:

make: `hello' is up to date.

Zbavme sa jej (tej binárky), aby sme ju zostavili nanovo:

rm hello

A spusťme make nanovo:

make hello

make prevezme existujúci makefile a na zostavenie využije gcc

gcc     hello.c   -o hello

V makefile sme totiž nastavili premennú CC, ktorá udáva názov kompilátora pre céčkarske zdrojáky, teda súbory s príponou .c.

Pre pokročilých: Čo sa stalo na pozadí?

Premenná CC sa použila v zabudovanom odvodzovacom pravidle z predošlej úlohy.

Zmena parametrov pre kompilátor

Ak začíname s céčkom, je dobré si pri kompilovaní dodať mnoho parametrov, ktoré upozornia na problémy v zdrojákoch. Jeden z kompilačných úsloví:

gcc -Wall -Wextra -Werror -pedantic -ansi hello.c -o hello

Aj toto vieme nastaviť v makefile, stačí nastaviť premennú CFLAGS˙:

CC=gcc
CFLAGS=-Wall -Wextra -ansi -pedantic -Werror

Skúsme si opäť zostaviť projekt cez make hello:

novotnyr@s:~/$ make hello
gcc -Wall -Wextra -ansi -pedantic -Werror    hello.c   -o hello

Cieľ pre upratanie binárok a poradie cieľov

Často sa hodí Lojzo Čistič, teda cieľ clean, pomocou ktorého upraceme vykompilované binárky. V demonštračnom projekte upraceme ručne jednoducho:

rm hello

Celý makefile môže vyzerať nasledovne. Pozor však, je to pasca!

CC=gcc
CFLAGS=-Wall -Wextra -ansi -pedantic -Werror

clean:
        rm hello

Zavolanie make hello bude bežať bez problémov. Skúste však omylom zavolať len samostatný make! Buď si zmažete binárky, alebo dôjde k chybe!

novotnyr@s:~/$ make
rm hello
rm: cannot remove `hello': No such file or directory
make: *** [clean] Error 1

Ak zabudnete v make uviesť názov cieľa, vykoná sa prvý cieľ uvedený v makefile… v našom prípade čistenie.

To teda nie je ktoviečo.

Opraviť to môžeme cieľom-necieľom, ktorý bude v makefile uvedený ako prvý, ale v skutočnosti len bude kričať, že takto sa makefile používať nemá. Tradícia káže tento prvý cieľ pomenovať all:

CC=gcc
CFLAGS=-Wall -Wextra -ansi -pedantic -Werror

all: hello

clean:
        rm hello

Na vykonanie cieľa all treba vykonať cieľ hello (hello je prerekvizita all), a to prebehne podľa pravidiel z predošlých ukážok (ak ste dávali pozor).

Ak teraz zavoláme make bez cieľa, uvidíme klasickú hlášku, ktorú čakáme

gcc -Wall -Wextra -ansi -pedantic -Werror    hello.c   -o hello

Zovšeobecnenie!

Ak narýchlo vyrábame kopu nezávislých céčkarských súborov (lebo napríklad chodíme na UINF/JAC1), hodí sa univerzálny nástroj: teda univerzálny makefile, ktorý sa strčí do adresára s kopou zdrojákov a dá sa použiť podľa potreby na ten zdroják, ktorý potrebujeme.

Oprava implicitnieho cieľa

Najprv opravme cieľ all, lebo už sa nemôžeme spoliehať na zadrôtovaný názov cieľa. Po novom nech make all, či čistý make vypíše len hlášku o chýbajúcom cieli:

CC=gcc
CFLAGS=-Wall -Wextra -ansi -pedantic -Werror

all:
        echo Chyba meno ciela
clean:
        rm hello

Ak teraz zavoláme make bez cieľa, uvidíme:

novotnyr@s:~/$ make
echo Chyba meno ciela
Chyba meno ciela

Prekáža dvojitý výpis? Využime špeciálny cieľ .SILENT, ktorému do prerekvizít nasekajme názvy cieľov, pri ktorých má byť make ticho — teda nemá vypisovať ich príkazy.

CC=gcc
CFLAGS=-Wall -Wextra -ansi -pedantic -Werror

.SILENT: all

all:
        echo Chyba meno ciela
clean:
        rm hello

Čistič verzie 2.0

Podobne môžeme opraviť čistenie. Spôsobov je viacero, podľa toho, ako šialene robustné a blbuvzdorné má čistenie byť. Jedno z nebezpečných riešení: vymažme všetky binárky, ktoré nájdeme v adresári. Predpokladáme, že iné binárky, než tie, ktoré vypadli z kompilátora nebudú a teda ich môžeme rmnúť všetky.

clean:
        find . -executable -type f -exec rm {} \;

Využijeme vyhľadávacieho klasika find, ktorým nájdeme všetky spustiteľné (-executable) súbory (-type f), ktoré postupne nasúkame do rm.

Kompletný univerzálny makefile

CC=gcc
CFLAGS=-Wall -Wextra -ansi -pedantic -Werror

.SILENT: all

all:
        echo Chyba meno ciela
clean:
        find . -executable -type f -exec rm {} \;

Ako spustiť projekt?

Celý projekt nanovo vymažeme a skompilujeme cez:

make clean hello

Binárku spustíme klasickým spôsobom:

./hello

Do kompilovania!

Pridaj komentár

Vaša e-mailová adresa nebude zverejnená. Vyžadované polia sú označené *