.. _meson-build:
Meson Build Template
====================
The ``meson-build.yml`` template provides a standardized workflow for building
projects using the `Meson build system `_ across
multiple platforms and toolchains in a GitLab CI environment.
Overview
--------
This template enables you to:
- Build your project with Meson for various target platforms and architectures
using the multiplatform :ref:`oci-images`.
- Support both native and cross-compilation via Meson cross files.
- Generate build artifacts for use in :ref:`meson-test`.
- Optionally enable coverage reporting with `Gcovr `_ for
supported environments, with an aggregate summary provided by
:ref:`gcovr-summary`.
Pre-built images such as ``llvm-meson`` from this repository are suitable for
most Meson-based builds (see :ref:`oci-pre-built`). These images include all
necessary tools for Meson, LLVM, and GNU toolchain builds. If your project
needs additional dependencies, you can extend these images by adding custom
layers or modifications in :ref:`oci-build`.
Usage in CI
-----------
Typically, this template is included in CI pipelines (see
:ref:`meson-build-examples`) to define jobs for each supported platform. Each
job uses the template to set up the build environment, configure Meson, and
compile the project. Coverage can be enabled for native builds.
.. _ci-matrix-limitations-meson-build:
Parallel matrix limitations
^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. note::
Currently, full CI parallel matrix support is limited due to the following
GitLab CI issues: `#396845
`_, `#423553
`_, `#255311
`_. At present, the
build matrix is only used to build for different toolchains. Only GNU and
LLVM toolchains are supported at this point.
Inputs
------
The template accepts the following inputs:
Target
^^^^^^
- ``target``: Build target in the form ``OS-TYPE-ARCH`` (e.g.,
``linux-native-amd64``). This is similar to an OCI platform string but uses a
hyphen instead of a slash, and includes a ``TYPE`` (either ``native`` or
``cross``). See :ref:`platform-naming` for details.
- ``toolchain``: Array of toolchains to test. Each toolchain should have a
corresponding Meson cross file. Used to create a job matrix. Default: ``[gnu,
llvm]``.
- ``qemu_cpu``: ``QEMU_CPU`` environment variable used by the OCI runner (which
uses QEMU). Not used for targets running natively on the runners. Default:
``""``.
Set this to a specific value if needed to properly discover a platform during
the build.
Meson
^^^^^
- ``meson_source_directory``: Directory containing the Meson project. Default:
``".""``.
- ``meson_cross_directory``: Directory containing Meson cross files. Cross
files should follow the format ``${TARGET}-${TOOLCHAIN}.meson``. If the
cross-file is not found in the directory, it uses the default from
``/opt/meson-cross`` from the OCI image. See :ref:`meson-cross-files`.
Default: ``.gitlab-ci.d/meson-cross``.
- ``meson_c_args``: Extra ``CARGS`` (C compiler arguments) to pass to Meson
builds. Default: ``""``.
- ``meson_setup_args``: Extra arguments passed to ``meson setup``. Default:
``""``.
- ``meson_compile_args``: Extra arguments passed to ``meson compile``. Default:
``""``.
- ``enable_gnu_coverage``: Enable coverage build flags. It can be later used to
collect a coverage report for all the jobs (with :ref:`gcovr-summary`). It
should be enabled only for native build environments as they have all the
optional dependencies, and are the most reliable and uniform, which is
required by Gcovr to properly parse the coverage reports. Disable for cross
environments. Default: ``true``.
CI Job
^^^^^^
- ``allow_failure``: Set the ``allow_failure`` flag for jobs expected to fail.
Set ``retry`` input to 0 to prevent unnecessary retries. Default: ``false``.
- ``artifact_expiry_in``: Set how long GitLab keeps the artifacts. Build
artifacts are not strictly needed afterwards besides the test job, so it can
be set to short period of time to decrease the usage of artifact storage.
Default: ``1 day``.
- ``extends``: Array of jobs to extend this job template. Must include an OCI
image template (see :ref:`top-level-reqs`) and can include target activation
pattern. Default: ``[.ci-multiplatform-base]``.
- ``job_name_prefix``: Prefix for the job name. Useful for disabling or
customizing jobs. Default: ``""``.
- ``job_name_suffix``: Suffix for the job name. Can be used to prevent job
duplication for jobs for the same target. Default: ``""``.
- ``oci_job``: OCI image build job name. Can remain unchanged if no image is
built in the pipeline. Default: ``oci``.
- ``runner_tag``: GitLab runner tag for this job. Default: ``""``.
- ``stage``: CI stage name for the job. Default: ``build``.
.. _meson-cross-files:
Meson Cross Files
-----------------
Meson cross files are configuration files used by Meson to enable
cross-compilation, specify custom toolchains for native builds, or set project
options. They describe the properties of the target platform, compilers, and
tools, allowing Meson to generate correct build rules for different
environments.
This template requires cross files even for native builds, making the template
more uniform and predictable, but if no modifications are required, the
template uses the default cross-files. In this codebase, Meson cross files are
named ``${TARGET}-${TOOLCHAIN}.meson`` (e.g., ``linux-native-amd64-gnu.meson``)
and stored in the directory specified by ``meson_cross_directory`` input
(default: ``.gitlab-ci.d/meson-cross``). These files are referenced during CI
builds to select the appropriate toolchain and platform configuration.
The default cross-files are located in the Meson OCI image in
``/opt/meson-cross`` directory, and in this repo under
:ci_project_url:`oci/debian/meson-cross <-/blob/main/oci/debian/meson-cross>`.
You can use them as a base for customization.
Besides use in CI, using cross files in development provides a standard target
description, allowing you to specify project options and ``CFLAGS``. You can
use the cross file during setup, for example:
.. code-block:: console
$ meson setup build \
--cross-file .gitlab-ci.d/meson-cross/linux-native-amd64-gnu.meson
You can also create a single ``native-gnu.meson``/``native-llvm.meson`` and
create symbolic links for all targets using the native toolchain, as done in
the Pixman project in :pixman_url:`.gitlab-ci.d/meson-cross
<-/tree/ci-external/.gitlab-ci.d/meson-cross>`. The following examples are from
Pixman.
Refer to the Meson documentation for more details on cross file syntax:
https://mesonbuild.com/Cross-compilation.html
.. _native-gnu-meson:
Native GNU (Linux)
^^^^^^^^^^^^^^^^^^
.. code-block:: ini
:caption: native-gnu.meson
[binaries]
c = 'gcc'
ar = 'ar'
strip = 'strip'
pkg-config = 'pkg-config'
Uses GCC and standard GNU tools for native builds. No platform section is
needed, as host matches target.
Native LLVM (Linux)
^^^^^^^^^^^^^^^^^^^
.. code-block:: ini
:caption: native-llvm.meson
[binaries]
c = 'clang'
cpp = 'clang++'
ar = 'llvm-ar'
strip = 'llvm-strip'
Uses Clang and LLVM tools for native builds. Similar to
:ref:`native-gnu-meson`, no platform section is needed.
Cross-Compilation GNU (Windows)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: ini
:caption: windows-cross-amd64-gnu.meson
[binaries]
c = 'x86_64-w64-mingw32-gcc'
ar = 'x86_64-w64-mingw32-ar'
strip = 'x86_64-w64-mingw32-strip'
windres = 'x86_64-w64-mingw32-windres'
exe_wrapper = 'wine'
[project options]
openmp = 'disabled'
[host_machine]
system = 'windows'
cpu_family = 'x86_64'
cpu = 'x86_64'
endian = 'little'
Specifies the cross-compiler for Windows AMD64. Uses Wine as the
``exe_wrapper`` to run Windows binaries on Linux. Defines project options and
target platform details. It is recommended to disable ``openmp`` for Windows
targets, as it can intermittently fail for large and concurrent test sets.
Cross-Compilation GNU (Linux)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: ini
:caption: linux-cross-mips-gnu.meson
[binaries]
c = 'mips-linux-gnu-gcc'
ar = 'mips-linux-gnu-ar'
strip = 'mips-linux-gnu-strip'
exe_wrapper = ['qemu-mips', '-L', '/usr/mips-linux-gnu/']
[host_machine]
system = 'linux'
cpu_family = 'mips32'
cpu = 'mips32'
endian = 'big'
Uses the cross-compiler for MIPS32 (big-endian) targets. Explicitly specifies
QEMU as the ``exe_wrapper``.
Here we need to define the ``host_machine`` to indicate the target
specification to Meson.
Cross-Compilation LLVM (Linux)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: ini
:caption: linux-cross-mips-llvm.meson
[binaries]
c = ['clang', '-target', 'mips-linux-gnu', '-fPIC', '-DCI_HAS_ALL_MIPS_CPU_FEATURES']
ar = 'llvm-ar'
strip = 'llvm-strip'
exe_wrapper = ['qemu-mips', '-L', '/usr/mips-linux-gnu/']
[built-in options]
c_link_args = ['-target', 'mips-linux-gnu', '-fuse-ld=lld']
[host_machine]
system = 'linux'
cpu_family = 'mips32'
cpu = 'mips32'
endian = 'big'
Similar to the above, but for LLVM. Clang uses ``-target`` argument to specify
the cross-compilation target.
Explicit QEMU execution wrapper
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
To use QEMU with specific flags (e.g., CPU specification) as the
``exe_wrapper``, set it as follows (under ``[binaries]``):
- ``exe_wrapper = ['qemu-arm', '-cpu', 'arm1136']`` uses ``qemu-arm`` and sets
the CPU used by Meson.
- ``exe_wrapper = ['qemu-mips', '-L', '/usr/mips-linux-gnu/']`` uses an
explicit ELF interpreter prefix.
Managing project options
^^^^^^^^^^^^^^^^^^^^^^^^
You can explicitly set some Meson project options by specifying them as
follows:
.. code-block:: ini
[project options]
mips-dspr2 = 'disabled'
In this example, ``mips-dspr2`` is disabled to build with another MIPS SIMD
backend.
Adding ``CFLAGS``
^^^^^^^^^^^^^^^^^
Add custom C compiler flags (``CFLAGS``) by modifying the ``c`` binary, e.g.:
.. code-block:: ini
[binaries]
c = ['gcc', '-DCI_HAS_ALL_MIPS_CPU_FEATURES']
Here, ``CI_HAS_ALL_MIPS_CPU_FEATURES`` is added as a compile define.
Job Structure
-------------
The build and test stages (see :ref:`meson-test`) are split to two stages in
the CI pipeline. This allows you to build artifacts once and test them with
multiple configurations, such as different SIMD backends or QEMU flags to
emulate various processor features (e.g., RVV VLEN for RISC-V). This approach
improves efficiency and flexibility, enabling comprehensive testing without
redundant builds.
Each job created by the template:
- Sets up the build directory and enables coverage if requested.
- Runs ``meson setup`` with the appropriate cross file and arguments.
- Compiles the project with ``meson compile``.
- Stores build artifacts for the testing stage in ``build-${TOOLCHAIN}`` (e.g.,
``build-gnu`` for the GNU toolchain).
.. _meson-build-examples:
Examples
--------
A typical job definition in ``build.yml``:
.. code-block:: yaml
spec:
inputs:
ci_path:
description:
Path to the ci-multiplatform meson-build component with branch name.
type: string
default: gitlab.com/riseproject/ci/ci-multiplatform/meson-build@main
runner_tag_qemu:
description: Regular x86 runner with QEMU support.
type: string
default: "saas-linux-medium-amd64"
---
include:
# Native x86_64 target.
- component: $[[ inputs.ci_path ]]
inputs:
target: linux-native-amd64
runner_tag: $[[ inputs.runner_tag_qemu ]]
# QEMU target with specific `QEMU_CPU`.
- component: $[[ inputs.ci_path ]]
inputs:
target: linux-native-mips64le
runner_tag: $[[ inputs.runner_tag_qemu ]]
qemu_cpu: Loongson-3A4000
# Target with only GNU toolchain and no coverage support.
- component: $[[ inputs.ci_path ]]
inputs:
target: linux-native-mipsel
runner_tag: $[[ inputs.runner_tag_qemu ]]
toolchain: [gnu]
qemu_cpu: 74Kf
enable_gnu_coverage: false
Adding ``ci_path`` and ``runner_tag_qemu`` as inputs makes the declaration
shorter and easier to update if any inputs change.
For a full example, see :ref:`examples-meson`.
Another example is in the Pixman project in
:pixman_url:`.gitlab-ci.d/02-build.yml
<-/blob/ci-external/.gitlab-ci.d/02-build.yml>` file.