1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
|
---
category: tool
tool: make
filename: Makefile
contributors:
- ["Robert Steed", "https://github.com/robochat"]
- ["Stephan Fuhrmann", "https://github.com/sfuhrm"]
translators:
- ["Andrés Perdomo", "https://github.com/andres7293"]
lang: es-es
---
Un archivo Makefile define un conjunto de reglas para crear un objetivo (o
varios objetivos). Su propósito es hacer la mínima cantidad de trabajo necesaria
para actualizar un objetivo a la versión más reciente de la fuente. Escrito
famosamente en un fin de semana por Stuart Feldman en 1976, todavía se utiliza
ampliamente (especialmente en Unix y Linux) a pesar de muchos competidores y
críticas.
Existen muchas variedades de Make en existencia, no obstante, este artículo
asume que estamos utilizando GNU Make, que es el estándar en Linux.
```make
# Los comentarios se pueden escribir de esta forma.
# El fichero debe tener el nombre de Makefile y luego puede ser ejecutado
# como `make <objetivo>`.
# De lo contrario, se utiliza `make -f "nombre_archivo" <objetivo>`
# Advertencia: ¡solo use TABULACIONES para la identación en Makefiles, nunca
# espacios!
#-----------------------------------------------------------------------
# Fundamentos
#-----------------------------------------------------------------------
# Las reglas tienen el formato
# objetivo: <prerrequisito>
# donde prerrequisito es opcional.
# Una regla - esta regla solamente se ejecutará si file0.txt no existe.
file0.txt:
echo "foo" > file0.txt
# Incluso los comandos en esta sección de 'receta' se pasan a la shell.
# Prueba `make file0.txt` o simplemente 'make' - La primera regla es la
# predeterminada.
# Esta regla se ejecutará solo si file0.txt es más reciente que file1.txt.
file1.txt: file0.txt
cat file0.txt > file1.txt
# Use las mismas reglas de comillas que en la shell.
@cat file0.txt >> file1.txt
# @ evita que el comando se muestre en stdout.
-@echo 'hello'
# - Quiere decir que make continuará en caso de error.
# Pruebe 'make file1.txt` en la línea de comandos.
# Una regla puede tener múltiples objetivos y múltiples prerrequisitos
file2.txt file3.txt: file0.txt file1.txt
touch file2.txt
touch file3.txt
# Make se quejará de múltiples recetas para la misma regla. Sin embargo,
# las reglas vacías no cuentan y se pueden utilizar para agregar nuevas
# dependencias
#-----------------------------------------------------------------------
# Objetivos ficticios (Phony Targets)
#-----------------------------------------------------------------------
# Un objetivo ficticio (phony target). Cualquier objetivo que no sea un archivo.
# Nunca estará actualizado, por lo que make siempre tratará de ejecutarlo.
all: make process
# Podemos declarar cosas sin orden.
maker:
touch ex0.txt ex1.txt
# Se puede evitar que las reglas ficticias (phony) se rompan cuando un archivo
# real tiene el mismo nombre usando:
.PHONY: all maker process
# Esto es un objetivo especial. Hay varios otros.
# Una regla con una dependencia en un objetivo ficticio (phony target)
# se ejecutara siempre:
ex0.txt ex1.txt: maker
# Los objetivos ficticios (phony target) más comunes son:
# all make clean install...
#-----------------------------------------------------------------------
# Variables automáticas y Wildcards
#-----------------------------------------------------------------------
process: file*.txt # usa un wildcard para coincidir con los nombres de archivos.
@echo $^ # $^ es una variable que contiene una lista de todos los prerrequisitos
@echo $@ # imprime el nombre del objetivo
#(para reglas con múltiples objetivos, $@ es el que hizo que se ejecutara la regla)
@echo $< # el primer prerrequisito listado
@echo $? # solo las dependencias que están desactualizadas
@echo $+ # todas las dependencias incluyendo las duplicadas (a diferencia de lo normal)
#@echo $| # solo los 'prerrequisitos solicitados'
# Incluso si dividimos las definiciones de las dependencias, de las reglas, $^
# las encontrará
process: ex1.txt file0.txt
# ext1.xt se encontrará pero file0.txt se duplicará.
#-----------------------------------------------------------------------
# Patrones
#-----------------------------------------------------------------------
# Se puede instruir a make sobre como convertir ciertos tipos de archivos en
# otros archivos.
%.png: %.svg
inkscape --export-png $^
# Las reglas de patrones solo harán algo si make decide crear el objetivo.
# Los directorios no suelen tenerse en cuenta al coincidir con reglas de
# patrones.
# Pero make intentará usar la regla más apropiada disponible.
small/%.png: %.svg
inkscape --export-png --export-dpi 30 $^
# make usará la última versión de una regla de patrón que encuentre.
%.png: %.svg
@echo esta regla es elegida
# Sin embargo make usará la primera regla de patrón que pueda construir el
# objetivo.
%.png: %.ps
@echo esta regla no es elegida si *.svg y *.ps están ambas presentes
# Make ya tiene algunas reglas de patrón integradas.
# Por ejemplo, sabe cómo convertir archivos *.c en archivos *.o.
# En makefiles antiguos se solían utilizar las reglas de sufijo en lugar de las
# reglas de patrón
.png.ps:
@echo esta regla es similar a una regla de patrón.
# Instruye a make sobre una regla de sufijo
.SUFFIXES: .png
#-----------------------------------------------------------------------
# Variables
#-----------------------------------------------------------------------
# también conocidas como macros.
# Las variables son básicamente de tipo cadena (string)
name = Ted
name2="Sarah"
echo:
@echo $(name)
@echo ${name2}
@echo $name # Esto no funcionará, se tratará como $(n)name.
@echo $(name3) # Variables desconocidas se tratarán como cadenas vacías.
# Hay 4 lugares donde se pueden definir variables.
# En orden de prioridad de mayor a menor:
# 1: argumentos de línea de comando.
# 2: Makefile.
# 3: variables de entorno de la shell - make las importa automáticamente.
# 4: make tiene algunas variables predefinidas.
name4 ?= Jean
# Solo establece la variable si la variable de entorno no está aún definida.
override name5 = David
# Detiene que los argumentos de línea de comandos modifiquen esta variable.
name4 +=grey
# Añade valores a la variable (incluye un espacio).
# Valores de variables específicos de patrones (Extension de GNU).
echo: name2 = Sara # Verdadero dentro de la regla coincidente
# y también dentro de sus dependencias recursivas rehechas
# (¡excepto que puede romperse cuando el grafo se complica demasiado!)
# Algunas variables son definidas automáticamente por make.
echo_inbuilt:
echo $(CC)
echo ${CXX}
echo $(FC)
echo ${CFLAGS}
echo $(CPPFLAGS)
echo ${CXXFLAGS}
echo $(LDFLAGS)
echo ${LDLIBS}
#-----------------------------------------------------------------------
# Variables 2
#-----------------------------------------------------------------------
# El primer tipo de variables se evalúan cada vez que se usan.
# Esto puede ser costoso, por lo que existe un segundo tipo de variable que se
# evalúa solo una vez. (Esta es una extensión de GNU make)
var := hello
var2 ::= $(var) hello
#:= y ::= son equivalentes
# Estas variables se evalúan de manera procedimental (en el orden en que
# aparecen), ¡rompiendo así con el resto del lenguaje!
# Esto no funciona
var3 ::= $(var4) and good luck
var4 ::= good night
#-----------------------------------------------------------------------
# Funciones
#-----------------------------------------------------------------------
# make tiene muchas funciones disponibles.
sourcefiles = $(wildcard *.c */*.c)
objectfiles = $(patsubst %.c,%.o,$(sourcefiles))
# El formato es $(func arg0,arg1,arg2...)
# Algunos ejemplos
ls: * src/*
@echo $(filter %.txt, $^)
@echo $(notdir $^)
@echo $(join $(dir $^),$(notdir $^))
#-----------------------------------------------------------------------
# Directrices (Directives)
#-----------------------------------------------------------------------
# Incluye otros makefiles, útil para código de plataformas específicas
include foo.mk
sport = tennis
# Compilación condicional
report:
ifeq ($(sport),tennis)
@echo 'game, set, match'
else
@echo "They think it's all over; it is now"
endif
# También existe ifneq, ifdef, ifndef
foo = true
ifdef $(foo)
bar = 'hello'
endif
```
### Más recursos (en inglés)
+ [GNU Make documentation](https://www.gnu.org/software/make/manual/)
+ [Software carpentry tutorial](http://swcarpentry.github.io/make-novice/)
|