En un Makefile, las reglas se definen de la siguiente manera: ```
Los comentarios se escriben con "#"
objetivo1 objetivo2 ... : dependencia1 dependencia2 ...
Las reglas pueden no tener dependencias ni objetivos; estos últimos se llaman "objetivos ficticios" (phony targets)
comando1 # Cada comando debe precederse de una tabulación
comando2 # Cada comando debe precederse de una tabulación
- **Objetivo:** El archivo que se genera al ejecutar el comando asociado.
- **Dependencia:** Archivos necesarios para construir el objetivo.
- **Comando:** Instrucciones que se ejecutan para generar el objetivo.
Ejemplo: ```
# Múltiples objetivos y comandos
app1 app2 : a.c b.c c.c
gcc -o app1 a.c b.c
gcc -o app2 b.c c.c
1.1 Control de impresión en Makefile
Por defecto, Makefile muestra los comandos que se ejecutan durante la compilación. Para evitar esto, antecede los comandos con @. ```
sin_salida: @echo 'No se muestra' echo 'Se muestra'
Resultado: ```
$ make sin_salida
No se muestra
echo 'Se muestra'
Se muestra
2. Funcionamiento de Makefile
2.1 Ejecución de reglas
Ejemplo: ```
makefile
Reglas anidadas
app: a.o b.o c.o gcc a.o b.o c.o -o app
a.o: a.c gcc -c a.c
b.o: b.c gcc -c b.c
c.o: c.c gcc -c c.c
Conclusión: 1. Al ejecutar `make`, busca la primera regla del Makefile y verifica si todas sus dependencias existen.
2. Si alguna dependencia no existe, busca qué regla puede generarla.
3. Verifica si cada objetivo es más reciente que sus dependencias; si no lo es, ejecuta recursivamente las reglas necesarias.
#### 2.2 Tiempos de modificación de archivos
Make verifica si algún archivo de dependencia ha sido modificado después del objetivo. #### 2.3 Inferencia automática
Makefile puede inferir automáticamente cómo compilar archivos `.c` a `.o`. #### 2.4 Objetivos ficticios
Un objetivo ficticio, como `clean`, no genera ningún archivo. ```
.PHONY: limpiar
limpiar:
-rm $(objetos) $(binario)
@echo "Archivos temporales eliminados."
3. Variables
Existen tres tipos de variables: personalizadas, predefinidas y automáticas. #### 3.1 Variables personalizadas
Definición: nombre_variable = valor Uso: $(nombre_variable) #### 3.2 Variables predefinidas
Ejemplo: ```
objetos = add.o div.o main.o mult.o sub.o binario = calc CFLAGS = -O3
$(binario): $(objetos) $(CC) $(objetos) -o $(binario) $(CFLAGS)
#### 3.3 Variables automáticas
| Variable | Implicación |
|---|---|
| $\* | Nombre del archivo objetivo sin extensión. |
| $@ | Nombre completo del archivo objetivo. |
| $< | Primera dependencia. |
| $? | Dependencias más recientes que el objetivo. |
| $^ | Todas las dependencias sin repeticiones. |
| $+ | Todas las dependencias incluyendo repeticiones. |
Ejemplo: ```
calc: add.o div.o main.o mult.o sub.o
gcc $^ -o $@
3.4 Métodos de asignación de variables
variable = valor # Retrasa la evaluación hasta su uso.
variable := valor # Evalúa inmediatamente.
variable ?= valor # Solo asigna si la variable no está definida.
variable += valor # Concatena valores.
4. Coincidencia de patrones
Se usa % como comodín para representar nombres de archivo genéricos. ```
%.o: %.c gcc $< -c -o $@
### 5. Funciones
Ejemplo de función `wildcard`: ```
archivos = $(wildcard *.c ./src/*.c)
Función patsubst: ```
fuentes = aa.c bb.c objetos = $(patsubst %.c, %.o, $(fuentes))
### 6. Ejercicio práctico
Estructura de archivos: ```
├── Makefile
├── include
│ └── head.h
├── main.c
└── src
├── add.c
├── div.c
├── mult.c
└── sub.c
Makefile: ```
CC = gcc CFLAGS = -Wall -O2 CFLAGS += -DENABLE_FLAG objetivo = test.out cabeceras = ./include fuentes = $(wildcard ./.c ./src/.c) objetos = $(patsubst %.c, %.o, $(fuentes))
$(objetivo): $(objetos) $(CC) $(CFLAGS) $^ -o $@
%.o: %.c $(CC) $(CFLAGS) -I $(cabeceras) -c $< -o $@
.PHONY: limpiar limpiar: -rm $(objetos) $(objetivo) @echo "Archivos temporales eliminados."
### 7. Expresiones condicionales
Ejemplo de condicional: ```
ifdef VARIABLE
comando_si_verdadero
else
comando_si_falso
endif