Sestavení aplikace
Kvůli snažšímu proniknutí do problematiky sestavení aplikace si na začátku připomeneme všechny základní kroky, z kterých je proces sestavení aplikace složen. Tak logicky najdeme místo v tomto procesu, kde program make bude velmi užitečný.
Víme, že aplikace v jazyce C/C++ se skládá z jednoho nebo více souborů zdrojového kódu (přípona .c nebo .cpp), které nazýváme překladovými jednotkami. Preprocesor do těchto překladových jednotek nejprve vloží hlavičkové soubory, rozvine makra, nahradí symbolické konstanty atd. Kompilátor pak kompilací vytvoří pro každou překladovou jednotku odpovídající objektový soubor, což je binární soubor (v našem případě ve formátu elf), který obsahuje sekce s globálními a statickými proměnnými, sekci s vlastním strojovým kódem a další sekce. Nakonec přijde ke slovu linker a ten sloučí (slinkuje) všechny objektové soubory a případně i knihovny do jednoho výsledného spustitelného souboru.
Kompilátor v akci
Na jednoduchém příkladě si ukážeme, jak docílit sestavení aplikace helloarm bez použití programu make. Zdrojový kód (main.c) ukázkové aplikace je na výpisu 1:
1#include <stdio.h> 2 3int main(void) 4{ 5 printf("Ahoj! Tady je Arm!)\n"); 6 7 return 0; 8}
Protože pro výstup na obrazovku používáme knihovní funkci printf(), tak nesmíme zapomenout přilinkovat k naší aplikaci i knihovnu libc.
Sestavením aplikace pověříme křížový kompilátor gcc z vývojového prostředí SourceryG++ pro platformu ARM, který za nás zavolá preprocesor, provede vlastní křížovou kompilaci a dokonce sám zavolá i křížový linker a přikáže mu, aby slinkoval aplikaci s knihovnou libc:
$ arm-none-linux-gnueabi-gcc -march=armv5te -mabi=aapcs-linux -o helloarm main.c
Výsledkem je spustitelný soubor helloarm, který při spuštění na cílovém zařízení vypíše na standardní výstup (systémovou konzoli) řetězec ”Ahoj! Tady je Arm!”.
Pro úplnost dodejme, že ke spuštění aplikace helloarm, musí být na cílovém zařízení k dispozici dynamický linker/loader (ld-linux.so) a dynamická knihovna libc, jelikož výchozí způsob linkování knihoven je dynamickýRozdíly mezi statickým a dynamickým linkováním jsou pěkně vysvětleny zde: http://cs.wikipedia.org/wiki/Knihovna_(programování) (knihovna libc je k aplikaci přilinkována ve skutečnosti až při startu aplikace).
Něco málo k nastavení kompilátoru. Volba -march=armv5te informuje kompilátor, že cílová architektura je ARMv5TE, tzn. že cílový procesor používá instrukční sadu definovanou touto architekturou. Volba -mabi=aapcs-linux je povinnáK nastavení gcc pro ARM EABI více viz: http://wiki.debian.org/ArmEabiPort, protože naše aplikace používá a splňuje požadavky rozhraní ARM EABIDefinice pojmů ABI a EABI je např. zde: http://en.wikipedia.org/wiki/Application_binary_interface.
V souvislosti s nastavením kompilátoru si dovolím malou výchovnou poznámku: Architektura ARMv5TE je v případě použitého kompilátoru výchozí. Volba -march=armv5te je proto z pohledu správného nastavení kompilátoru zbytečná. Ovšem je dobrým zvykem uvádět explicitně i výchozí volby. Pro někoho, kdo detailně nezná vlastnosti použitého kompilátoru, je pak snazší pochopit nastavení kompilátoru.
Asi si teď říkáte proč vlastně používat program make, když stačí volat přímo kompilátor. Jenže aplikací, které jsou tak jednoduché jako naše HelloArm, je mizivé množství. Představte si, že byste měli vždy znovu a znovu vypisovat na příkazový řádek seznam všech překladových jednotek, z kterých se skládá aplikace, pak seznam knihoven, vůči kterým se linkuje ... Ne, takto se to opravdu nedělá. Od téhle otročiny tu máme make a dobře napsaný makefile.
Výhodou dvojice make a makefile je, že sestavení aplikace s pomocí make nevyžaduje detailní znalosti o způsobu sestavení aplikace. Ty jsou zapsány právě v makefile. Takže takřka kdokoliv je schopen si i velmi složitou aplikaci sestavit sám.
Další výhodou je, že make umí zjistit, které soubory byly od posledního sestavení změněny a zpracuje pouze tyto soubory, případně ještě ty, které na nich závisí. Nemusí se tak pokaždé při změně byť jediného souboru kompilovat celá aplikace.
Make v akci
Umíme sestavit jednoduchou aplikaci bez použití programu make. Zopakujme si, proč je použití programu make a souboru makefile výhodné a jaké výhody nám to přináší. Jinými slovy, co získáme za námahu spojenou s vytvářením souboru makefile:
- Kdokoliv, kdo si chce zkompilovat vaši aplikaci, není nucen znát podrobný postup. To za něj řeší vámi napsaný makefile.
- Make není závislý ani na jazyku ani na platformě. Jen interpretuje a vykonává příkazy zapsané v souboru makefile podle daných pravidel.
- S pomocí make můžete nejen sestavit vaši aplikaci, ale můžete ji také nainstalovat nebo zase odinstalovat.
- Make umí zjistit, které překladové jednotky se od posledního sestavení změnily, a přeloží a znovu slinkuje jen ty.
- Postup sestavení aplikace vymyslíte jen jednou. Zapíšete jej do makefile a pak už jen sestavujete a sestavujete a ...
Motivační úvod je za námi a teď je už nejvyšší čas, abychom si ukázali, jak snadno sestavíme naši ukázkovou aplikaci s pomocí make:
$ cd HelloArm/ $ make
Nic víc nic míň. Program make vyhledal v aktuálním adresáři (adresář aplikace, v kterém byl make spuštěn) soubor makefile, načetl si jeho obsah a provedl všechny předepsané kroky. My jsme jen točili prstem. Lidově řečeno.
Z výstupu na obrázku 1.1 vidíme, že make nejprve zavolal kompilátor, aby přeložil všechny překladové jednotky na objektové soubory a pak přikázal linkeru, aby objektové soubory slinkoval spolu s knihovnou libc do spustitelného souboru. Výsledkem je spustitelný soubor helloarm.
Obsah souboru makefile, který make během své práce interpretoval a který popisuje postup sestavení naší ukázkové aplikace, je na výpisu 2.
1# ——————————————————————-- 2# prefix cross-nastroju 3CROSS_PREFIX=arm-none-linux-gnueabi- 4 5# kompilator 6CC=gcc 7 8# linker 9LD=gcc 10# ——————————————————————-- 11# volby kompilatoru pro danou architekturu 12CFLAGS_ARCH=-march=armv5te -mabi=aapcs-linux 13 14# obecne volby kompilatoru 15CFLAGS=-g -Os -Wall 16 17# volby predavane linkeru 18LDFLAGS= -march=armv5te 19# ——————————————————————-- 20# cesty k hlavickovym souborum 21INCLUDE_PATHS= -I.\ 22 23# cesty ke knihovnam pro linkovani 24LIB_PATHS= -L.\ 25# ——————————————————————-- 26# nazev spustitelneho souboru 27TARGET=helloarm 28 29# knihovny, ktere se maji prilinkovat k aplikaci 30LIBS= -lc\ 31 32# objektove soubory 33OBJS= main.o\ 34# ==================================================================== 35# vychozi pravidlo 36all: $(TARGET) 37 38# pravidlo pro linkovani 39$(TARGET): $(OBJS) 40 $(CROSS_PREFIX)$(LD) $(LDFLAGS) $(LIB_PATHS) $(OBJS) $(LIBS) -o $(TARGET) 41 42# pravidlo pro kompilaci 43%.o:%.c 44 $(CROSS_PREFIX)$(CC) $(INCLUDE_PATHS) $(CFLAGS_ARCH) $(CFLAGS) -c -o $@ $< 45 46# pravidlo pro uklid 47clean: 48 rm -f *.o ${TARGET} 49 50.PHONY: all 51.PHONY: clean
Vysvětlivky:
Na řádcích 3 - 33 nastavujeme proměnné, které se pak použijí dále v pravidlech nebo k nastavení jiných proměnných. Pro přehlednost uvádíme vždy v závorce název proměnné, která bude dané nastavení obsahovat.
Řádky 3 - 9: Uložíme si nastavení použitého kompilátoru (CC), linkeru (LD) a prefixu jejich názvu (CROSS_PREFIX).
Řádky 12 - 18: Definujeme volby, s kterými bude kompilátor volán (CFLAGS a CFLAGS_ARCH), a volby, které kompilátor předá linkeru (LDFLAGS).
Řádky 21 - 24: Nastavíme si cesty k hlavičkovým souborům (INCLUDE_PATHS) a knihovnám (LIB_PATHS), které se přidají do výchozího seznamu prohledávaných cest.
Řádky 27 - 33: Určíme jméno výsledného spustitelného souboru (TARGET), seznam použitých knihoven (LIBS), které je třeba k aplikaci přilinkovat, a seznam všech objektových souborů (OBJS), které je nutné pro sestavení aplikace vytvořit.
Řádek 36: Výchozí pravidlo pro sestavení aplikace, které se použije, pokud je makefile volaný bez parametru.
Řádek 39: Linkovací pravidlo, které říká, že se spustitelný soubor helloarm skládá z objektových souborů přístupných v proměnné OBJS. Definuje příkaz pro linkování aplikace.
Řádek 43: Kompilační pravidlo, které je univerzální šablonou pro jakýkoliv objektový soubor. Říká, že objektový soubor se vytvoří kompilací stejnojmenného zdrojového souboru.
Řádek 47: Úklidové pravidlo, které zajišťuje vymazání všech objektových souborů a spustitelného souboru helloarm.
Řádek 50 a 51: Speciální pravidla, které říkají programu make, že cíl all a ani cíl clean nejsou skutečnými soubory, ale jen pomocnými cíly. Zajišťují funkčnost pomocných cílů i v případě, že existují soubory se stejnými jmény.
Poznámka: volba -lc říká, že se do seznamu knihoven (LIBS) má přidat knihovna libc. Linker totiž jméno souboru knihovny rozšíří automaticky i o předponu lib a odpovídající koncovku podle typu linkování.