This shows you the differences between two versions of the page.
|
uso:laboratoare:new:04-appdev:demo [2018/10/28 19:09] elena.stoican |
uso:laboratoare:new:04-appdev:demo [2019/10/24 09:59] (current) adrian.zatreanu [Demo] |
||
|---|---|---|---|
| Line 1: | Line 1: | ||
| ===== Demo ===== | ===== Demo ===== | ||
| - | În această secțiune vom urmări să obținem o mai bună înțelegere a | + | În această secțiune vom urmări să obținem o mai bună înțelegere asupra |
| - | procesului de compilare/build precum și a utilității și utilizării fișierelor Makefile. | + | procesului compilării precum și asupra utilității și utilizării fișierelor Makefile. |
| Pentru această secțiune trebuie să vă asigurați că sunteți în directorul potrivit. Rulați comanda | Pentru această secțiune trebuie să vă asigurați că sunteți în directorul potrivit. Rulați comanda | ||
| - | <code> | + | |
| - | cd ~/uso.git/labs/04-appdev/support/ | + | <code bash> |
| + | student@uso:~$ cd ~/uso-lab/04-appdev/support/demo/ | ||
| </code> | </code> | ||
| Line 14: | Line 15: | ||
| scrise în C este gcc, iar pentru C++, g++. | scrise în C este gcc, iar pentru C++, g++. | ||
| - | Să presupunem că avem următorul fișier sursă, print.c; în urma rulării comenzii | + | Să presupunem că avem următorul fișier sursă ''print.c''. |
| - | gcc print.c, procesul de compilare trece prin toate cele patru faze intermediare | + | |
| - | rezultând fișierul executabil a.out. | + | <code bash> |
| + | #include <stdio.h> | ||
| + | #include <stdlib.h> | ||
| + | |||
| + | int main(void) { | ||
| + | printf("USO Rules! <3\n"); | ||
| + | |||
| + | return 0; | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | În urma rulării comenzii ''gcc print.c'', procesul de compilare trece prin toate cele | ||
| + | patru faze intermediare rezultând fișierul executabil a.out. | ||
| <code bash> | <code bash> | ||
| Line 24: | Line 37: | ||
| student@uso:~$ ls | student@uso:~$ ls | ||
| a.out print.c | a.out print.c | ||
| + | root@ebp:~$ | ||
| </code> | </code> | ||
| ''a.out'' este denumirea default în situația în care nu este specificat care să fie | ''a.out'' este denumirea default în situația în care nu este specificat care să fie | ||
| - | numele executabilului. Pentru aceasta folosim parametrul [-o outputFileName] | + | numele executabilului. Pentru aceasta folosim parametrul ''[-o output_filename]'' |
| la rularea comenzii. Parametrul poate să se găsească la orice poziție în cadrul | la rularea comenzii. Parametrul poate să se găsească la orice poziție în cadrul | ||
| comenzii, dar este obligatoriu să fie urmat întotdeauna de numele dorit. | comenzii, dar este obligatoriu să fie urmat întotdeauna de numele dorit. | ||
| Line 36: | Line 50: | ||
| a.out print print.c | a.out print print.c | ||
| student@uso:~$ | student@uso:~$ | ||
| + | </code> | ||
| + | |||
| + | Observăm ca fișierul ''a.out'' este un fișier binar folosind comanda ''file''. | ||
| + | |||
| + | <code bash> | ||
| + | student@uso:~$ file a.out | ||
| + | a.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=c5ad78cfc1de12b9bb6829207cececb990b3e987, not stripped | ||
| </code> | </code> | ||
| Line 41: | Line 62: | ||
| link-editare. La o rulare normală a comenzii gcc se trece prin toate aceste faze, | link-editare. La o rulare normală a comenzii gcc se trece prin toate aceste faze, | ||
| însă există și posibilitatea de a întrerupe procesul la finalul uneia anume. | însă există și posibilitatea de a întrerupe procesul la finalul uneia anume. | ||
| - | * folosirea parametrului -c spune compilatorului să se oprească după faza de | + | * folosirea parametrului -c spune compilatorului să se oprească după faza de asamblare și să nu linkeze codul. |
| - | asamblare și să nu linkeze codul. | + | |
| <code bash> | <code bash> | ||
| Line 49: | Line 69: | ||
| print.c print.o | print.c print.o | ||
| student@uso:~$ cat print.o | student@uso:~$ cat print.o | ||
| - | ELF>�@@ | + | ELF>�@@ |
| - | UH��H�=��]�USO Rules! <3GCC: (Debian 8.2.0-7) 8.2.0zRx | + | UH��H�=��]�USO Rules! <3GCC: (Debian 8.2.0-7) 8.2.0zRx |
| - | R �A�C | + | R �A�C |
| - | �� $print.cmain_GLOBAL_OFFSET_TABLE_puts�������� | + | �� $print.cmain_GLOBAL_OFFSET_TABLE_puts�������� |
| - | + | ||
| - | �������� .symtab.strtab.shstrtab.rela.text.data.bss.rodata.comment.note.GNU-stack.rela.eh_frame @@0 | + | �������� .symtab.strtab.shstrtab.rela.text.data.bss.rodata.comment.note.GNU-stack.rela.eh_frame @@0 |
| - | &WW1W90eB�W�R@@ | + | &WW1W90eB�W�R@@ |
| - | � | + | � |
| - | �)Xaroot@ebp:~/Documents/uso/lab_04/support# | + | �)Xaroot@ebp:~/Documents/uso/lab_04/support# |
| </code> | </code> | ||
| + | |||
| Se observă că rezultatul final este un fișier cu cod obiect. | Se observă că rezultatul final este un fișier cu cod obiect. | ||
| * folosirea parametrului -S instruiește compilatorul să nu asambleze codul. | * folosirea parametrului -S instruiește compilatorul să nu asambleze codul. | ||
| Line 97: | Line 118: | ||
| * folosirea parametrului -E oprește procesul de compilare după faza de preprocesare. | * folosirea parametrului -E oprește procesul de compilare după faza de preprocesare. | ||
| - | (HINT: man gcc) | + | <note> |
| + | Toate opțiunile utilitarului ''gcc'' pot fi regăsite în pagina de manual (''man gcc''). | ||
| + | </note> | ||
| ==== Makefile ==== | ==== Makefile ==== | ||
| - | Utilitarul de automatizare cel mai folosit pentru aplicațiile C/C++ este make. | + | Utilitarul de automatizare cel mai folosit pentru aplicațiile C/C++ este **make**. |
| În general numele unui fișier makefile este Makefile, însă te poți afla în | În general numele unui fișier makefile este Makefile, însă te poți afla în | ||
| situația în care ai nevoie de mai multe astfel de fișiere, moment în care | situația în care ai nevoie de mai multe astfel de fișiere, moment în care | ||
| pentru a alege unul dintre ele putem rula comanda make cu parametrul -f, urmat | pentru a alege unul dintre ele putem rula comanda make cu parametrul -f, urmat | ||
| de numele makefile-ului pe care dorim să îl folosim. | de numele makefile-ului pe care dorim să îl folosim. | ||
| - | Exemplu: make -f makefile.win | + | |
| + | <code> | ||
| + | student@uso:~$ ls | ||
| + | Makefile Makefile.win | ||
| + | student@uso:~$ make -f Makefile.win | ||
| + | (..) | ||
| + | </code> | ||
| <note> | <note> | ||
| Line 117: | Line 146: | ||
| </note> | </note> | ||
| - | <code bash> | + | Avem fișierul sursă ''print.c''. Un exemplu de Makefile care autmatizeaza procesul de compilare |
| - | student@uso:~$ cat Makefile | + | al acestuia este următorul: |
| - | rule1: print.c | + | |
| + | <code> | ||
| + | build: print.c | ||
| gcc -Wall print.c -o print | gcc -Wall print.c -o print | ||
| clean: | clean: | ||
| rm print | rm print | ||
| + | </code> | ||
| + | |||
| + | Acest fișier conține 2 reguli: una de **build** prin care se compilează fișierul ''print.c'' și una de ''clean'' | ||
| + | pe care o putem folosi să ștergem fișierele generate în urma compilării (cum ar fi fișierele executabile, obiect, etc.). | ||
| + | |||
| + | Pentru a rula regula numită ''build'', rulăm comanda ''make build''. | ||
| + | |||
| + | <code bash> | ||
| + | student@uso:~$ make build | ||
| + | gcc -Wall print.c -o print | ||
| + | student@uso:~$ ls | ||
| + | Makefile print print.c | ||
| student@uso:~$ | student@uso:~$ | ||
| + | </code> | ||
| + | |||
| + | Pentru a șterge fișierul generat (''print''), rulăm comanda ''make clean''. | ||
| + | |||
| + | <code bash> | ||
| + | student@uso:~$ make clean | ||
| + | rm print | ||
| + | student@uso:~$ ls | ||
| + | Makefile print.c | ||
| student@uso:~$ | student@uso:~$ | ||
| + | </code> | ||
| + | |||
| + | Dacă nu se precizează niciun argument comenzii ''make'', atunci aceasta va rula prima regulă întâlnită în fișier, adică regula ''build''. | ||
| + | |||
| + | <code bash> | ||
| student@uso:~$ make | student@uso:~$ make | ||
| gcc -Wall print.c -o print | gcc -Wall print.c -o print | ||
| Line 133: | Line 190: | ||
| </code> | </code> | ||
| - | Regulă reprezintă numele unei instrucțiuni. La simpla rulare a comenzii make prima | + | <note> |
| - | regulă din fișier este cea care va fi executată. În schimb, dacă vom scrie make raccoon, | + | Regulile din Makefile pot avea și ''dependențe''. Aceastea sunt opționale, însă sunt încurajate. |
| - | se va executa comanda aferentă regulii raccoon. | + | Ele reprezintă, de fapt, fișiere și/sau reguli necesare pentru a putea rula o altă regulă. |
| + | Practic, la rularea unei reguli se verifică dacă fișierul din dependență există. | ||
| + | Dacă acesta există, putem rula regula, dacă nu, se caută o altă regulă cu acel nume și se va | ||
| + | rula acea regulă (dacă dependențele ei sunt îndeplinite, dacă nu, se continuă lanțul de dependențe). | ||
| + | </note> | ||
| - | Dependențele pot să lipsească sau nu. Ele reprezintă de fapt fișiere și/sau reguli | + | Să considerăm următorul Makefile: |
| - | necesare pentru a putea rula o altă regulă. Practic, la rularea unei reguli se verifică | + | |
| - | dacă fișierul din dependintă există. Dacă acesta există, putem rula regula, dacă nu, | + | |
| - | se caută o altă regulă cu acel nume și se va rula acea regulă (dacă dependențele ei | + | |
| - | sunt îndeplinite, dacă nu, se continuă lanțul de dependențe). | + | |
| - | Să considerăm următorul makefile: | + | |
| <code bash> | <code bash> | ||
| Line 164: | Line 220: | ||
| </code> | </code> | ||
| - | Prima regulă care va fi rulată este "build". Când se încearcă rularea ei se verifică | + | Prima regulă care va fi rulată este ''build''. Când se încearcă rularea ei se verifică |
| existența fișierelor obiect utils.o, hello.o și help.o. Cum ele nu au fost încă | existența fișierelor obiect utils.o, hello.o și help.o. Cum ele nu au fost încă | ||
| generate se caută în fișier o regulă cu numele lor. După cum se observă, aceste | generate se caută în fișier o regulă cu numele lor. După cum se observă, aceste | ||
| - | reguli se găsesc mai jos în makefile și vor fi executate deoarece ele | + | reguli se găsesc mai jos în Makefile și vor fi executate deoarece ele |
| au ca dependențe doar fișiere cod sursă (despre care știm deja că există), comenzile | au ca dependențe doar fișiere cod sursă (despre care știm deja că există), comenzile | ||
| - | aferente lor generând codul obiect necesar rulării regulii "build". | + | aferente lor generând codul obiect necesar rulării regulii ''build''. |
| - | De reținut este și faptul că make verifică dacă o dependință a fost sau nu modificată | + | De reținut este și faptul că ''make'' verifică dacă o dependență a fost sau nu modificată |
| după momentul în care a fost creată. În caz afirmativ aceasta va fi regenerată, | după momentul în care a fost creată. În caz afirmativ aceasta va fi regenerată, | ||
| - | altfel, pentru eficientizare, aceasta va fi reutilizată. | + | altfel, pentru eficientizare, aceasta va fi reutilizată. |
| + | |||
| + | Spre exemplu, dacă avem fișierul Makefile de mai sus, am rulat deja o dată regula ''make build'' | ||
| + | și după modificăm fișierul ''utils.c'', atunci la următoarea rulare a regulii ''make build'' se | ||
| + | va rula mai întâi (automat) regula ''utils.o'' și abia dupa ''make build''. | ||