Última actualización:2026-10-12
Construir proyectos C++ con Meson¶
Últimamente, al usar algunos proyectos de código abierto, he comprobado que todos adoptan el sistema de compilación meson+ninja y abandonan el enfoque de CMake y Makefile; este artículo introducirá Meson, desde su instalación hasta la escritura completa de un proyecto meson.
A continuación, entremos en materia.
1. Instalación de Meson¶
Meson está disponible en PyPi, por lo que puede instalarse con pip3 install meson. Asegúrate de usar el comando pip correcto en cada sistema y de emplear siempre la versión de pip de Python 3.
Si lo prefieres, también puedes instalarlo localmente con el comando estándar de Python:
Si vas a construir con Ninja, puedes descargar Ninja directamente desde su página de releases de GitHub o a través de PyPi:
Para más información sobre la instalación de Meson build, consulta el sitio web oficial de Meson que se indica abajo.
2. Meson Vs Cmake¶
Si todo el mundo usa CMake, ¿por qué usar Meson? ¿Cuáles son las ventajas y desventajas de cada uno?
En cuanto al rendimiento, Meson suele ser conocido por su velocidad de compilación. El diseño de Meson busca optimizar la velocidad de construcción y destaca especialmente en las compilaciones incrementales. Meson usa Ninja como backend por defecto, y Ninja también es célebre por ser rápido y eficiente.
En comparación, la velocidad de compilación de CMake puede verse afectada por el tamaño del proyecto, sobre todo en proyectos grandes. CMake emplea varios generadores (como Makefile), y el rendimiento puede variar de un generador a otro.
Por supuesto, también se puede usar CMake + Ninja para acelerar la compilación.
Desde el punto de vista de los proyectos de código abierto, Meson tiene muchísimos casos de uso, por ejemplo: PostgreSQL, QEMU, GNOME Software, GTK+, etcétera
2.1 Ventajas y desventajas de Meson¶
1.Ventajas
- Basado en Python, sencillo de usar
- Admite compilación cruzada
- Todos los objetos son fuertemente tipados: como los objetos son entidades como 'dependency' o 'include directory', es difícil cometer errores de sustitución de cadenas.
- Resulta muy cómodo referenciar bibliotecas de terceros
- Muy, muy rápido, especialmente en las compilaciones incrementales.
- La documentación es n veces mejor que la de cmake.
2.Desventajas
- Puede no ser tan maduro como CMake
- Tiene las dependencias de Python3 + Ninja
- Generadores de proyectos: el soporte IDE de Meson no llega al de CMake
- soporte en vscode
- https://github.com/mesonbuild/vscode-meson
- Módulos disponibles limitados
- Hay que enviar uno mismo los proyectos que no son meson a wrapdb
- https://mesonbuild.com/Wrapdb-projects.html
2.2 Ventajas y desventajas de CMake¶
1.Ventajas
- Soporte IDE amigable y colaboración en equipo bastante buena
- Maduro, es prácticamente el estándar de los proyectos C++
2.Inconvenientes
- La compilación cruzada es difícil
- La velocidad de compilación es relativamente lenta
3. Meson WrapDB¶
Como googletest no es un proyecto meson, ¿cómo hacer que meson dependa de él?
Del mismo modo, grpc y abseil-cpp se usan de forma parecida.
Aquí hay que introducir primero WrapDB: Meson WrapDB es un componente del sistema de compilación Meson que se encarga de gestionar y proporcionar los archivos de descripción de compilación de proyectos de terceros, habitualmente llamados archivos "wrap". Estos archivos wrap contienen la información necesaria para configurar y compilar proyectos de terceros, de modo que puedan integrarse fácilmente en otros proyectos que usan el sistema de compilación Meson.
Puedes consultar las bibliotecas de terceros con el comando search o en el sitio web que aparece abajo.
https://mesonbuild.com/Wrapdb-projects.html#meson-wrapdb-packages
Tomemos como ejemplo el uso de gtest:
- Buscar gtest
Si este comando devuelve el nombre del proyecto empaquetado, ya se puede pasar al siguiente paso:
- Crear el directorio subprojects en tu propio proyecto e instalar gtest con install
En este momento, todas las bibliotecas de terceros de las que depende tu proyecto ya están instaladas en el directorio subprojects.
Ahora se genera gtest.wrap, cuyo contenido incluye lo siguiente.
Nota: este archivo se genera tras el install anterior; se recomienda no modificarlo.
[wrap-file]
directory = googletest-1.14.0
source_url = https://github.com/google/googletest/archive/refs/tags/v1.14.0.tar.gz
source_filename = gtest-1.14.0.tar.gz
source_hash = 8ad598c73ad796e0d8280b082cebd82a630d73e73cd3c70057938a6501bba5d7
patch_filename = gtest_1.14.0-1_patch.zip
patch_url = https://wrapdb.mesonbuild.com/v2/gtest_1.14.0-1/get_patch
patch_hash = 2e693c7d3f9370a7aa6dac802bada0874d3198ad4cfdf75647b818f691182b50
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/gtest_1.14.0-1/gtest-1.14.0.tar.gz
wrapdb_version = 1.14.0-1
[provide]
gtest = gtest_dep
gtest_main = gtest_main_dep
gmock = gmock_dep
gmock_main = gmock_main_dep
4. ¿Cómo escribir un proyecto meson?¶
Llegamos a la parte práctica: ¿cómo se escribe un proyecto meson?
A continuación, un pequeño proyecto que usa gtest para pruebas unitarias, tomando como ejemplo la prueba de la división a/b.
4.1 Escribir el código¶
Coloca el .h y el .cc en el directorio src:
A continuación, crea el directorio test al mismo nivel.
4.2 Gestión del proyecto con meson¶
Añade el archivo meson.build en la raíz del proyecto, con el siguiente contenido:
project('gtest_div', 'cpp')
gtest_proj = subproject('gtest')
gtest_dep = gtest_proj.get_variable('gtest_main_dep')
div_src = files('src/division.cc')
tests_src = files('test/division_test.cc')
e = executable(
'division_test',
tests_src + div_src,
dependencies : [ gtest_dep],
override_options : ['cpp_std=c++14']
)
# https://mesonbuild.com/Unit-tests.html#testing-tool
test('this is a division test', e)
Se puede ver que este contenido coincide básicamente con la sintaxis de python; quien conozca python leerá este código con mucha facilidad. Aquí destacamos las partes más importantes del mismo.
- Introducir bibliotecas de terceros
Por ejemplo: si el proyecto de la biblioteca de terceros que introduces se llama gtest, así:
Entonces puedes obtener ese project mediante subproject y, con gtest_proj.get_variable, conseguir la información de dependencia de gtest; por ejemplo, en googletest se declara así:
gtest_main_dep = declare_dependency(
include_directories : gtest_incdir,
sources : [gtest_libsources, gtest_mainsources],
dependencies : dependency('threads')
)
- executable
executable es muy similar al add_executable de cmake: genera el ejecutable division_test.
- test
Sintaxis de las pruebas unitarias:
Se puede usar meson test o ninja test; al terminar la ejecución se genera un registro de pruebas, ubicado en:
4.3 Construir y ejecutar el proyecto Meson¶
Con lo anterior, un proyecto meson está listo. A continuación, construimos y ejecutamos este proyecto.
4.3.1 Configurar el directorio de compilación¶
Esto es similar al mkdir build && cmake .. de cmake.
La ejecución es la siguiente:
➜ gtest_div meson setup build
The Meson build system
Version: 1.2.3
Source dir: /Users/light/work/practice/gtest_div
Build dir: /Users/light/work/practice/gtest_div/build
Build type: native build
Project name: gtest_div
Project version: undefined
C++ compiler for the host machine: c++ (clang 12.0.5 "Apple clang version 12.0.5 (clang-1205.0.22.11)")
C++ linker for the host machine: c++ ld64 650.9
Host machine cpu family: x86_64
Host machine cpu: x86_64
Downloading gtest source from https://github.com/google/googletest/archive/refs/tags/v1.14.0.tar.gz
Download size: 867764
Downloading: ..........
Downloading gtest patch from https://wrapdb.mesonbuild.com/v2/gtest_1.14.0-1/get_patch
Download size: 2440
Downloading: ..........
Executing subproject gtest
gtest| Project name: gtest
gtest| Project version: 1.14.0
gtest| C++ compiler for the host machine: c++ (clang 12.0.5 "Apple clang version 12.0.5 (clang-1205.0.22.11)")
gtest| C++ linker for the host machine: c++ ld64 650.9
gtest| Run-time dependency threads found: YES
gtest| Dependency threads found: YES unknown (cached)
gtest| Dependency threads found: YES unknown (cached)
gtest| Dependency threads found: YES unknown (cached)
gtest| Build targets in project: 0
gtest| Subproject gtest finished.
Build targets in project: 1
gtest_div undefined
Subprojects
gtest: YES
Found ninja-1.11.1 at /usr/local/bin/ninja
En este momento podemos ver en subprojects el proyecto gtest en caché.
4.3.2 Compilar¶
Podemos usar los dos comandos siguientes; el primero:
Registro de ejecución:
➜ gtest_div meson compile -C build/
INFO: autodetecting backend as ninja
INFO: calculating backend command to run: /usr/local/bin/ninja -C /Users/light/work/practice/gtest_div/build
ninja: Entering directory `/Users/light/work/practice/gtest_div/build'
[5/5] Linking target division_test
El segundo:
En esencia, estos dos comandos son lo mismo: ambos compilan con ninja. Por supuesto, también puedes omitir el directorio con -C, y en ese caso tendrás que hacer cd build && ninja o cd build && meson compile.
4.3.3 Ejecutar y probar¶
Ahora se genera el ejecutable division_test, cuya ejecución es la siguiente:
➜ gtest_div ./build/division_test
Running main() from ../subprojects/googletest-1.14.0/googletest/src/gtest_main.cc
[==========] Running 2 tests from 1 test suite.
[----------] Global test environment set-up.
[----------] 2 tests from DivisionTest
[ RUN ] DivisionTest.Divide
[ OK ] DivisionTest.Divide (0 ms)
[ RUN ] DivisionTest.DivideByZero
[ OK ] DivisionTest.DivideByZero (0 ms)
[----------] 2 tests from DivisionTest (0 ms total)
[----------] Global test environment tear-down
[==========] 2 tests from 1 test suite ran. (0 ms total)
[ PASSED ] 2 tests.
Como en meson.build añadimos la prueba unitaria test, podemos usar
o:
Si se especifica el directorio:
Registro de ejecución:
➜ gtest_div meson test -C build
ninja: Entering directory `/Users/light/work/practice/gtest_div/build'
ninja: no work to do.
1/1 this is a division test OK 0.01s
Ok: 1
Expected Fail: 0
Fail: 0
Unexpected Pass: 0
Skipped: 0
Timeout: 0
Full log written to /Users/light/work/practice/gtest_div/build/meson-logs/testlog.txt
Temas relacionados¶
- Construir proyectos C++ con Bazel | C++那些事
- Depuración conjunta de Bazel y LLDB | C++那些事
- CMake: introducción y práctica | C++那些事
- Introducción a Conan, gestor de paquetes de C++ | C++那些事
- C++ Insights: observación en tiempo de compilación | C++那些事
- C++ Jupyter Notebook interactivo | C++那些事
- Convertir string a int en C++ | C++那些事
- dbg-macro, macro de depuración para C++ | C++那些事
- Explicación detallada de las opciones de compilación de GCC | C++那些事
- Depurar programas C++ con GDB | C++那些事