Make

llenguatge de programació

Make és una programa informàtic que automatitza la compilació de programes i biblioteques a partir del seu codi font. Make llegeix uns fitxers anomenats makefiles que especifiquen quins passos s'han de seguir per a compilar i en quin ordre s'han de compilar els fitxers. Tot i que es poden fer servir els entorns integrats de desenvolupament per a manejar el procés de construcció de programari, make encara és molt utilitzat, especialment en entorns Unix.

Make
Modifica el valor a Wikidata
Tipussistema de construcció, utilitat UNIX, llenguatge script, llenguatge de programació i llenguatge de regles fora de joc Modifica el valor a Wikidata
Versió inicialabril 1976 Modifica el valor a Wikidata
Característiques tècniques
Sistema operatiuUnix Modifica el valor a Wikidata
Escrit enC Modifica el valor a Wikidata
Format de fitxer d'escriptura
Makefile (en) Tradueix Modifica el valor a Wikidata
Equip
Desenvolupador(s)Stuart Feldman Modifica el valor a Wikidata
DissenyadorStuart Feldman Modifica el valor a Wikidata
Més informació
Stack ExchangeEtiqueta Modifica el valor a Wikidata

Origen modifica

Creat el 1977 per Stuart Feldman en els Laboratoris Bell, es va començar a distribuir en entorna Unix, juntament amb altres eines dedicades al desenvolupament de programari, amb la versió 1.0 de PWB/UNIX. A partir d'aleshores, make ha esdevingut una de les eines de compilació automàtica més utilitzades fins al punt que el 2003 la ACM va atorgar un premi al Dr. Felman per aquesta eina.[1]

Abans de la introducció de make, el sistema de compilació de programari més comú era el de distribuir un shell script per a cada sistema operatiu diferent a on s'hagués de compilar el programa. Make va fer un pas molt important cap a entorns de compilació moderns al poder combinar les ordres pels diferents sistemes operatius així com un mètode per poder seguir les dependències tot en un sol fitxer.

Aplicacions modifica

Per norma general, el make s'utilitza per a compilar programes i biblioteques binàries a partir del seu codi font. Tanmateix, make es pot fer servir per a qualsevol procés que necessiti convertir fitxers basats en dependències executant un nombre arbitrari d'ordres. Per exemple, es podria fer servir make per detectar qualsevol canvi en un fitxer imatge (la dependència) i les ordres a executar podrien convertir aquesta imatge en un altre format, copiar el resultat en un sistema de gestió de continguts i enviar un correu a un conjunt de destinataris que s'han realitzat totes aquestes operacions.

Versions modernes modifica

Amb el pas del temps, s'han reescrit diverses variants del make que utilitzen el mateix format pels makefiles i segueixen el mateix algorisme bàsic, però que afegeixen un nombre de millores no estàndards pròpies. Algunes d'aquestes variants són:

  • make del BSD, derivat de la versió del make escrita per Adam de Boor la qual és capaç de compilar els fitxers en paral·lel, amb certes modificacions per a FreeBSD, NetBSD i OpenBSD. El més destacat, és la introducció de condicionals i de bucles que s'apliquen durant l'anàlisi de les dependències i que permeten modificar de manera automàtica el makefile, incloent els fitxers a compilar.
  • make de GNU s'utilitza molt freqüentment junt amb el GNU build system. Es diferencia molt del make tradicional sobretot en la cerca de patrons i en la generació de grafs de dependències, així com un nombre de funcions que es poden cridar dins del makefile que permeten, per exemple, funcions com llistar els fitxers d'un directori.

name de Microsoft, utilitzat en sistemes Windows. És una versió força bàsica i només conté un subconjunt de les característiques de les versions explicades més amunt. No s'ha de confondre el nmake de Microsof amb el de AT&T i el de Laboratoris Bell per Unix.

L'estàndard POSIX inclou una estandardització de les característiques i operacions bàsiques del make i la majoria de les implementacions per Unix el segueixen força completament. En general, la majoria del makefiles simples es poden fer servir sense diferències entre les diferents variants del make. El make de GNU i el del BSD es poden configurar de manera que primer busquin fitxers anomenats GNUmakefile i BSDmakefile respectivament,[2][3] de manera que és possible fer servir makefiles que utilitzin detalls d'una implementació concreta en diferents llocs.

Avantatges i desavantatges modifica

Make ordena la llista de dependències pels fitxers a compilar, com ara quines capçaleres contribueixen a la compilació d'un fitxer objecte. Això manté el make com una eina general i útil per a qualsevol tipus de fitxer, però també augmenta la possibilitat d'error humà. Una dependència de més o que s'hagi oblidat pot no ser òbvia a primera vista i donar com a resultat errades de programari difícils de trobar. És possible escriure makefiles que generin les dependències de manera automàtica utilitzant eines externes, i alguns generadors de makefiles, com ara GNU Automake, per defecte ho fan així.

Un altre problema que make no maneja molt bé és la diferència de paràmetres que hi poden haver entre les eines de diversos sistemes. Per exemple, el compilador d'una plataforma pot no acceptar els paràmetres del compilador d'una altra. Aquest problema generalment es deixa en mans de processos que generen les instruccions necessàries per a cada plataforma. Eines comuns per a aquesta feina són el Autoconf i el Cmake, que generen un shell script anomenat configure que l'usuari ha d'executar abans de començar el procés de compilació.

Make decideix si un fitxer de sortida s'ha de regenerar o no comparant l'hora de modificació del fitxer de sortida i les seves dependències. Tot i que aquesta solució és simple, no funciona quan un fitxer canvia però la seva hora de modificació no. Canvis d'aquest estil són freqüents quan s'utilitza programari de control de versions o quan el codi font es troba en un sistema d'arxius en xarxa els rellotges del sistemes no està sincronitzat. En aquests casos, l'usuari es veu forçat a recompilar-ho tot.

Les ordres dels makefiles s'executen dins d'una shell. Com que els diferents sistemes operatius utilitzen diferents shells això significa que alguns makefiles poden no ser portables. Per exemple, el make de GNU executa les ordres a través de bash i pot executar eines d'Unix com el cp. En canvi, el nmake de Microsoft executa les ordre en a través del cmd.exe i per tant s'han de fer servir ordres de batch com COPY.

La sintaxi utilitzada pel make utilitza de manera diferent el caràcter del tabulador i el d'espai de manera diferent. Això és problemàtic perquè per norma general no hi ha cap diferència visual entre els dos caràcters i sovint es critica la sintaxi del make per culpa d'això. Pels programadors que utilitzen generadors de makefiles o editors de text amb suport per a makefiles, aquest problema és menys greu.

El llenguatge de make s'assembla molt a la programació declarativa.[4][5] Aquest tipus de llenguatges, en què es declaren els objectius però l'ordre de les accions no és tan important, provoca a vegades confusió entre els programadors acostumats a llenguatges imperatius.

Estructura d'un Makefile modifica

Un makefile consisteix en línies de dependències a on es defineix un objectiu (una regla) seguida per dos punts i de manera opcional els conjunt de fitxers del que depèn. La línia de dependències s'escriu de manera que a la part esquerra del caràcter : hi ha l'objectiu a compilar i a la dreta del : hi ha les seves dependències.

Després de cada línia de dependències poden haver-hi una sèrie de línies sagnades amb el caràcter tab que indiquen quines ordres s'han d'executar per transformar les dependències a l'objectiu. Si qualsevol de les dependències s'ha modificat, s'executen totes les ordres aquí llistades. L'estructura bàsica és:

 # Els comentaris comencen amb el caràcter de sostingut (#)
 objectiu [objectiu ]: [dependència ]
 [<TAB>ordre 1]
 .
 .
 .
 [<TAB>ordre n]

Nota: Generalment els objectiu s'escriuen en línies separades i les línies d'ordres són opcionals. La llista de dependències pot consistir únicament en altres objectius que s'han de compilar com ara:

 realclean: clean disclean

Les ordres generalment s'escriuen de manera que generen l'objectiu. Per exemple, si el fitxer "fitxer.html" és més nou que el fitxer de text a convertir, es pot escriure el següent makefile:

 fitxer.txt: fitxer.html
 lynx -dump fitxer.html > fitxer.txt

Aquesta regla s'executa invocant el make amb el nom de l'objectiu:

 make fitxer.txt

Un makefile també pot contenir definicions de macros i algunes ordres poden incloure altres makefiles. Les macros definides en els makefiles es poden anul·lar en els arguments que es passen en executar el make. Això permet als usuaris especificar diferents comportaments a l'hora de compilar o executar determinats programes. Un exemple és la macro "CC" que s'utilitza molt sovint en makefiles per definir la ruta al compilador de C i l'usuari podria voler fer servir un compilador alternatiu sota alguns casos. Un exemple del make de GNU:

 # Makefile pel make de GNU

 # Aquest fragment atura als make(1) que no siguin de GNU i que
 # no entendrien totes les ordres.

 ifneq (,)
 Aquest makefile necessita el make de GNU.
 endif

 include makefile/environment.mk
 include makefile/common.mk

 # Defineix macros. En aquest case són "variables simples que no s'expandeixen"
 # Es poden canviar per la línia d'ordres

 CC = gcc
 CFLAGS = -Wall -pedantic -g

 all:
 echo "Res a fer"

Sintaxi modifica

Intèrpret d'ordres modifica

  • El make busca els fitxers a executar en el directori actual. Per exemple, el make de GNU busca els fitxers en l'ordre GNUmakefile, makefile, Makefile.
  • Sense cap paràmetre, make executa el primer objectiu que apareix en el fitxer que tradicionalment se l'anomena all.
  • Es poden passar diversos objectius quan s'executa el make des de l'intèrpret d'ordres:
 make OBJECTIU [OBJECTIU ...]
  • Les macros del makefile es poden modificar des de l'intèrpret d'ordres abans d'executar els objectius. Si les macros només contenen simples definicions, com ara make CC=gcc all, aleshores s'anomenen "variables". La sintaxi genèrica és:
 make MACRO="valor" [MACRO="valor" ...] OBJECTIU [OBJECTIU ...]

Contingut del makefile modifica

Les variables de la shell que formen part de l'entorn també es troben disponibles com a macros (o "variables") i tradicionalment s'escriuen tot en majúscules:

 MACRO = definició

Quan s'expandeixen les macros per obtenir-ne el seu valor, generalment s'escriuen entre (). Tot i que també és possible escriure-les entre {}, generalment no es fa.

 NOVA_MACRO = $(MACRO)-$(MACRO2)

Els valor de les macros també pot ser el resultat d'executar una ordre ja sigui utilitzant operadors de substitució d'ordres o l'accent greu ``.

 YYYYMMDD = ` date `

Aquest valor es guarda tal com apareix a la sortida de la comanda i només s'expandeix quan s'utilitza la macro en una línia d'ordre d'un objectiu. Per exemple:

 PACKAGE = package
 VERSION = ` date +"%Y.%m%d" `
 ARCHIVE = $(PACKAGE)-$(VERSION)

 dist:
 # Fixa't com només les macro s'expandeixen per a ser interpretades per la shell:
 # tar -cf package-`date +"%Y%m%d"`.tar

 tar -zcf $(ARCHIVE).tar.

Cada ordre que segueix la línia de dependències han d'estar sagnades amb un caràcter de tabulació.

 objectiu: dependència
 <TAB>ordre

Cada ordre s'executa en una shell independent i ha d'estar escrita en una única file. Es poden concatenar ordres indicant-t'ho amb una barra invertida \ al final de cada línia.

 objectiu: dependència \
 dependència
 <TAB>ordre; \
 <TAB>ordre | \
 <TAB>ordre-enllaçada

Les ordres es poden prefixar amb els següents tres caràcters: un guió ("-") per indicar que s'ignoren els errors de la comanda, una arrova ("@") per no escriure l'ordre per pantalla abans d'executar-la, o un signe de suma ("+") per executar la comanda encar que make s'executi en mode "no executis". De manera alternativa, es poden ignorar errors i amagar les ordres a executar amb els objectius especials .IGNORE i .SILENT.[6]

El makefiles també poden accedr a macros internes.

 objectiu: dependència1 dependència2
 echo $? # conté les dependències modificades més recentment que objectiu
 echo $@ # conté el nom del objectiu

Es poden escriure regles de sufix a l'estil FROM.TO i es poden fer servir per executar ordres basant-se en l'extensió dels fitxers. En les regles de sufix, la macro interna $< es refereix a la dependència i la macro $@ a l'objectiu. Com a exemple es podria crear una regla de sufix per a convertir tots els fitxers HTML a fitxers de text. Fixa't també en el caràcter de redirecció al mig de l'ordre:

 .SUFFIXES: .txt .html

 # De .html a .txt
 .html.txt:
 lynx -dump $< > $@

Quan s'executa el make, l'exemple anterior s'expandeix a:

 $ make -n fitxer.txt
 lynx -dump fitxer.html > fitxer.txt

Exemples de makefiles modifica

Els makefiles s'utilitzen generalment per a compilar codi (*.c, *.cc, *.C, etc.), però també es poden fer servir per a automatitzar tasques comunes. Al cridar un d'aquests makefiles des de l'intèrpret d'ordres:

 make # Sense cap paràmetre s'executa el primer objectiu
 make help # Mostra tots els objectius
 make dist # Crea un fitxer comprimit amb el contingut del directory

The makefile:

 PACKAGE = package
 VERSION = ` date "+%Y.%m%d%" `
 RELEASE_DIR = ..
 RELEASE_FILE = $(PACKAGE)-$(VERSION)

 # Fixa't que la variable LOGNAME prové de l'entorn
 # de les shells de POSIX.
 #
 # objectiu: all - Objectiu per defecte. No fa res.
 all:
 echo "Hola $(LOGNAME), per defecte no es fa res"
 echo "Prova amb 'make help'"

 # objectiu: help - Mostra els objectius.
 help:
 egrep "^# objectiu:" [Mm]akefile

 # objectiu: llistar - Llista el fitxers de codi font
 llistar:
 # Això no funciona perquè cada ordre d'executa en un shell diferent.
 cd src
 ls

 # Això sí perquè es continua l'ordre dins de la mateixa shell.
 cd src; \
 ls

 # objectiu: dist - Crear un fitxer comprimit amb el contingut del directori.
 dist:
 tar -cf $(RELEASE_DIR)/$(RELEASE_FILE) && \
 gzip -9 $(RELEASE_DIR)/$(RELEASE_FILE).tar

A sota hi ha un makefile molt simple que compila un codi font anomentar "holamon.c" utilitzant el gcc, un compilador, i també especifica un objectiu anomenat "clean" que esborra els fitxers generats. L'objectiu .PHONY és una manera d'inicar a make que un objectiu en particular no és el nom d'un fitxer a generar.

 CC = gcc
 CFLAGS = -g

 all: holamon

 holamon: holamon.o
 $(CC) $(LDFLAGS) -o $@ $^

 holamon.o: holamon.c
 $(CC) $(CFLAGS) -c -o $@ $<

 clean:
 rm -f holamon holamon.o

 # Aquesta és una extensió del make de GNU que significa que 'clean' no és un
 # nom de fitxer i per tant no ha de comprovar-ne cap hora de modificació.
 .PHONY: clean

Referències modifica

  1. Matthew Doar. Practical Development Environments. O'Reilly Media, 2005, p. 94. ISBN 978-0596007966. 
  2. «GNU `make'». Free Software Foundation.
  3. «Manual Pages: make». OpenBSD 4.8.
  4. Re: Choreography and REST, from Christopher B Ferris on 2002-08-09
  5. Target Junior Makefiles, Andrew W. Fitzgibbon and William A. Hoffman
  6. make, The Open Group Base Specifications Issue 6