Správa projektu pomocí programu Make

[  Program make  |  Makefile  |  Komentáre  |  Promenné  |  Pravidla  |  Vyhodnocení pravidel  |  Slozitejsí makefile  |  Preklad projektu s moduly  ]

Program make

Make je program pro automatické kompilování programu, které jsou slozeny z více souboru. Vyuzijeme jej vsak i u jednoduchých projektu, které jsou tvoreny jediným zdrojovým souborem. Program make totiz umí daleko více nez jen prekládat. Muzeme pomocí nej spravovat celý projekt. Ukázeme si, ze s jeho pomocí hrave vycistíme celý projekt od pomocných souboru vytvorených prekladacem nebo zálozních souboru vytvorených editorem. Také si ukázeme, jak vsechny dulezité soubory projektu zabalit do archívu a dalsí uzitecné veci.

Podrobnejsí informace o programu make najdete na jeho manuálové stránce (man make), na info stránce (info make) nebo na webu. V tomto dokumentu jsou popsány pouze základní vlastnosti, které jsou potrebné pro zacátecníky - zejména pri resení projektu kurzu IZP. Podrobneji se pouzívání programu make probírá v kurzu IJC.

Existuje více verzí programu make, zejména na ruzných platformách. Program make je soucástí distribucí GCC (ve Windows MinGW, Cygwin), ale i komercních prekladacu (napr Borland). Dokonce i vetsina vizuálních prostredí umoznuje pro kazdý projekt vygenerovat makefile. Základní principy vsech verzí jsou vsak stejné.

Makefile

Aby program make vedel, co má s projektem delat, potrebuje k tomu soubor se jménem makefile. Je to obycejný textový soubor, který je nejlépe umístit v hlavním adresári projektu. Celý makefile se skládá ze specifikace pravidel a promenných. Na následujícím príkladu si ukázeme makefile, pro preklad programu skládajícího se z jediného zdrojového souboru helloworld.c (císla rádku jsou zde jenom proto, abych se na ne mohl odkazovat).

01 #
02 # Projekt: Hello world!
03 # Autor:   David Martinek
04 # Datum:   11.12.2012
05 # 
06 
07 CC=gcc                              # prekladac jazyka C
08 CFLAGS=-std=c99 -Wall -pedantic -g  # parametry prekladace
09
10 hello: helloworld.c
11 	$(CC) $(CFLAGS) helloworld.c -o hello
12

Komentáre

Jak je videt, komentáre se uvozují znakem # (mrízka). Komentár koncí na konci rádku. Je docela dobré na zacátek souboru makefile vlozit hlavicku s podpisem, datem vytvorení a pokud je to slozitejsí makefile, tak i s popisem nejdulezitejsích cílu.

Promenné

Na rádcích 7 a 8 je specifikace promenných. V tomto prípade jsem si takto definoval prekladac a parametry prekladu. Promenné je mozné definovat kdekoli v souboru. Hodnotu promenné získáme tak, ze napíseme $(JMENOPROMENNE), jak je videt na rádku 11.

Pravidla

Nejdulezitejsí cástí souboru makefile je specifikace pravidel. V nasem souboru je jednoduché pravidlo na rádcích 10 a 11. Kazdé pravidlo se skládá z cíle, závislostí a kódu. V nasem prípade se cíl jmenuje hello (rádek 10), závislost je v tomto prípade pouze jediná - hello.c. Název cíle musí být ukoncen dvojteckou. Závislostí muze být libovolný pocet (tedy i nulový) a jsou vzájemne oddeleny mezerami. Jako závislosti se pouzívají jména souboru nebo názvy jiných cílu. Kód naseho pravidla najdeme na rádku 11. Kód musí následovat bezprostredne za specifikací cíle. Není mozné vkládat prázdné rádky. Rádky s kódem musí zacínat tabulátorem! Blok kódu koncí rádkem, který nezacíná tabulátorem. Obecne vypadá pravidlo takto:

cíl: [závislosti]
  [príkaz]
  [príkaz]
  ...

Pokud je cíl jméno souboru, znamená to, ze pravidlo bude generovat soubor s tímto jménem. Potom se v závislostech musí uvést jména vsech souboru, které jsou potreba ke zkonstruování cíle. V prípade projektu v jazyce C, je potreba zde uvést jméno zdrojového souboru (.c) a jména vsech lokálních hlavickových souboru (.h), které tento zdrojový soubor pouzívá.

Vyhodnocení pravidel

Program make jde spoustet dvema zpusoby. V obou prípadech je nutné spoustet program make v adresári, kde se nachází soubor makefile. První zpusob je spoustení make bez parametru

$ make
gcc -std=c99 -Wall -pedantic -g helloworld.c -o hello

Vyhodnocení potom probíhá tímto zpusobem:

  1. Program make vyhledá pravidlo, které se v souboru makefile vyskytuje na prvním míste. Program make spustený bez dalsích parametru spoustí vzdy první pravidlo. Na poradí ostatních pravidel potom nijak nezálezí.
  2. Pokud se v závislostech tohoto pravidla (cást za dvojteckou v hlavicce pravidla) vyskytují cíle jiných pravidel, nejprve se vyhodnotí vsechna tato pravidla v poradí v jakém jsou vyjmenována za dvojteckou. Vyhodnocení ostatních pravidel nezálezí na poradí jejich uvedení v souboru, ale na poradí, v jakém jsou uvedeny v závislostech práve zpracovávaných pravidel.
  3. Pokud je cíl jméno souboru a v závislostech se také vyskytují jména souboru, pravidlo se vykoná pouze tehdy, je-li cas vytvorení cílového souboru starsí nez cas nekterého souboru v seznamu závislostí. Jinými slovy, pravidlo se vykoná jen kdyz je to potreba, tj. kdyz se zdrojový kód zmenil od posledního prekladu.

V nasem prípade se spustí preklad souboru helloworld.c a výsledkem bude spustitelný soubor hello. V prostredí Windows bychom museli makefile upravit tak, aby se generoval soubor hello.exe.

Druhý zpusob spoustení programu make si vysvetlíme vzápetí.

Slozitejsí makefile

Preklad není to jediné, co jde s programem make delat. Následující Makefile umí nejenom prekládat, ale také pakovat do archívu, odstranovat zbytecné soubory a spoustet debugger.

#
# Projekt: Hello world!
# Autor:   David Martinek
# Datum:   10.10.2012
# 
# Pouzití:
#   - preklad:      make
#   - ladit:        make debug
#   - zabalit:      make pack
#   - vycistit:     make clean
#   - vycistit vse: make clean-all
#

NAME=hello

CC=gcc                                # prekladac jazyka C
CFLAGS=-std=c99 -Wall -pedantic -g # parametry prekladace

ALLFILES=helloworld.c makefile        # obsah projektu

$(NAME): helloworld.c
	$(CC) $(CFLAGS) helloworld.c -o $(NAME)

.PHONY: debug pack clean clean-exe clean-all

debug: $(NAME)
	export XEDITOR=gvim;ddd $(NAME)

pack:
	tar cvzf $(NAME).tar.gz $(ALLFILES)
	zip $(NAME).zip $(ALLFILES)

clean:
	rm -f *~ *.bak
  
clean-exe:
	rm -f $(NAME)

clean-all: clean-exe clean

Pokud nyní spustím program make bez parametru, bude se chovat zpusobem popsaným výse. Pokud jako parametr pouzijeme cíl nekterého z pravidel, vykoná se toto zadané pravidlo.

Zvlástní pozornost zaslouzí cíl .PHONY. Toto pravidlo slouzí pro oznacení tzv. falesných cílu - tedy cílu, které nemají význam "cílový soubor", ale spíse "návestí". Tyto falesné cíle neprodukují soubory shodné se svým jménem. Tyto cíle se pouzívají práve k tomu, aby se spoustely pres parametr programu make. Pokud by cíl .PHONY v souboru makefile nebyl, pravdepodobne by to nemelo vliv na jeho funkcnost. Problémy by mohly nastat, kdyby se v nasem adresári objevil soubor, jehoz jméno se shoduje s nekterým falesným cílem. Program make by se potom pokousel porovnávat cas jeho vytvorení a pravidlo by prestalo fungovat. Proto je dobré cílem .PHONY oznacit vsechny falesné cíle, abychom se vyhnuli prípadným problémum.

Preklad projektu s moduly

Vsechny predchozí príklady slouzily k prekladu programu, který je tvoren jediným zdrojovým souborem. Program make ovsem predevsím slouzí k prekladu projektu, které jsou tvoreny více moduly (viz kapitolu Moduly a knihovny). U techto projektu je potreba vytvorit v Makefile pravidlo pro generování objektového souboru kazdého modulu a také pravidlo pro jejich slinkování. Pokud pridáme na zacátek souboru Makefile pomocné startovací pravidlo, nezálezí na poradí jednotlivých pravidlel pro preklad modulu.

# pomocné startovací pravidlo, nemá zádné telo, slouzí jenom jako odkaz
all: program

modul1.o: modul1.c modul1.h
	$(CC) $(CFLAGS) -c modul1.c -o modul1.o
modul3.o: modul3.c modul3.h
	$(CC) $(CFLAGS) -c modul2.c -o modul2.o
modul2.o: modul2.c modul1.h modul2.h
	$(CC) $(CFLAGS) -c modul2.c -o modul2.o
program.o: program.c modul1.h modul2.h modul3.h
	$(CC) $(CFLAGS) -c program.c -o program.o
program: modul1.o modul2.o modul3.o program.o
	$(CC) $(CFLAGS) modul1.o modul2.o modul3.o program.o -o program

Protoze tyto cinnosti jsou velmi casté, lze si usetrit práci a vyuzitím tzv. univerzálních pravidel a promenných.

NAME=program
OBJFILES=$(NAME).o modul1.o modul2.o modul3.o

CC=gcc
CFLAGS=-std=c99 -Wall -pedantic -W -g

# univerzální pravidlo pro generování vsech objektových souboru
%.o : %.c
	$(CC) $(CFLAGS) -c $<

# Startovací pravidlo
all: $(NAME)

## ## ## 
# pravidla bez tela - to se sem doplní z univerzálního pravidla
modul1.o: modul1.c modul1.h
modul2.o: modul2.c modul1.h modul2.h
modul3.o: modul3.c modul3.h
program.o: program.c modul1.h modul2.h modul3.h
## ## ## 

# Slinkování vsech objektových souboru do jednoho spustitelného programu.
$(NAME): $(OBJFILES)
	$(CC) $(CFLAGS) $(OBJFILES) -o $@

Vytvárení cásti predchozího souboru Makefile, která je oznacena rádky s textem ## ## ##, lze generovat automaticky. Je to mnohem spolehlivejsí, nez vytváret závislosti rucne.

## ## ## 
# Generování závislostí
dep: 
	$(CC) -MM *.c >dep.list

## vlozí vygenerované závislosti
-include dep.list
## ## ## 

Vzdy, kdyz se závislosti zmení (tj. vytvoríte nový modul nebo hlavickový soubor), je potreba rucne zavolat pravidlo make dep a vytvorit tak soubor dep.list, který bude obsahovat vsechna potrebná pravidla pro generování modulu i s jejich skutecnými závislostmi. Poté, co je tento soubor vytvoren, se preklad spoustí obvyklým zpusobem pomocí volání programu make.


Autor: David Martinek. Poslední modifikace: 11. December 2012. Pokud v tomto dokumentu narazíte na chybu, dejte mi prosím vedet.