Build moderno con Meson
El sistema de build que ha ganado en C moderno: rápido, legible y con sanitizers integrados. De un meson.build mínimo a targets, dependencias y opciones.
Compilar a mano con flags está bien para aprender; para un proyecto real necesitas un sistema de build. Meson se ha convertido en el favorito del C moderno: sintaxis limpia, compilaciones rapidísimas (usa Ninja por debajo) y soporte integrado para lo que importa, como los sanitizers.
- Por qué un sistema de build.
- Un
meson.buildmínimo y el flujo configure/compile. - Ejecutables, bibliotecas y dependencias.
- Opciones y sanitizers integrados.
Por qué un sistema de build
Escribir gcc -std=c23 -Wall -Wextra ... a.c b.c c.c -o prog a mano no escala: olvidas flags, recompilas todo aunque cambie un archivo, y no es portable. Un sistema de build declara qué construir y él calcula el cómo: qué recompilar, en qué orden, con qué flags.
Un meson.build mínimo
project('mi_proyecto', 'c',
version: '1.0.0',
default_options: ['c_std=c23', 'warning_level=3', 'werror=true'])
executable('prog', 'main.c', 'mates.c')
warning_level=3 equivale a -Wall -Wextra -Wpedantic, y werror=true a -Werror: los buenos hábitos del nivel 2, en una línea y para todo el proyecto.
El flujo: configure y compile
meson setup build # configura (una vez): crea el directorio build/
meson compile -C build # compila (usa Ninja, rapidísimo)
./build/prog # ejecuta
Meson separa configuración de compilación, y hace builds fuera del árbol (todo en build/, tu código fuente queda limpio). Cambia un archivo y meson compile solo recompila lo necesario.
Bibliotecas y dependencias
# una biblioteca propia
milib = library('mates', 'mates.c', install: true)
# un ejecutable que la usa
executable('prog', 'main.c', link_with: milib)
# una dependencia externa del sistema
m_dep = dependency('threads') # busca la librería de hilos
zlib = dependency('zlib', required: false)
executable('app', 'app.c', dependencies: [m_dep, zlib])
Meson localiza dependencias del sistema (vía pkg-config) y, si activas subproyectos/wraps, hasta las descarga. Adiós a las rutas de include cableadas a mano.
Opciones y sanitizers integrados
Aquí brilla Meson para C. Los sanitizers (nivel 24) se activan como una opción de build, sin tocar tu meson.build:
# compila todo con AddressSanitizer + UndefinedBehaviorSanitizer
meson setup build-asan -Db_sanitize=address,undefined
meson compile -C build-asan
El patrón que Meson hace trivial y que usan los equipos serios: mantener varios directorios de build a la vez, cada uno con su configuración. Un build/ normal optimizado, un build-asan/ con sanitizers para cazar bugs de memoria, un build-debug/ con símbolos y sin optimizar para gdb. Cambias de uno a otro sin reconfigurar nada, porque cada build/ es independiente y guarda su estado. Esto convierte “compilar con sanitizers” o “hacer un build de release” en un comando, no en un ritual de flags. Un buen sistema de build no es burocracia: es lo que hace baratas las buenas prácticas, y por eso las acabas usando.
Meson genera archivos de Ninja, un backend de build minimalista y velocísimo, en vez de Makefiles. Para un proyecto nuevo en C, Meson es hoy la opción más ergonómica y rápida. Aun así, entenderás Make (nivel 18): sigue siendo omnipresente, y el kernel de Linux y millones de proyectos lo usan.
- Escribe un
meson.buildconc_std=c23,warning_level=3ywerror=true. - Compila un proyecto de varios archivos con
meson setup+meson compile. - Añade una biblioteca propia con
library()y enlázala conlink_with. - Crea un segundo directorio de build con
-Db_sanitize=address,undefinedy corre tu programa bajo sanitizers.