This is an old revision of the document!
Descărcați arhiva TODO
. Dezarhivați folosind tar:
tar xf lab06.tar.gz
Intrați în directorul tutorial/2
. Fișierul hello.c
este o sursă C completă. Compilați fișierul utilizând gcc
:
gcc hello.c
Ce fișiere s-au creat? Aflați tipul acestora utilizând comanda file
.
ls -l file a.out
Rulați fișierele executabile.
./a.out
Compilați sursa specificând și numele fișierului executabil:
gcc hello.c -o stallman
Rulați executabilul creat.
Compilați sursa afișând avertismente:
gcc hello.c -o linus -Wall
-Wall
pentru fiecare compilare.
-Wextra
și -Werror
.
Corectați warning-urile apărute. Recompilați sursa.
Rulați comenzile următoare:
gcc -o jobs -Wall hello.c gcc -Wall -o turing hello.c gcc -Wall hello.c -o dijkstra
Utilizând ls -l
comparați dimensiunile celor 3 executabile create. Verificați că cele 3 executabile sunt identice vizualizând output-ul fiecăruia.
Calculați md5-ul fiecărui executabil și verificați că este identic.
md5sum
putem obține un rezumat al conținutului unui fișier. Acest rezumat, cunoscut și sub numele de hash, are proprietatea interesantă că cea mai mică modificare posibilă în fișierul inițial va duce la modificarea completă a md5-ului. Din acest motiv, 2 fișiere cu același md5 pot fi considerate identice.
În general, ordinea parametrilor nu contează. Anumiți parametri au argumente. Aici avem parametrul -o
. Acest argument trebuie urmat întotdeauna de numele executabilului.
Intrați în directorul tutorial/3/1
. Vizualizați conținutul fișierului answer.c
. Rulați comanda
gcc -E answer.c -o answer.i
Cum s-a modificat fișierul sursă în urma etapei de preprocesare? Ce tip are fișierul generat (folosiți file
)?
Intrați în directorul tutorial/3/2
. Vizualizați conținutul fișierului answer.c
. Rulați comanda
gcc -S answer.c -o answer.s
Ce tip are fișierul generat în etapa de compilare?
Folosind gcc
efectuați etapa de asamblare:
gcc -c answer.s -o answer.o
Ce tip are fișierul obținut?
.c
adresa acestei funcții nu va fi cunoscută în momentul asamblării fișierului. Ea va fi completată în etapa următoare
Ultima etapă din procesul de compilare este cea de link-editare. Folosind gcc
, invocați această etapă pentru a obține executabilul final:
gcc answer.o
Ce fișier a fost creat? Ce tip are acest fișier? Rulați executabilul.
Intrați în directorul tutorial/4/1
. Fișierul sandwich.c
conține un program C valid. Rulați
make sandwich
și vizualizați fișierele create (utilizând file
pentru a vedea tipul acestora). Ce comandă a fost folosită pentru a compila sursa?
Makefile
nu există și nu este specificat, make
va folosi comenzi implicite pentru build, în funcție de extensia fișierului primit ca parametru. În acest caz, comanda implicită a fost cc sandwich.c -o sandwich
.
Intrați în directorul tutorial/4/2
. Fișierul Makefile
va fi folosit pentru a compila sursa sandwich.c
. Rulați comenzile:
make ./sandwich
Vizualizați fișierul Makefile
. Fișierul conține o singură linie sandwich:
. Aceasta îi indică utilitarului make
să execute target-ul sandwich
. Deoarece nu există altceva, se va încerca folosirea unei reguli implicite.
Care este regula implicită folosită? (afișată în terminal). Diferă fată de cea anterioară?
Intrați în directorul tutorial/4/3
. Fisierul Makefile
a fost completat astfel încât să se precizeze explicit ce sursă se compilează, pentru a putea diferenția între cele 2 surse prezente în director, sandwich.c
și reply.c
. Rulați comenzile următoare și urmăriți ce se execută:
make ls rm sandwich make sandwich ls make reply ls ./sandwich ./reply
Un target poate avea o listă de dependențe. Acestea se scriu pe aceeași linie, după :
.
Modificați reply.c
adăugând porțiunea comentată. Rulați comenzile
make reply make reply
Deoarece între cele 2 comenzi nu am modificat sursa, nu se va executa nimic pentru a doua comandă.
Intrați în directorul tutorial/4/5
. Fișierul Makefile
a fost completat astfel încât să se poată construi ambele executabile cu aceeași comandă și pentru a putea șterge toate fisierele create pe baza surselor. Rulați comenzile
ls make ls make clean ls
Pentru targetul clean
s-au introdus și instrucțiunile necesare producerii acestuia din dependențe. Acestea se pun indentate cu un tab pe liniile imediat următoare definirii targetului.
Intrați în directorul tutorial/4/6
. Fișierul Makefile
este identic cu cel din exercițiul anterior (verificați cu diff
). Rulați comenzile
touch clean ls make ls make clean ls
touch clean
!!
De ce nu se revine la situația initială a fișierelor din director?
Redenumiți fișierul Makefile.good
în Makefile
și rulați din nou comenzile de mai sus. Singura diferență este linia .PHONY: all clean
.
.PHONY
a tuturor target-urilor ce nu reprezintă fișiere pentru a preveni situația în care un fișier cu același nume există în directorul curent și targetul nu se va executa.
Intrați în directorul tutorial/4/7
. Rulați comenzile următoare și observați ce se execută:
make story rm story make story CFLAGS=-Wall rm story make story CC=gcc rm story make story CC=gcc CFLAGS="-Wall -Wextra -O3"
Ați folosit variabile Makefile
pentru a modifica regula implicită.
Un mic grafic cu etapele compilării și legătura dintre acestea și variabilele makefile este următorul
Intrați în directorul tutorial/5
. Compilați fișierul traceable.c
utilizând gcc
, salvând executabilul ca traceme
. Rulați comenzile:
./traceme strace ./traceme
Utilitarul strace
permite evidențierea fiecărui apel de sistem din execuția programului. În cazul nostru, printf
se reduce la un apel write
.
Putem evidenția doar anumite apeluri de sistem folosind argumentul -e <nume_apel>
. Rulați comanda:
strace -e write ./traceme
Intrați în directorul tutorial/6
. Compilați sursa math.c
utilizând gcc
:
gcc math.c
Se observă că avem o eroare undefined reference to `sinh
'. Compilați programul până la modulul obiect:
gcc -c math.c -o math.o
Utilitarul nm
listează simbolurile dintr-un fișier obiect sau dintr-un executabil. Rulați comanda:
nm math.o
Liniile ce conțin 'U' listează simbolurile folosite dar nedefinite în math.o
. Liniile cu 'T' listează simbolurile definite (translatate).
Pentru a putea obține executabilul va trebui să definim și simbolul sinh
. Funcția este definită în biblioteca matematică libm.so
. Pentru a da biblioteca ca argument lui gcc
pentru etapa de link-editare va trebui să folosim argumentul -l
astfel:
lib
.-l
Rulați:
gcc -lm math.c
Compilarea reușește. Pentru a vedea bibliotecile folosite de executabil vom folosi un alt utilitar - ldd
:
ldd a.out
Folosiți următoarea comandă pentru a compila sursa static:
gcc math.c -static -o staticmath -lm
Comparați dimensiunile fișierelor a.out
și staticmath
.
a.out
este mai mic decât staticmath
, deoarece nu conține codul obiect pentru biblioteca math.
Pentru a observa simbolurile definite în executabilul legat static, rulați:
ldd staticmath
Creați fișierele README
, tema.c
, util.c
, util.h
. Fișierul tema.c
va include headerul util.h
și va defini funcția main
.
Adăugați un fișier Makefile
pentru compilarea sursei.