wandres.dev
CONSTRUCTOR · Build con Meson

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.

⏱ 14 min

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.

🎯 Al terminar esta lección sabrás
  • Por qué un sistema de build.
  • Un meson.build mí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
Configuraciones paralelas: el flujo profesional

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 + Ninja, no Make

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.

⚔️ Monta un build de verdad
  1. Escribe un meson.build con c_std=c23, warning_level=3 y werror=true.
  2. Compila un proyecto de varios archivos con meson setup + meson compile.
  3. Añade una biblioteca propia con library() y enlázala con link_with.
  4. Crea un segundo directorio de build con -Db_sanitize=address,undefined y corre tu programa bajo sanitizers.