Está en la página 1de 10

Como hacer un

Makefile
Guías Granada.NET
(Junio 2008)

Óscar Valor
Oscar@granada.dotnetclubs.com
Vicepresidente de club .Net de Granada
A lo largo de este breve documento, vamos a intentar explicaos de la forma más sencilla
posible como lograr hacer un makefile que funcione y no morir en el intento (o borrarnos la practica
por el camino, que no sé que es peor).

Partamos de un programa muy sencillo llamado, en un alarde de originalidad, programa.cpp


tal que así:

#include <iostream>
using namespace std;

int main()
{
cout << "\n Estudiando para conquistar el mundo... \n";
}

Bueno amigos, veamos como es eso que dicen que es tan difícil, vamos a empezar por lo
más sencillo, compilar programa.cpp desde consola:

[consola]$> make programa

Hasta aquí todo muy bonito, se crea el ejecutable programa (en algunas consolas de Linux
para ejecutar el programa es necesario poner [consola]$>./programa indicando con el ./ que
es en este fichero). Vamos a hacerlo usando g++

[consola]$> g++ programa.cpp

De esta manera ha creado el ejecutable, pero con el nombre a.out que es mucho mas feo
que programa. Así que vamos a ponerle el nombre que nosotros queramos

[consola]$> g++ programa.cpp -o cmundo

De esta manera le decimos al compilador el fichero de salida (-o) se va a llamar cmundo


(palabra en clave de conquistar el mundo).

Ahora vamos a crear un fichero objeto, que se llamará programa.o (Los ficheros objeto son
los ficheros compilados con nuestro código que más adelante nos sirven para poder enlazar
programas entre sí, y que nadie sepa que hemos escrito en los ficheros fuentes, pero puedan usar
nuestros programas). Para hacer esto hay que usar la palabra -c

[consola]$> g++ -c programa.cpp

Ahora nos ha creado el objeto programa.o, pero mira por donde se me ha olvidado poner -
o programa y esta vez linux está de nuestro lado, ha hecho el programa con el nombre bien (un
aplauso para linux). Vamos a probar poniendo todas las opciones anteriores:

[consola]$> g++ -c programa.cpp -o programa

Y ahora nos sale un archivo llamada programa, que no lo podemos ejecutar, ya la hemos
liado. Nooo, vamos a ver, hemos dicho que con -c se sacan objetos, pues hemos creado un objeto
con un nombre un poco conflictivo, el nombre del ejecutable que queríamos sacar. Así que habrá
que ponerlo bien:
[consola]$> g++ -c programa.cpp -o programa.o

Ahora ya no se lía nadie. Bien vamos a ver que hemos visto. Cuando se genera un archivo
con g++ el compilador por defecto va a sacar el ejecutable como a.out, así que usaremos -o para
decirle como queremos que se llame y cuando le ponemos el -c va a sacar por defecto el objeto
programa.o.

-2-
Bueno, llegamos a lo que todos temíamos: El Makefile, Asesino de Almas. Vamos a
empezar por algo sencillo, un fichero llamado Makefile tal que así:

. g++ programa.cpp -o cmundo

Y yasta, hemos puesto lo que habíamos hecho en consola. Fijaos en un detalle. He puesto un
punto al principio, pero no porque haya que ponerlo, sino para representar que las instrucciones en
consola SIEMPRE hay que ponerlas con una tabulación dentro del makefile. Vale, ahora vamos a
ejecutarlo desde consola:

[consola]$>make
Makefile:1: *** las instrucciones comenzaron antes del primer objetivo.
Alto.

Ya la hemos liado. Mira que sabía que era complicado. ¡¿¡¿Y que me está contando de
noseque objetivos?!?!. Vale, que no cunda el pánico, en una línea de código no nos podemos haber
equivocado mucho. Aquí pasa lo siguiente tenemos que añadirle una etiqueta (su nombre de verdad
es objetivo, pero con etiqueta creo que es mas como para todos). Probablemente no sepáis que es
una etiqueta si usáis lenguajes de alto nivel como C++, C#, Java, porque usar las etiquetas en estos
lenguajes es vender tu alma al diablo y luego vas al infierno, como todo el mundo sabe. Pero en
otros lenguajes como ensamblador (ese lenguaje que todos queremos tanto) es imprescindible. Una
etiqueta se describe con un nombre con dos puntos, por ejemplo, etiqueta : , que sirve para que
desde cualquier otra parte del programa si se llama a la etiqueta (poniendo su nombre sin los dos
puntos) el programa sigue ejecutándose desde la etiqueta (y en los makefiles terminará de ejecutarse
cuando empiece una nueva etiqueta), se podría decir que es como una función, a la que llamas para
ejecutar un código. Así que esto quedaría así:

programa :
g++ -c programa.cpp -o cmundo

Expliquemos un poco lo que pone, la etiqueta programa (también conocida en este caso
como regla explícita, ya que impone unas reglas de compilación) va a compilar programa.cpp, y en
la siguiente línea con un tabulador empezamos a escribir la línea de código que habíamos escrito en
consola, y a partir de ahora desde consola sólo habrá que poner make para que se ejecute.

[consola]$> make

Y todo va bien y funciona de maravilla. Uff, casi parece difícil. Bueno, ahora vamos a
complicarlo un poco. Alguien en un arranque de euforia quiere añadir un fichero .h que ha creado,
llamado funciones.h y es tal que así:
#include <iostream>
using namespace std;

void imprimir(char* c)
{
cout << c;
}

Y a programa.cpp lo cambiamos por:

#include <funciones.h>
using namespace std;

int main()
{
Imprimir("\n Estudiando para conquistar el mundo... \n");
}

-3-
Ejecutamos el make por consola:
[consola]$> make
g++ programa.cpp -o cmundo
programa.cpp:2:23: error: funciones.h: No existe el fichero ó directorio
programa.cpp: In function ‘int main()’:
programa.cpp:7: error: ‘imprimir’ no se declaró en este ámbito
make: *** [programa] Error 1

Y nos vuelve a reventar. No encuentra funciones.h. Entonces es cuando llega el listo y dice:
pues ponle comillas (“ ”) en vez de menor mayor (< >). Y claro, funciona, pero voy a ser malo y
voy a poneros un caso en el que eso no sirve, vamos a añadirlo en otro directorio, llamado inc de
esta manera:
./ // Directorio actual
|- programa.cpp
|- Makefile
|- inc // Carpeta
|- funciones.h

Ahora hemos metido la pata, ya si que no se puede hacer nada contra el sistema. No os
preocupéis, todavía hay esperanza. Hay una opción que nos sacará de este atolladero, la opción -I,
que indica en que carpetas tiene que buscar el compilador para enlazar, es decir, donde hemos
metido el código, que no se va a poner a buscar por todo el disco duro el g++, no gana para tanto.
Así queda el makefile de esta manera:
programa :
. g++ programa.cpp -I inc -o cmundo

(Recordad que el punto es para indicar que hay una tabulación, no porque haya que poner un
punto). Ejecutamos en consola y:

[consola]$> make
g++ programa.cpp -I inc -o cmundo

Voilá, funciona. Y ya da igual si es con comillas (“ ”) o con menor mayor el include (< >)
porque g++ ya sabe donde tenemos escondidos los archivos.

Bueno, vamos a complicar esto para darle emoción. Supongamos ahora que nos
preguntamos, ¿tanto lío al principio con los objetos y el -c y no lo usamos para nada? Bueno, vamos
a usarlos. Vamos a hacer la compilación por partes. Probablemente aquí no le veáis ahora mucha
utilidad, pero pensad que estamos compilando un solo fichero, cuando hay muchos más la cosa se
complica y hay que organizarse, así que vamos a ir preparándonos. Vamos a ver la versión más
sencilla:

programa :
. g++ -c programa.cpp -I inc
. g++ programa.o -o cmundo

Si ejecutamos make sale todo a la perfección. Fijaros que donde se pone el -I es cuando se
hace el objeto, y que no hemos puesto -o programa.o en la primera instrucción porque ya sabemos
que el compilador le pone el nombre bonito a los objetos automáticamente (aunque si queréis
aseguraros podéis ponerlo, que no cambia nada). Pero esto plante un problema. Todo es un bloque,
y a mi me gustaría que pudiera hacer sólo el objeto sin tener que hacer también el ejecutable. Así
que habrá que arreglarlo. La primera idea sería esta:
programa_o :
. g++ -c programa.cpp -I inc

-4-
programa :
. g++ programa.o -o cmundo

Si ahora ejecutamos make nos sale:


[consola]$> make
g++ -c programa.cpp -I inc

Aquí nos falta algo...., ostras, la línea del ejecutable. ¿Que ha pasado? Bien, seamos por un
momento la máquina que ejecuta el makefile. Abrimos el fichero, leemos la primera etiqueta,
ejecutamos la instrucción, no hay más instrucciones, pues nos salimos.

¿¿No debería de leer todo?? Pues no. Ahora mismo con lo que he contado no se entiende el
porqué. Así que os voy a contar la auténtica historia de las etiquetas (cuyo nombre real son
objetivos):

Una etiqueta, sirve para llamar desde consola a las líneas de instrucción que van precedidas
de una tabulación. es decir, podemos ejecutar desde consola el makefile de esta manera:
[consola]$> make programa
g++ programa.o -o cmundo

Y hace lo que nos faltaba de instrucción. Pero claro, no nos vamos a poner a llamar al make
cada vez que queramos ejecutar cada parte del programa. Por eso las etiquetas están definidas de
esta forma:
etiquetas : otras etiquetas
Instrucciones de consola precedidas de tabulación

Las otras etiquetas son las listas de dependencias, que es sólo la forma de decir que otras
etiquetas tenemos que hacer antes de ejecutar las instrucciones. Y abusando de esto, se puede hacer
un pequeño truco, que es como lo hace todo el mundo para lanzar el make. Crear una etiqueta sin
instrucciones y así llamar a las etiquetas que nos hacen falta. He aquí como quedaría:
todo : programa_o programa

programa_o :
g++ -c programa.cpp -I inc
programa :
g++ programa.o -o cmundo

Ahora si lanzamos el make si nos lanza las dos instrucciones, porque la primera etiqueta que
lee es todo, y esta a su vez llama a generar el objeto y el ejecutable. El orden es importante, porque
no puedes crear el ejecutable a partir del objeto, si no tienes el objeto. Así que aquí se sigue viendo
un problema, si hacemos:
[consola]$> make programa
g++ programa.o -o cmundo
g++: programa.o: No existe el fichero ó directorio
g++: no hay ficheros de entrada
make: *** [programa] Error 1

No encuentra a programa.o (si lo probáis sin haber borrado el programa.o que habíais
generado antes no os dará este error, pero siempre estaréis compilando el programa que
compilasteis en el .o). Así que hay que decirle que cuando haga programa haga también el objeto.
Esto es fácil, ya somos casi unos expertos:
todo : programa_o programa

programa_o :
g++ -c programa.cpp -I inc

-5-
programa : programa_o
g++ programa.o -o cmundo

Lo lanzamos y:
[consola]$> make programa
g++ -c programa.cpp -I inc
g++ programa.o -o cmundo

Perfecto. Ya hemos terminado de aprender cómo compilar un fichero sencillo, y conocer


porqué puede estar dándonos errores el makefile. Ahora un detalle. Si ahora ejecutamos sólo make
y lo lanzamos debería de ejecutarse: programa_o, programa (y cuando empiece se vuelve a ejecutar
programa_o) y luego las instrucciones de programa. Entonces, ¿Lo estamos ejecutando dos veces?
La verdad es que no, porque la instrucción make ejecuta la etiqueta cuando hace falta, es decir, no
la ejecuta si:

- Ya la ha ejecutado antes
- El fichero del nombre de la etiqueta no ha sido creado en esta ejecución del makefile

Esto último sólo pasaría si generamos con dos reglas distintas la misma instrucción. Se
detiene si la etiqueta tiene el nombre del fichero. Lo que pasa es que ponerle a la etiqueta el nombre
del fichero es un poco peligroso si no se sabe que pasa en realidad. Hay que tener cuidado con lo
que se pone, ya que una etiqueta llamada como un fichero, sin ejecutar ninguna acción, lanza un
conjunto de acciones de compilación básicas, que puede desbocar en un error si hay que añadirle
información al g++. Así que si se usa una etiqueta con el nombre de un fichero (o el nombre de un
fichero.cpp sin .cpp) siempre hay que ponerle una acción, que sino se pasa de listo el makefile y nos
da un disgusto.

Vamos a ver ahora algunos detalles, como por ejemplo, si quisiéramos crear un makefile que
tuviera otro nombre que no fuera Makefile, sino makefil, o make2 o algo así, para llamarlo habría
que poner:

[consola]$> make -f makefil

O si quisiéramos llamar a otro makefile que está en otra carpeta desde nuestro makefile, hay
que poner la orden -C <directorio> para saber que se ejecuta.

etiqueta :
. make -C ./carpeta/

Bueno, sigamos aprendiendo más cosas interesantes. Supongo que conoceréis o al menos os
sonarán las macros en c++, del tipo: #DEFINE paco_pepe 25 y que cada vez que pongáis
paco_pepe es como si pusierais 25, (si a alguien les resulta extrañas, se pueden ver como unas
variables que no vas a cambiar de valor) pues el makefile no es menos y también tiene macros, si,
si, y además luego nos serán de ayuda, porque ahorran trabajo, ya lo veréis. Bueno, hagamos las
macros más conocidas:

INC = inc
SRC = src
OBJ = obj
LIB = lib
BIN = bin

GPP = g++
# g plus plus, lo ponemos como macro porque existen otro tipo
# de compiladores, aunque de momento sólo vamos a usar gcc,
# que es muy bonito

-6-
Declarar las macros no ha sido doloroso, ni algo superdifícil, tal vez algo largo porque hay
muchas carpetas. Las macros se definen así <nombre> = <valor>. Se puede considerar para hacer
un símil más sencillo, con que las macros son variables string (cadenas de caracteres) fijas. El
símbolo # es vuestro amigo porque significa comentario (hay que tener cuidado al ponerlo a la
derecha de las definiciones que no coge bien la variable), y seguro que os sirve de ayuda para
recordar porqué pusisteis algo en ese sitio (y ## sirve para doxygen) Así que vamos a aprender a
utilizarlas en el programa. Volvamos a escribir lo que teníamos con las macros:

todo : programa.o programa

programa.o:
$(GPP) -c programa.cpp -I $(INC)

programa : programa.o
$(GPP) programa.o -o cmundo

Tampoco nos vamos a matar, la verdad es que ese símbolo $ es un poco feo, pero si lo
piensas, es el símbolo del dinero, y si tener dinero es bueno, porqué no lo es tener muchos dólares
en el makefile, se puede decir que es un makefile apoderado y rico. Pero todavía no es
multimillonario, porque todavía nos faltan macros por crear. Si sabemos que siempre vamos a poner
-c, y vamos a incluir siempre los archivos del include, entonces vamos a crear más macros que nos
hagan más ricos, y así algún día conquistaremos el mundo:

FLAGS = -c -I$(INC)

Así el programa se queda de la forma:

todo : programa.o programa

programa.o:
$(GPP) $(FLAGS) programa.cpp

programa : programa.o
$(GPP) programa.o -o cmundo

Además de rico, elegante. Aunque tenemos los mismos dólares, hay menos código que nos
estorbe a la vista. Algún avispado se habrá dado cuenta que de esta manera hemos cambiado el
orden, bien visto, pero lo que no sabe es que el único orden que importa es que g++ sea lo primero
que pone, el resto no importa (es obvio que -o fichero_salida va junto al igual que -I inc
también, pero no importa si uno va delante de otro)

Ahora podemos añadir a nuestra amiga @, una a repeinada conocida en los correos
electrónicos, que a nosotros nos va a servir para que cuando compilemos quitemos esa línea fea que
nos recuerda lo que hemos escrito. Así si ponemos:

todo : programa.o programa

programa.o:
@$(GPP) $(FLAGS) programa.cpp

programa : programa.o
@$(GPP) programa.o -o cmundo

Ya no nos sale la línea recordándonos que habíamos escrito, pero tampoco me gusta que no
salga nada, ¿y si hacemos que salga lo que nosotros queramos?, bueno, pues usaremos echo:

todo : programa.o programa

programa.o:
@echo Creando programa.o

-7-
@$(GPP) $(FLAGS) programa.cpp

programa : programa.o
@echo Creando el ejecutable cmundo
@$(GPP) programa.o -o cmundo

Ahora sí sale exactamente lo que queríamos, una línea bonita que dice lo que hace pero en
español y no el lenguaje máquina. Si lo miráis bien, si le hemos puesto una @ no debería de salir
nada... Este nos está tomando otra vez el pelo. Pues no, porque con la instrucción echo si pones una
@ delante sólo tapa el echo, y lo que quieres escribir sale sin decir: echo Creando el ejecutable
programa

Ahora vamos a dar el último paso para que nuestro pequeño proyecto esté terminado, es
generar cada archivo y leerlo de su carpeta correspondiente. Es decir, si tenemos los .cpp dentro de
la carpeta src (source), los .h en inc (include), los .o en obj (objetcs), y los ejectables en bin. Lo
primero que hay que hacer es crear las carpetas aunque estén vacías, porque el makefile no tiene
permisos para crear carpetas. Una vez creadas, y metidos los ficheros de código en su sitio, al
makefile sólo hay que decirle delante de cada archivo donde está o donde va, así que queda tal que
así:

INC = inc
SRC = src
OBJ = obj
LIB = lib
BIN = bin

GPP = g++
FLAGS = -c -I$(INC)

todo : programa.o programa

programa.o:
@echo Creando programa.o
@$(GPP) $(FLAGS) $(SRC)/programa.cpp -o $(OBJ)/programa.o

programa : programa.o
@echo Creando el ejecutable cmundo
@$(GPP) $(OBJ)/programa.o -o $(BIN)/cmundo

Bueno, ahora viene la parte buena, esa en la que todo esto parece tontería al lado del todo lo
que tenéis luego que escribir. Pero no os asustéis, yo lo he escrito y sólo he estado al borde de
destrozar el ordenador 3 veces por culpa del makefile, no entendía como lo explicaban en los otros
documentos, como podía hacerlo siempre mal y no tenía solución. Pero vosotros tenéis este manual,
que ayuda bastante, y la verdad es que hay mucho más de lo que voy a explicar, pero con lo que hay
aquí es suficiente para programar casi todo.

Bueno, vamos a explicar primero que es una librería (en verdad es library, que significa
biblioteca, pero luego veréis que hay que usar instrucciones en las que nos ayudará llamarla librería
en vez de biblioteca). Una librería es un conjunto de objetos, es decir, que en vez de tener que crear
un ejecutable con todos los objetos que queremos, podemos hacer una bola con ellos y meterlos en
1, creando una librería. Se puede ver también como una forma de poder comercializar tu librería, y
que otras personas la usen. El código del makefile para crear una librería es:

libMiLibreria.a :
@echo Creando biblioteca libMiLibreria.a
@ar rvs $(LIB)/libMiLibreria.a $(OBJ)/objeto1.o $(OBJ)/objeto2.o ...

Se puede ver que se necesita el fichero objeto a meter en la librería y luego usamos en vez
de g++ el compilador ar y le ponemos los flags r, v y s, que significan:

-8-
r : reemplazar en caso de que se haya actualizado el objeto,
v : imprime por consola si se ha actualizado o no
s : crea un índice en la biblioteca para enlazarla.

Ahora vemos que usamos más macros, pero su explicación es bastante intuitiva, el archivo
claseAparte.o se encuentra en la carpeta OBJ, va a crear la librería libClaseAparte.a en la carpeta
LIB con el objeto claseAparte.o que como ya dijimos se encuentra en OBJ, y lleva la / delante
porque es el archivo ./lib/libClaseAparte.a el que se va a crear.

Ahora también sabemos hacer librerías, veamos como se crea un ejecutable con librerías:

programa :
@echo Creando ejecutable programa
@$(GPP) $(OBJ)/ programa.o $(LIBFLAGS) -o $(BIN)/programa

Aquí hemos cambiado de nuevo como hacer un ejecutable. Ya sabemos hacerlo con el cpp,
el objeto y con las librerías. Sabemos hacer de todo. Pero hay aquí una macro LIBFLAG a la que no
nos han presentado. Bueno, esta macro es tal que así:

LIBFLAG = -L$(LIB) –lClaseAparte

Tenemos la instrucción –L, parecida a –I , que se refiere a lo mismo, -L indica en que


directorio hay que buscar las librerías. Y –lClaseAparte, que nombre más raro, se parece a
libClaseAparte.a pero no empieza por lib ni tiene el .a, pues es porque para incluir las librerías
hay que transformar el nombre. Las librerías en un makefile deben de empezar por lib, con
extensión .a, y para indicar cuáles vamos a usar se preceden por –l y se les quita la extensión.
Dicho así no es tan difícil, ¿verdad?.

Bueno otra cosa MUY IMPORTANTE, el orden en que se incluyen las librerías es crucial
para que funcione bien o mal. Se deben de incluir de derecha a izquierda, estando a la derecha
aquellas librerías que no dependen de nadie y a la izquierda las que dependen de las de la derecha.

También es importante saber que aquí $(LIBFLAGS) tiene que ir después que la declaración
del objeto, sino no funciona. Aquí no pasa como con los flags –I y –c que pueden ir al principio o al
final, este si tiene que respetar un orden.

ATENCION AL NAVEGANTE: Si ya has llegado hasta aquí te recomendamos que crees una copia
de seguridad de todo lo que lleves, porque vamos a empezar a borrar (y borrando nunca se sabe), y
a nadie le haría gracia que por faltarnos un simple ‘.’ se nos fuera todo al garete.

¿Qué es el borrado?, pues es algo que no se le presta importancia pero que es bastante
importante. Yo aconsejo encarecidamente que lo primero que hagas antes de compilar sea borrar los
archivos creados, porque muchísimas veces te dirá que no está actualizado, o tiene un warning en
vez de un error, y te deja el último objeto creado, y tienes errores de un archivo que has modificado
hace media hora y no sabes que le pasa, y es que no se ha actualizado el objeto y te sigue dando los
mismos errores. Así que perder medio segundo más borrando y volviendo a ejecutar de nuevo
merece la pena antes de buscar errores en un código que no refleja lo que has creado en el objeto.
Para borrar se crea una etiqueta llamada clean, por ejemplo, de esta manera:

## Borrar ficheros ejecutables y intermedios


mrproper : clean cleanexe

## Borrar ficheros innecesarios


clean :
@echo Borrando ficheros innecesarios
@rm -rf $(OBJ)/*.o $(LIB)/libMiLibreria.a $(SRC)/*~ $(INC)/*~ ./*~

-9-
## Borrar ejecutables
cleanexe :
@echo Borrando los ejecutables
@rm -rf $(BIN)/*

-rf indica que se borra sin preguntar y si hay subdirectorios también se borran estos. Mi
consejo es que no pongáis esta etiqueta hasta que no estéis seguros que lo que habéis puesto
funciona, y la primera vez que lancéis el borrado, tened hecha una copia de seguridad de los
ficheros fuentes, por si acaso (y si usáis -rf no dentro de la misma carpeta, por si hacéis rm -rf ./). Si
nos fijamos borramos los ficheros que genera Linux de seguridad (los que acaban en ~) y los puntos
objeto y de las librerías no las borramos todas porque las librerías prestadas no la volveríamos a
crear con este makefile, y hay que conservarla para que luego podamos enlazarla.

Nos queda el Doxygen, que es la documentación en formato html, latex ó xml que nos saca
doxygen de lo que hayamos documentado en nuestros programas. Para ejecutar doxygen primero
hay que crear un fichero llamado Doxyfile, donde se detallarán todos los datos acerca de la
presentación de la documentación: formato, nombre del proyecto, versión , autor, idioma.... y
muchas más cosas. Para crearlo tecleamos en consola:

[consola]$> doxygen –g

Y te dirá que ya tienes creado el Doxyfile, ahora con un editor de textos, lo abres y
modificas todas las opciones importantes para que la documentación sea correcta, el único
inconveniente es que está en inglés, pero bueno, hay que acabar acostumbrándose. Así en el
Makefile añadimos estas líneas para que doxygen (con –s para evitar que nos salga una ristra
gigante de instrucciones (porque aún así salen bastantes)) cree la documentación a partir de lo que
le hemos indicado:

doxygen :
@echo Creando documentación con Doxygen
@doxygen Doxyfile -s

Es importante el orden para crear los archivos. Primero las clases que no dependen de nadie,
luego las clases que dependan de clases ya creadas, y así hasta terminar las clases. Luego lo objetos
de los ejecutables, pues estos dependen de las clases (por norma general, porque no haríamos una
clase si no la vamos a utilizar). Una vez creados todos los objetos, pasaos a enlazar las clases en
librerías, y cuando ya tienes las librerías crea los ejecutables. Ese es el orden para llamar a las
funciones. Y se pude mantener gracias a las dependencias, es decir, poniendo al lado de cada
etiqueta de que depende lo que estás ejecutando para que lo ejecute antes. La prueba de fuego es
hacer make con todas las etiquetas que tengas y comprobar que con ninguna te da error.

Ahora se puede resumir más el código, pero eso ya lo dejo a vuestra imaginación y
creatividad. La pista que os dejo es que hay muchas macros que están escritas seguidas y que se
pueden juntar en una macro gigante, los nombres de las macros pueden ser mas cortos (cuidado
porque puede volverse muy lioso) y hay algunas cosas como lo era la @ que aparecen cerca y
siempre se pueden añadir a la macro.

A divertirse.

- 10 -