OCI Images

The build and test templates use layered OCI/Docker images to provide the base environment. Currently, the project includes images based on Debian, which are suitable for building and testing across multiple architectures due to Debian’s extensive multi-architecture support.

Tip

You can use this template repository solely for building OCI images, independent of the provided build and test system templates.

Note

We aim to use a consistent Debian version across all architectures to ensure compatibility and reduce complexity. However, for some architectures, different Debian versions may be required due to varying support (e.g., older versions for EOL architectures or newer/unstable versions for newer and unofficial architectures).

Containerfile Structure

Image Layering

Templates are designed to allow layering of multiple Containerfiles. This modular approach enables customization, where each layer adds specific tools or configurations for different toolchains, with optional platform-specific adjustments.

To support image layering, the following image build arguments are used:

  • FROM_IMAGE_NAME: Name of the base image for the build.

  • FROM_IMAGE_TAG: Tag of the base image for the build.

These are automatically set by the oci template during layered image builds.

Platform Naming

Supported platforms follow this naming convention: OS-TYPE-ARCH.

  • OS: Either linux or windows.

  • TYPE: Type of toolchain used for the build:

    • native: Uses the toolchain from the base image.

    • cross: Uses a cross-toolchain for the target platform.

  • ARCH: Target architecture, e.g., amd64, arm64, riscv64.

This convention follows OCI platform naming, with addition of native and cross used to indicate the type of the build environment, and uses a dash instead of a slash to separate platform type from architecture.

Platform-specific Adjustments

Containerfiles use multi-stage builds for platform-specific adjustments. The base OCI target provides a common foundation, which each platform can extend with its own tools and configurations.

For example, Containerfile.base installs essential tools for all platforms and adds Wine only for Windows targets. Here is a snippet showing customization for different platforms:

ARG FROM_IMAGE_NAME
ARG FROM_IMAGE_TAG
FROM ${FROM_IMAGE_NAME}:${FROM_IMAGE_TAG} AS base

# Common for all targets.
RUN ${APT_UPDATE} \
    && ${APT_INSTALL} package-used-by-all-platforms \
    && ${APT_CLEANUP}

# Targets without adjustments.
FROM base AS linux-native-386
FROM base AS linux-native-amd64
...

# Target with adjustment.
FROM base AS windows-cross-amd64
RUN ${APT_UPDATE} \
    && ${APT_INSTALL} windows-specific-dependency \
    && ${APT_CLEANUP}

Available Layers

Base

The base image, defined in Containerfile.base, serves as the foundation for all other images. It includes essential tools for CI:

  • build-essential: Meta-package with tools for building software (GCC, Make, etc.).

  • pkg-config: Manages compile and link flags for libraries, often needed but not included in build-essential.

  • wine and mingw toolchain for Windows targets: Enables running and testing Windows applications on Linux.

Additionally, the base image defines environment variables for use in subsequent layers:

  • APT_UPDATE: Updates package lists.

  • APT_INSTALL: Installs packages with sane defaults.

  • APT_CLEANUP: Cleans up APT cache to reduce image size.

LLVM

Containerfile.llvm extends the base image with the LLVM toolchain. It includes Clang, LLVM tools (e.g., llvm-ar, llvm-strip), lld, and libomp if supported. LLVM version is set to the latest available in Debian repositories.

For Windows targets, it also installs a recent version of the LLVM-MinGW toolchain.

Meson

Containerfile.meson builds upon the base image (either Base or Base with LLVM layer) and adds support for the Meson build system. It installs Meson, Ninja, and Gcovr.

Meson and Gcovr are Python packages with outdated versions in Debian repositories, so they are installed via pipx for consistency for all layers.

Pre-built Images

This repository builds and pushes pre-built OCI images to the GitLab Container Registry.

Available images:

  • buildah: Base image with Buildah and QEMU, used by the oci template for multi-arch builds.

  • debian/debootstrap: Used for building Debian images via debootstrap if the upstream image is unavailable for a given platform.

  • debian/debian: Upstream Debian image (slim variant).

  • debian/base: Based on debian/debian with the Base layer.

  • debian/llvm: Based on debian/base with the LLVM layer.

  • debian/llvm-meson: Based on debian/llvm with the Meson layer.

  • debian/example: Composed of Base, LLVM, and Meson layers in a single build job for selected architectures, demonstrating oci template usage.

Each image tag consists of a branch indicator and platform. For the default branch, the indicator is latest. For other branches, it is a sanitized branch name. For example, debian/llvm-meson:latest-linux-native-amd64 is the default branch image for the linux-native-amd64 platform.

Debian Images

Current platform support for Debian images:

Supported Debian Platforms and Toolchain Versions

Platform

Debian

GNU

LLVM

Meson

Gcovr

linux-cross-mips

Trixie (13)

14

19

1.8

7.2

linux-native-386

Trixie (13)

14

19

1.8

7.2

linux-native-amd64

Trixie (13)

14

19

1.8

7.2

linux-native-arm-v5

Trixie (13)

14

19

1.8

7.2

linux-native-arm-v7

Trixie (13)

14

19

1.8

7.2

linux-native-arm64-v8

Trixie (13)

14

19

1.8

7.2

linux-native-mips64le

Bookworm (12)

12

19

1.8

7.2

linux-native-mipsel

Bookworm (12)

14

19

1.8

7.2

linux-native-ppc

Sid (14)

latest (15)

19

1.8

7.2

linux-native-ppc64

Sid (14)

latest (15)

19

1.8

7.2

linux-native-ppc64le

Trixie (13)

14

19

1.8

7.2

linux-native-riscv64

Trixie (13)

14

19

1.8

7.2

windows-cross-686

Trixie (13)

14

20250709

1.8

7.2

windows-cross-amd64

Trixie (13)

14

20250709

1.8

7.2

windows-cross-arm64-v8

Trixie (13)

N/A

20250709

1.8

7.2

Note

linux-native-mipsel, linux-native-ppc, and linux-native-ppc64 are built from Debian Ports as they have no official OCI image builds.

Note

Windows Cross targets use MinGW GNU toolchain from official Debian repositories, and for LLVM pre-built binaries from LLVM MinGW.

OCI Image Build Template

The oci.yml template provides a workflow for building layered OCI container images. It uses Buildah for multi-arch images, leveraging QEMU for cross-architecture builds.

Inputs

The template accepts the following inputs:

Layering

  • from_image_name: Base OCI image name (e.g., one of the Pre-built Images images).

  • from_image_tag_base: Base OCI image tag, without the target platform suffix. Default: latest.

  • oci_context: The context for the OCI build. The default “.” means the top-level repository directory.

  • containerfiles: Path to a Containerfile or multiple Containerfiles for stacking, separated by space (e.g., Containerfile.base Containerfile.llvm) in the oci_context directory. Default: Containerfile.

Image Configuration

  • image_registry: Registry for the built image. Default: $OCI_REGISTRY_IMAGE.

  • image_name: Image name which will be pushed to the image_registry. Default: $CI_PROJECT_NAME.

  • image_tag_base: Default image tag, without the target suffix. Default: $OCI_TAG.

Target Configuration

  • image_target_tag_matrix: List of targets to build, as an array for the job matrix.

    Default:

    - TARGET:
      - linux-cross-mips
      - linux-native-386
      - linux-native-amd64
      - windows-cross-686
      - windows-cross-amd64
      - linux-native-mips64le
      - linux-native-mipsel
      - linux-native-ppc
      - linux-native-ppc64
      - linux-native-ppc64le
      - linux-native-riscv64
      - linux-native-arm-v5
      - linux-native-arm-v7
      - linux-native-arm64-v8
      - windows-cross-arm64-v8
      RUNNER_TAG: ""
    

    You can adjust this to include specific targets and set the CI runner tag for each group. For example, Freedesktop.org projects might use:

    # Use fleeting runners if possible.
    - TARGET:
      - linux-cross-mips
      - linux-native-386
      - linux-native-amd64
      - windows-cross-686
      - windows-cross-amd64
      RUNNER_TAG: ""
    
    # Use QEMU-capable runners if no native runners are available.
    - TARGET:
      - linux-native-mips64le
      - linux-native-mipsel
      - linux-native-ppc
      - linux-native-ppc64
      - linux-native-ppc64le
      - linux-native-riscv64
      RUNNER_TAG: "kvm"
    
    # Use native aarch64 runners for ARM targets.
    - TARGET:
      - linux-native-arm-v5
      - linux-native-arm-v7
      - linux-native-arm64-v8
      - windows-cross-arm64-v8
      RUNNER_TAG: "aarch64"
    
  • image_target_env_dir: Base path for target environments. Each target should have a file named ${TARGET}.env. Default: .gitlab-ci.d/oci/target-env.

    This allows you to define target-specific environment variables, passed as build arguments. Not all targets require a file.

  • image_target_platform_map: Maps target platforms to their OCI platform string for multi-arch builds. Default:

    linux-cross-mips linux/amd64
    linux-native-386 linux/386
    linux-native-amd64 linux/amd64
    linux-native-arm-v5 linux/arm/v5
    linux-native-arm-v7 linux/arm/v7
    linux-native-arm64-v8 linux/arm64/v8
    linux-native-mips64le linux/mips64le
    linux-native-mipsel linux/mipsel
    linux-native-ppc linux/ppc
    linux-native-ppc64 linux/ppc64
    linux-native-ppc64le linux/ppc64le
    linux-native-riscv64 linux/riscv64
    windows-cross-686 linux/amd64
    windows-cross-amd64 linux/amd64
    windows-cross-arm64-v8 linux/arm64/v8
    

    Usually, you do not need to change this. To add a new target, add it here in the format <target> <platform>, where <target> matches image_target_tag_matrix and <platform> is the OCI platform string.

CI Job and Builder

  • buildah_image_name: Buildah image name, used by the GitLab runner to build the image. If the default value is left, it uses instance-specific image from ci-multiplatform mirror. Default: """.

  • buildah_image_tag: Buildah image tag. Default: latest.

  • cache_image_name: Name of the image used for caching layers in the image_registry. Default: cache.

  • extends: Array of jobs to extend this job template. Can include target activation rules, e.g.:

    .ci-multiplatform-base:
      rules:
        - if: "$TARGET =~ $ACTIVE_TARGET_PATTERN"
    

    Default: [.ci-multiplatform-base]. See Top-level Requirements for details.

  • job_name_prefix: Prefix for the job name. Useful for disabling or customizing jobs. Default: "".

  • job_name_suffix: Suffix for the job name. Useful for distinguishing multiple oci template instances. Default: "".

  • needs: Array of jobs that must run before this job. Useful for chained builds. Default: [].

  • retry: Job retry count, helpful for intermittent issues on GitLab.com runners. Default: 2.

  • stage: CI stage name for the job. Default: oci.

Image labels

When the image is built with the OCI template, the following OCI image labels are applied:

Image Label

Value

<prefix>.commit

$CI_COMMIT_SHA

<prefix>.job_id

$CI_JOB_ID

<prefix>.pipeline_id

$CI_PIPELINE_ID

<prefix>.pipeline_url

$CI_PIPELINE_URL

<prefix>.project

$CI_PROJECT_PATH

<prefix> is fdo for jobs run on Freedesktop.org, and gitlab-ci otherwise. This is to use similar labeling convention as ci-templates on FDO.

For the values starting with CI_, see the GitLab environment variables documentation

Example Usage

For basic usage without a full build/test/summarize flow, see OCI Build Example. For more advanced usage, using the Meson flow, see Meson Project Example.

This template is used in this repository to build the example image (debian/example), which includes the base, LLVM, and Meson layers. It is included in .gitlab-ci.d/oci/debian/debian.yml as the final include.

You can also create a wrapper template that encapsulates the oci component, allowing you to apply project-specific customizations and simplify reuse. For instance, the .gitlab-ci.d/oci/debian/debian-layer.yml template demonstrates how to instantiate the oci template to build the various debian image layers.

Another example is in the Pixman project, where it builds a customized image based on the Meson pre-built image.