malloc, free, append

This commit is contained in:
2026-10-02 11:36:59 +02:00
parent b8141311aa
commit 9d517f3607
13 changed files with 960 additions and 13 deletions
+79 -2
View File
@@ -26,6 +26,19 @@ objetivo: prerrequisitos
- **Prerrequisitos**: los ficheros de los que depende.
- **Receta**: los comandos de shell que producen el objetivo.
Es como una receta de cocina: *plato: ingredientes* y, debajo, los pasos.
```make
build/hello: build/hello.o build/escpos.o
$(CC) build/hello.o build/escpos.o -o build/hello
```
| Parte | Qué es | Pregunta que responde |
|---|---|---|
| `build/hello` (antes de `:`) | **Objetivo**: el fichero que sale. No es el nombre de un comando. | ¿Qué quiero tener? |
| `build/hello.o build/escpos.o` (después de `:`) | **Prerrequisitos**: los ficheros que necesita. | ¿Qué hace falta antes? |
| línea con tabulador | **Receta**: el comando. | ¿Cómo se fabrica? |
Make rehace un objetivo si no existe o si **algún prerrequisito tiene una fecha
de modificación más reciente** que él. No usa hashes como Go: solo compara
fechas (`mtime`). Por eso un `touch` basta para forzar una recompilación.
@@ -54,8 +67,33 @@ build/escpos.o: src/escpos.c include/escpos.h
**En Go** es la diferencia entre llamar a `go build` paquete por paquete desde
un script y dejar que `go build` resuelva los imports.
Make recorre el grafo desde el objetivo que le pides (o el primero del fichero)
hacia sus prerrequisitos, en profundidad.
### Make va hacia atrás
Make no ejecuta el Makefile de arriba abajo como un script. Empieza por el
objetivo que le pides (o el primero del fichero si no pides ninguno) y va
tirando de lo que necesita:
```
all
└─ build/hello (enlazar)
├─ build/hello.o ← examples/hello.c + escpos.h
└─ build/escpos.o ← regla patrón: src/escpos.c + escpos.h
```
1. Le pides `all`, que necesita `build/hello`.
2. `build/hello` necesita `build/hello.o` y `build/escpos.o`.
3. Para cada prerrequisito busca una regla que lo fabrique y repite lo mismo,
hasta llegar a ficheros que ya existen (`examples/hello.c`, `src/escpos.c`).
4. Después construye de las hojas hacia arriba. Antes de cada receta compara
fechas: si el objetivo existe y es más nuevo que todos sus prerrequisitos,
no lo rehace.
El orden de las reglas en el fichero da igual. Solo importa que `all` sea la
primera, porque es la que se construye por defecto.
Nadie le dice a Make "compila `escpos.o`": llega ahí porque `build/hello` lo
pide. Si un objetivo no aparece como prerrequisito de nada, Make no lo
construye.
## Piezas que vas a necesitar
@@ -103,6 +141,45 @@ cambies compilador o flags: `make clean` y construir de cero.
**En Go** los flags y la versión del compilador forman parte del hash de la
caché, así que `go build` sí recompila lo necesario.
### Regla patrón = función con parámetros
Una regla patrón es como una función de Go, y `$@` y `$<` son sus parámetros:
```make
build/%.o: src/%.c
$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@
```
```go
// Equivalente mental en Go
func buildObject(target, source string) { // target = $@, source = $<
run("gcc -std=c17 ... -c " + source + " -o " + target)
}
```
Cuando Make necesita `build/escpos.o`:
1. Busca una regla para `build/escpos.o`. No hay ninguna escrita a mano.
2. Prueba la regla patrón `build/%.o`. Encaja, con `%` = `escpos`.
3. Calcula el prerrequisito: `src/%.c` → `src/escpos.c`.
4. "Llama a la función": `$@` = `build/escpos.o`, `$<` = `src/escpos.c`.
5. Sustituye las variables, **imprime el comando ya sustituido** y lo ejecuta.
Por eso en la salida de `make` nunca se ve `$<`: Make imprime el comando
después de sustituir, igual que `fmt.Printf` imprime los valores y no `%s`.
Otro ejemplo, para `build/buffer.o`:
| | Valor | Ojo |
|---|---|---|
| `%` | `buffer` | Solo la parte que varía: sin carpeta ni extensión. |
| `$@` | `build/buffer.o` | El objetivo **completo**, con su carpeta. |
| `$<` | `src/buffer.c` | El prerrequisito **completo**, con su carpeta. |
**La regla patrón es una plantilla, no compila "todo lo que hay en `src`".**
Make solo la usa cuando algún objetivo pide un `build/ALGO.o`. Si creas
`src/buffer.c` y nadie pide `build/buffer.o`, no se compila.
## El problema de las cabeceras
Si `escpos.c` incluye `escpos.h` y cambias solo el `.h`, make no lo sabe: