Info |
---|
Ciele cvičeniaCvičenie je zamerané na prácu s kompilačným nájstrojom make. Tento nástroj slúži na kompiláciu zložitejších projetov, pozostávajúcich z niekoľkých súborov zdrojových kódov, vlastných hlavičkových súborov a podobne. Také projekty sa skladajú z takzvaných modulov, ktorých kombináciou a kompiláciou vzniká finálny softvérový produkt. Po osvojení si problematiky študent dokáže pracovať s nástrojom make, dokáže generovať konfiguračné súbory Makefile a rozumie filozofii modulárneho programovania.
|
Info |
---|
Odporúčaná literatúra a dôležité odkazy[1] KPI-FEI-TUKE: Prednáška č. 1 [2] KPI-FEI-TUKE: Prednáška č. 2 [3] KPI-FEI-TUKE: Cvičenie č. 3 - Introduction to Modular Programming [4] Umberto Salsi: Modular programming in C [5] Kovač, O.: ZAP - Cvičenie č. 2 |
Modulárne programovanie
Modulárne programovanie je technika softvérového dizajnu, pri ktorej sa na výsledný program nepozeráme ako na monolit ale ako na celok zložený zo separátnych častí - modulov. Modulárne programovanie oproti klasickému - "monolitickému" vnáša do vývoja softvéru ako aj do finálneho produktu prehľadnosť. Táto prehľadnosť je zavedená tým, že za rôzne funkcionality programu sú zodpovedné rôzne moduly. Výhodou modulov je tiež to, že je možné pracovať na vylepšeniach alebo opravách (bugfix) programu bez toho, bolo potrebné kompilovať celý projekt. Jednotlivé časti programu môžu byť v jazyku C predkompilované do takzvaných objektových súborov a tieto sa následne spoja - "zlinkujú" do výsledného programu. Takýto prístup pri ozaj rozsiahlych projektoch výrazne šetrí čas. V prípade veľkých projektov je modulárne programovanie doslova nutnosťou. Bližšie si kompiláciu zdrojového kódu (.c) do objektového súboru (.o) popíšeme v ďalšej časti textu.
Kompilácia zdrojového kódu do objektu
Ako už bolo uvedené vyššie, v jazyku C sa pri modulárnom programovaní zdrojové súbory najprv kompilujú do objektových súborov (.o) a až následne sa spoja do výsledného spustiteľného programu. Na nasledujúcom príklade ukážeme tento postup s využitím nástroja gcc, ktorý už veľmi dobre poznáme [5]. Len pre pripomenutie tento nástroj/príkaz používame nasledovne:
Code Block |
---|
// použitie gcc všeobecne $ gcc -prepinac1 -prepinac2 ... -prepinacN zdrojovy_kod_1.c zdrojovy_kod_2.c obejkotvy_subor_1.o -kniznica1 -kniznica2 -o nazov_programu // praktický príklad $ gcc -Werror -Wall program.c -lkarel -lcurses -o PROGRAM // -Werror znamená, že každé upozornenie (warning) sa vyhodnotí ako chyba (error) // -Wall zobraziť všetky upozornenia |
Príklad:
Vytvorte program pre zobrazenie zadanej matice a výpočet nasledovných parametrov matice: stredná hodnota, disperzia, maximum, minimum. Využite pritom zásady modulárneho programovania!
Riešenie:
Jedno z možných riešení je nasledovné:
- Program bude pozostávať z dvoch zdrojových súborov - hlavny.c a funkcie.c
- Program bude obsahovať jeden vlastný hlavičkový súbor - funkcie.h
- Modul funkcie.c bude prv skompilovaný na objektový súbor - funkcie.o
- Použite kostru programu ktorá je zobrazená nižšie! V poskytnutom kóde je už vyriešené zobrazenie matice a tiež výpočet strednej (priemernej) hodnoty.
Nástrojom gcc objektový súbor vytvoríme nasledovne:
Code Block |
---|
// použitie gcc všeobecne $ gcc -prepinac1 -prepinac2 ... -prepinacN zdrojovy_kod.c -c // praktický príklad $ gcc -Werror -Wall funkcie.c -c |
V pracovnom priečinku by mal vzniknúť súbor s názvom funkcie.o. Teraz je možné pristúpiť ku kompilácii a zlinkovaniu celého programu:
Code Block |
---|
$ gcc -Werror -Wall hlavny.c funkcie.c -o PROGRAM |
*poznámka: aj súbor hlavny.c by mohol byť vopred skompilovaný na objektový súbor.
Asi nie je potrebné uvádzať, že je pomerne nepraktické kompilovať kód takto z príkazového riadka. Na ZAP ste už používali nástroj make ale pritom ste do hĺbky nevedeli čo presne tento nástroj robí a ako funguje. V nasledujúcej časti sa teda bližšie pozrieme na tento nástroj.
Pokiaľ nenastala žiadna chyba aktuálny priečinok by mohol vyzerať nasledovne:
Code Block | ||
---|---|---|
| ||
ab123cd@zapfei:MODULAR$ ls -l total 36 -rw-rw-r-- 1 ok876zd ok876zd 547 Mar 3 10:15 funkcie.c -rw-rw-r-- 1 ok876zd ok876zd 93 Mar 3 09:46 funkcie.h -rw-rw-r-- 1 ok876zd ok876zd 2128 Mar 3 10:15 funkcie.o -rw-rw-r-- 1 ok876zd ok876zd 312 Mar 3 09:46 hlavny.c -rwxrwxr-x 1 ok876zd ok876zd 16896 Mar 3 10:21 PROGRAM |
Výpis z terminálu po spustení programu, bude vyzerať nasledovne:
Code Block | ||
---|---|---|
| ||
ab123cd@zapfei:$ ./PROGRAM 1 2 3 4 5 6 7 8 9 Stredna hodnotoa matice = 5.000000 |
Kostra úlohy:
Code Block | ||||
---|---|---|---|---|
| ||||
#include <stdio.h> #include "funkcie.h" int main() { int matica[3][3] = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} }; // Volanie funkcie pre vykreslenie matice vykreslenie(matica, 3); printf("\nStredna hodnotoa matice = %f \n \n", priemer(matica,3)); // tu budú ostatné výpočty a zobrazenie ich výsledkov return 0; } |
Code Block | ||||
---|---|---|---|---|
| ||||
void vykreslenie(int matica[][3], int velkost); float priemer(int matica[][3], int velkost); // tu budú deklarácie ostatných funckii |
Code Block | ||||
---|---|---|---|---|
| ||||
#include <stdio.h> void vykreslenie(int matica[][3], int velkost) { printf("\n"); for(int i = 0; i < velkost; i++) { printf("\n"); for(int ii = 0; ii<velkost; ii++) printf(" %d ", matica[i][ii]); } printf("\n"); } // Výpočet strednej (priemernej) hodnoty float priemer(int matica[][3], int velkost) { int suma = 0; for(int i = 0; i < velkost; i++) for(int ii = 0; ii<velkost; ii++) suma = suma + matica[i][ii]; return suma/(velkost*velkost); } // tu budú definície ďalších funkcii - Disperzia, Max, Min, |
Nástroj make a konfiguračný súbor Makefile
Účelom nástroja make je automaticky určiť, ktoré časti rozsiahleho programu musia byť skompilované alebo skompilované opakovane a skompilovať ich. Nástroj pracuje s konfiguračným súborom Makefile, ktorý obsahuje všetky jednotlivé príkazy pre kompiláciu objektových resp. spustiteľných súborov, rôzne prepínače či príkazy pre vymazanie nepotrebných súborov. Principiálne súbor Makefile obsahuje dva typy parametrov. Ide o takzvané cieľe - targets a nutných súčasti(premenné) - dependecies. Tiež môžeme definovať rôzne, prepínače, cesty k súborom, konštanty, knižnice, preferovaný prekladač a podobne. Súbor Makefile má nasledovnú štruktúru, kde [TAB] znamená odsadenie tabulátorom. Pozor na medzery a podobne, musí tam byť TAB inak skončíte pri chybe!
Komentáre sa v tomto súbore zadávajú za mriežku #. Ak pred príkaz dáme znak @, potlačí sa výpis príkazu do terminálu. V princípe v Makefile môžete používať ľubovoľný príkaz linux-u. Napr. v poslednej časti súboru Makefile z príkladu je zabezpečené "upratanie" nepotrebných súborov po kompilácii.
Code Block | ||
---|---|---|
| ||
# Tu môže byť ozaj kadečo, kto má záujem veľa nájde na google INCLUDES = -I/home/newhall/include LIBS = -lmylib -lm CC = gcc TARGET: DEPENDENCIES [TAB] SYSTEM_COMMAND1 ... [TAB] SYSTEM_COMMANDn |
Pre príklad, ktorý riešime môže súbor Makefile vyzerať nasledovne:
Code Block | ||
---|---|---|
| ||
# Tu su definovane prepinace, kompilator a vystup CC= gcc CFLAGS= -Werror -Wall OUTPUT= PROGRAM # Skompiluje sa cely program all: funkcie.o hlavny.o gcc $(CFLAGS) hlavny.o funkcie.o -o $(OUTPUT) @echo "Skompilovaný celý program" # Pokiaľ súbor funkcie.o nie je aktuálny tak sa skompiluje funkcie.c funkcie.o: funkcie.c @gcc -Werror -Wall funkcie.c -c @echo "Skompilovane iba funkcie.o" # Pokiaľ súbor hlavny.o nie je aktuálny tak sa skompiluje hlavny.c hlavny.o: hlavny.c @$(CC) $(CFLAGS) hlavny.c -c @echo "Skompilovane iba hlavny.o" # takto sa odstránia všetky súbory s príponou .o a tiež spustiteľný súbor clean: rm *.o $(OUTPUT) |