Dacă doriți să rulați sau să actualizați o sarcină atunci când anumite fișiere sunt actualizate, utilitarul make
poate fi util. make
utilitar necesită un fișier, Makefile
(sau makefile
), care definește un set de sarcini pentru a fi executat. Este posibil să fi folosit make
pentru a compila un program din codul sursă. Cele mai multe proiecte open source folosi make
pentru a compila un final binar executabil, care poate fi apoi instalat folosind make install
.,
În acest articol, vom explora make
și Makefile
utilizarea de bază și avansate de exemple. Înainte de a începe, asigurați-vă că make
este instalat în sistemul dvs.
Exemple de bază
să începem prin imprimarea clasicului „Hello World” pe terminal. Creați un director gol myproject
conține un fișier Makefile
cu acest conținut:
say_hello:
echo "Hello World"
Acum, rulați fișierul prin tastarea make
în directorul myproject
., Rezultatul va fi:
$ make
echo "Hello World"
Hello World
În exemplul de mai sus, say_hello
se comportă ca un nume de funcție, la fel ca în orice limbaj de programare. Aceasta se numește țintă. Premisele sau dependențele urmează ținta. Din motive de simplitate, nu am definit nicio condiție prealabilă în acest exemplu. Comanda echo "Hello World"
se numește rețetă. Rețeta folosește premise pentru a face o țintă. Ținta, premisele și rețetele împreună fac o regulă.,pentru a rezuma, mai jos este sintaxa unei reguli tipice:
target: prerequisites
<TAB> recipe
ca exemplu, o țintă ar putea fi un fișier binar care depinde de cerințe preliminare (fișiere sursă). Pe de altă parte, o condiție prealabilă poate fi și o țintă care depinde de alte dependențe:
nu este necesar ca ținta să fie un fișier; ar putea fi doar un nume pentru rețetă, ca în exemplul nostru. Noi numim aceste ” ținte false.,”
revenind la exemplul de mai sus, atunci când make
a fost executat, întreaga comandă echo "Hello World"
s-a afișat, urmată de comandă efectivă de ieșire. De multe ori nu vrem asta. Pentru a suprima un ecou comanda propriu-zisă, avem nevoie pentru a începe echo
cu @
:
say_hello:
@echo "Hello World"
Acum încerca pentru a rula make
din nou., Producția ar trebui să afișeze numai acest lucru:
$ make
Hello World
Să adăugați câteva mai multe ținte false: generate
și clean
la Makefile
:
Dacă vom încerca să rula make
după modificări, singura țintă say_hello
va fi executat. Asta pentru că doar prima țintă din makefile este ținta implicită. Adesea numit obiectivul implicit, acesta este motivul pentru care veți vedea all
ca prima țintă în majoritatea proiectelor., Este responsabilitatea all
să apeleze la alte ținte. Putem suprascrie acest comportament folosind o țintă falsă specială numită .DEFAULT_GOAL
.
Să includă faptul că la început de makefile:
.DEFAULT_GOAL := generate
Acesta va rula țintă generate
ca implicit:
$ make
Creating empty text files...
touch file-{1..10}.txt
după Cum sugerează și numele, fals țintă .DEFAULT_GOAL
poate rula doar o singură țintă la un moment dat. Acesta este motivul pentru care majoritatea fișierelor Makefile includ all
ca țintă care poate apela cât mai multe ținte după cum este necesar.,
Să includă fals țintă all
și scoateți .DEFAULT_GOAL
:
Înainte de a rula make
, să includă o altă speciale fals țintă, .PHONY
, unde ne-am defini toate obiectivele care nu sunt fișiere. make
își va rula rețeta indiferent dacă există un fișier cu acest nume sau care este ultima sa modificare., Aici este complet makefile:
make
ar trebui să apel say_hello
și generate
:
$ make
Hello World
Creating empty text files...
touch file-{1..10}.txt
este o bună practică să nu pentru a apela clean
în all
sau pune-l ca prima tinta., clean
ar trebui să fie numit manual, atunci când curățarea este necesar ca un prim argument pentru make
:
$ make clean
Cleaning up...
rm *.txt
Acum, că aveți o idee de cât o bază makefile funcționează și cum să scrie un simplu makefile, să ne uităm la unele mai avansate exemple.
Exemple avansate
variabile
în exemplul de mai sus, cele mai multe valori țintă și premise sunt greu codate, dar în proiecte reale, acestea sunt înlocuite cu variabile și modele.,
cel mai simplu mod de a defini o variabilă într-un makefile este de a utiliza =
operator., De exemplu, pentru a atribui comanda gcc
o variabila CC
:
CC = gcc
Acest lucru este, de asemenea, numit un recursiv extins variabilă, și este utilizat în regulă așa cum se arată mai jos:
hello: hello.c
${CC} hello.c -o hello
Cum poate ați ghicit, reteta se extinde ca mai jos atunci când este trecut la terminal:
gcc hello.c -o hello
Ambele ${CC}
și $(CC)
sunt valabile trimiteri la apel gcc
. Dar dacă cineva încearcă să realoce o variabilă în sine, va provoca o buclă infinită., Să verifice acest lucru:
CC = gcc
CC = ${CC}
all:
@echo ${CC}
Execută make
va avea ca rezultat:
$ make
Makefile:8: *** Recursive variable 'CC' references itself (eventually). Stop.
Pentru a evita acest scenariu, putem folosi :=
operator (acest lucru este, de asemenea, numit pur și simplu extins variabilă). Nu ar trebui să avem nicio problemă cu rularea makefile de mai jos:
CC := gcc
CC := ${CC}
all:
@echo ${CC}
modele și funcții
următoarele makefile pot compila toate programele C folosind variabile, modele și funcții., Să-l exploreze linie cu linie:
mai jos este rescrierea makefile de mai sus, presupunând că este plasat în directorul având un singur fișier foo.c: