Introduction to Modular Programming

nástroj make, konfiguračný súbor Makefile

Motivácia

V prvom zadaní, do ktorého sa tento týždeň pustíte, budete mať okrem iného za úlohu vytvoriť dva samostatné moduly. Aby ste ich zvládli vytvoriť a správne manažovať, naučíte sa na tomto cvičení konfigurovať nástroj make pomocou jeho konfiguračného súboru Makefile. Táto znalosť vám v budúcnosti pomôže pri práci na rozsiahlejších projektoch, ktoré sa budú skladať z viacerých samostatných modulov.

Ciele

  1. Naučiť sa vytvoriť vlastný konfiguračný súbor Makefile
  2. Naučiť sa vytvárať vlastné ciele (targets) v súbore Makefile
  3. Porozumieť modulárnemu programovaniu v jazyku C.

Postup

Project Creation

V prvom kroku si vytvoríte nový projekt na GitLab-e, do ktorého budú postupne pribúdať vaše zadania.

Úloha 1.1

Prihláste sa na GitLab a vytvorte si nový projekt s názvom prog-2019.

Poznámka

Nezabúdajte, že záleží na veľkosti písmen! Ak sa názov vášho projektu nebude volať presne prog-2019, Aréna ho nebude vedieť identifikovať a tým pádom ani vyhodnotiť.

Súčasťou projektu je aj súbor README, ktorý obsahuje len jeden riadok s informáciou o skupine, ktorú navštevujete na cvičeniach v tvare:

GROUP : A1

Pokiaľ len skopírujete a vložíte postupnosť príkazov priamo z GitLab-u, nezabudnite súbor README.md premenovať na súbor README.

Úloha 1.2

Zo stránky so zadaním projektu Top Secret si stiahnite jeho kostru.

Pokiaľ poznáte adresu súboru na stiahnutie, môžete si ho stiahnuť pomocou príkazu wget v tvare:

kde URL je adresa súboru na stiahnutie. Súbor sa následne stiahne do priečinka, v ktorom ste tento príkaz zadali.

Pre rozbalenie zip balíku môžete s výhodou použiť konzolový nástroj unzip v tvare:

kde FILE je názov, resp. cesta k zip balíku na rozbalenie.

Úloha 1.3

Vytvorte si vo svojom projekte priečinok ps1/ a prekopírujte do neho všetky potrebné súbory z kostry zadania Top Secret.

Presná podoba štruktúry projektu tohto zadania sa nachádza na stránke požiadaviek. V štruktúre projektu sa však nenachádzajú všetky potrebné súbory. Prázdne súbory môžete vytvoriť buď príkazom touch alebo uložením prázdneho súboru vo vašom editore. Ak následne sputíte príkaz tree nad priečinkom projektu prog-2019, jeho výstup by mal vyzerať nasledovne:

Poznámka

Ak pridáte do svojho projektu nový súbor, je dobrým zvykom ho pridať rovno aj do git projektu pomocou príkazu

git add FILE

Úloha 1.4

V súbore bmp.c vytvorte implementáciu funkcie reverse().

Úloha 1.5

Otestujte vytvorenú funkciu reverse() v hlavnej funkcii main() v súbore main.c.

Pre otestovanie môžete použiť napr. fragment kódu, ktorý sa nachádza v opise funkcie reverse() v špecifikácii zadania:

Úloha 1.6

Preložte a spustite projekt.

Program sa pokúste preložiť pomocou prekladača gcc spolu so zoznamom všetkých prepínačov, ktoré sú uvedené na stránke zadania. Výsledný spustiteľný súbor nech sa volá jednoducho ps1.

Úloha 1.7

Aktualizujte svoj projekt na git-e.

Okrem pridania súborov do lokálneho repozitára nezabudnite váš aktualizovaný projekt odoslať aj do vzdialeného repozitára. Obsah priečinka ps1/ vášho projektu by sa momentálne mal zhodovať s požadovanou podobou projektu, ako je uvedená na stránke zadania.

Makefile Configuration

V tomto kroku si vytvoríte svoj vlastný súbor Makefile, ktorý bude predstavovať konfiguráciu pre nástroj make. Skladá sa zo zoznamu cieľov (z angl. target) a premenných. Tento súbor sa používa hlavne vtedy, ak pracujete na programe, ktorého kód je uložený vo viacerých súboroch, ako len v jednom.

Úloha 2.1

Vytvorte v súbore Makefile cieľ all, pomocou ktorého bude možné preložiť celý program. Súbor Makefile sa skladá z niekoľkých cieľov, pomocou ktorých je možné zadefinovať príslušné správanie.

Všeobecná štruktúra cieľa vyzerá nasledovne:

pričom:

  • TARGET je názov cieľa,
  • DEPENDENCIES je zoznam závislostí pre zostavenie daného cieľa, a
  • SYSTEM_COMMAND1SYSTEM_COMMANDn je zoznam príkazov, ktoré sa majú v rámci daného cieľa vykonať.

Upozornenie

Je veľmi dôležité, aby prvý znak pred každým príkazom bol znak tabulátor. Ak sa tam bude nachádzať znak medzera, súbor Makefile nebude valídny a nástroj make skončí s chybou.

Vašou úlohou je vytvoriť cieľ s názvom all. V rámci príkazov, ktoré tvoria telo tohto cieľa zabezpečte preloženie programu podobne, ako ste to vykonali v predchádzajúcom kroku.

Poznámka

V tejto úlohe nemusíte použiť žiadnu závislosť a nechajte tak zoznam závislostí prázdny.

Úloha 2.2

Overte funkčnosť vytvoreného cieľa.

Funkčnosť overíte spustením príkazu make nasledovne:

kde TARGET je názov cieľa, ktorý chcete spustiť.

Ak ste postupovali správne, po spustení príkazu make dôjde k preloženiu programu a vytvoreniu spustiteľného súboru ps1.

Poznámka

Ak pri spúšťaní príkazu make neuvediete žiadny cieľ, použije sa prvý cieľ v poradí, ktorý sa v súbore Makefile nachádza.

Úloha 2.3

Vytvorte v súbore Makefile tri ďalšie ciele main.o, playfair.o a bmp.o, pomocou ktorých sa program čiastočne preloží, čím vziknú tri rovnomenné objektové súbory. Upravte cieľ all tak, aby vzniknuté objektové súbory spojil (zlinkoval) do spustiteľného súboru ps1.

Aktuálne nám cieľ all umožňuje preložiť celý program naraz. Na základe troch súborov .c si však môžete všimnúť, že program pozostáva z troch modulov: main, playfair a bmp.

Každý z týchto modulov je možné preložiť samostatne, čím sa vytvorí tzv. objektový súbor. Spojením objektových súborov je možné vytvoriť spustiteľný súbor.

Vytvorte tri nové ciele main.o, playfair.o a bmp.o, pomocou ktorých bude možné preložiť daný modul programu. Výsledkom bude objektový súbor .o. K prekladu použite prepínač -c.

Poznámka

Prepínač -c umožňuje preložiť program bez spojenia (prelinkovania) zdrojových súborov. Výstupom takého prekladu je objektový súbor.

Upravte cieľ all tak, aby k prekladu použil objektové súbory. Spojením týchto súborov vznikne spustiteľný súbor ps1.

Overte funkčnosť všetkých cieľov.

Poznámka

Všimnite si, že k prekladu dôjde zakaždým, keď príkaz make spustíte.

Úloha 2.4

Aktualizujte cieľ all tak, aby k prekladu došlo len vtedy, ak sa niektorý zo súborov obsahujúcich zdrojové kódy aktualizuje.

V predchádzajúcej úlohe pri zostavovaní cieľa neboli použité žiadne závislosti. Závislosti je vo všeobecnosti možné charakterizovať ako súbory, ktoré sú potrebné pre zostavenie daného cieľa. V prípade, ak sa niektorá zo závislostí aktualizuje, nástroj make daný cieľ zostaví (preloží program). Ak pri jeho použití nedošlo k aktualizácii žiadnej závislosti (všetky súbory sú aktuálne), výsledný cieľ nebude zostavený.

Poznámka

Závislosti sa s výhodou používajú v prípadoch, ak zostavujete viacero cieľov. Ak následne urobíte zmenu v jednom súbore, nepotrebujete znovu prekladať všetky súbory, ale preložené budú len tie ciele, ktorých sa táto zmena dotkne.

Ako závislosti v tomto prípade použite všetky súbory, ktoré sa podieľajú na zostavení výsledného spustiteľného programu.

Úloha 2.5

Overte funkčnosť aktualizovaných cieľov a pridajte cieľ ps1.

Ak spustíte príkaz make s cieľom bmp.o alebo playfair.o tentokrát, k prekladu dôjde len vtedy, keď sa zmení niektorý zo súborov uvedených ako závislosti.

Avšak ak spustíte príkaz make s cieľom all, stále dôjde k prekladu, aj keď sa súbory v závislostiach nezmenili. Dôvodom je to, že nástroj make sa snaží nájsť súbor s rovnakým názvom, aký je názov cieľa, t.j. all.

Vytvorte preto nový cieľ s rovnakým názvom, aký má výstup celého prekladu: ps1. Tento cieľ bude mať rovnaké závislosti ako cieľ all a po jeho zavolaní sa vykoná rovnaká operácia. Pôvodný cieľ all potom zmeňte tak, aby sa priamo odvolával na nový cieľ ps1.

Overte funkčnosť aktualizovaného cieľa all. K prekladu by malo dôjsť iba ak došlo k zmene v niektorom zo súborov.

Úloha 2.6

Nahraďte v príkaze na preklad meno prekladača, zoznam jeho prepínačov a zoznam potrebných knižníc pomocou premenných.

Použitie premenných v súbore Makefile je výhodné v situáciách, keď definujete viacero cieľov, poprípade máte zadefinovaných viacero príkazov pri jednom cieli. Jednoducho tak môžete zmeniť alebo aktualizovať napr. prekladač, zoznam jeho parametrov alebo knižníc požadovaných pri preklade.

Vytvorte preto v súbore Makefile tieto premenné:

  • CC - názov, resp. absolútna cesta k prekladaču
  • CFLAGS - zoznam prepínačov pre prekladač
  • LDLIBS - zoznam knižníc potrebných pre preklad
  • OUTPUT - názov výsledného spustiteľného súboru

Inicializácia premennej vyzerá podobne ako v jazyku C, akurát nie je potrebné uvádzať jej typ:

Na mieste, kde chcete použiť hodnotu premennej, zapíšete túto premennú v tvare:

Poznámka

V súbore Makefile je možné rovnako používať aj komentáre. Makefile podporuje len jednoriadkové komentáre a riadok, ktorý začína znakom '#' bude ignorovaný. Poprípade ignorovaná bude aj časť riadku za týmto znakom.

Úloha 2.7

Overte funkčnosť aktualizovaných cieľov.

Pokiaľ ste postupovali správne, funkcionalita zostane nezmenená.

Úloha 2.8

Pridajte pred príkaz s prekladom statickú kontrolu kódu pomocou nástroja cppcheck a overte funkčnosť vašej úpravy.

Ako bolo uvedené vyššie, v jednom pravidle sa môže nachádzať aj viac príkazov ako len jeden. Ak sa tak stane, tak v prípade, že dôjde pri vykonávaní niektorého príkazu ku chybe (návratový kód príkazu bude iný ako 0), žiadne ďalšie príkazy sa nebudú vykonávať. Túto vlastnosť je teda možné úspešne zahrnúť aj do procesu prekladu, kedy pred samotným prekladom použijeme nástroje napr. na statickú analýzu kódu alebo na jeho formátovanie a až potom sa vykoná samotný preklad.

Nástroj cppcheck slúži na statickú analýzu kódu. Pri kontrole zadaní sa cppcheck bude používať nasledovne:

Cleanup

V tomto poslednom kroku vytvoríte cieľ, pomocou ktorého vyčistíte projekt od nepotrebných súborov. Pri preklade totiž budú vznikať rozličné súbory ako medzivýsledky prekladu. Vytvoríte preto cieľ clean, pomocou ktorého tieto súbory zmažete.

Úloha 3.1

Vytvorte cieľ clean, pomocou ktorého zmažete z disku spustiteľný súbor ps1 a všetky ostatné objektové súbory .o.

Poznámka

Pri zostavovaní pravidla nezabudnite s výhodou použiť premennú OUTPUT.

Upozornenie

Dajte si pozor, aby ste nesprávnym zápisom tohto cieľa nezmazali všetky súbory nachádzajúce sa vo vašom projekte!

Úloha 3.2

Overte funkčnosť vytvoreného cieľa.

Ak ste postupovali správne, po spustení príkazu make s cieľom clean dôjde k odstráneniu spustiteľného súboru ps1 z disku vrátane všetkých objektových súborov.

Ďalšie zdroje