Skip to content

The FSL build system

This page contains details on the FSL build system, and instructions on how to accomplish certain tasks which need to be performed periodically.

Implementation

All of the logic which drives the FSL build system is implemented in Python, in the following GitLab repositories: - fsl-ci-rules contains core logic, and the rules for building FSL projects - manifest-rules contains rules for building FSL releases

Installing locally

While most FSL build procedures are executed via GitLab CI / CD, several procedures described on this page must be executed manually, so you may need to have a local installation of the build system. This is easy to do:

  1. Create and activate Python or conda environment using your preferred method (virtualenv, conda, uv, etc).
  2. Install the CI and manifest rules:
    pip install git+https://git.fmrib.ox.ac.uk/fsl/conda/fsl-ci-rules.git
    pip install git+https://git.fmrib.ox.ac.uk/fsl/conda/manifest-rules.git
    

The build system provides a number of commands intended to be executed manually - some of the more useful commands are:

  • configure_repositories: Activate the FSL build system on new project and recipe repositories.
  • set_gitlab_variables: Set/update/delete CI / CD variables on a repository.
  • build_local_conda_package: Build a conda package on the local machine for a specific recipe.
  • trigger_pipeline: Start a CI / CD pipeline on a repository.
  • package_status: Print information about all published FSL conda packages.
  • apply_patch: Apply a patch to one or more recipe repositories.

Several sections in this page will refer to these commands, and assume that you have installed the build system locally.

Note that none of these commands are essential - they perform tasks which you can perform manually via the GitLab web UI. However, these commands do allow you to perform mundane operations automatically on many repositories at once.

Making changes to the build system

Updating the build system is performed using a standard merge request workflow. Create a branch, make your changes, then open a merge request via the GitLab web interface.

You must update the version number (in fsl_ci/__init__.py or manifest_rules/__init__.py) every time you make changes. This allows you to keep track of which version of the build system was used to run a particular CI job, which is essential when developing new features or debugging issues in the build system code.

GitLab API token

The build system interacts with GitLab via the GitLab REST API. This requires a GitLab API access token which has full (read+write) access to all projects within the fsl/ and fsl/conda/ namespaces. This token is stored on all GitLab repositories as as a CI / CD varible called FSL_CI_API_TOKEN.

When working locally, you may wish to store the token as an environment variable, as several of the build system commands require you to pass the token as a command-line argument.

Renewing the CI / CD API token

Whenever your Gitlab API token expires, you will need to create a new one and update it on all of the FSL Gitlab repositories. The following is one method for accomplishing this task:

  1. Create a new Gitlab API token via the Gitlab web interface.

  2. Compile a list of all internally hosted recipe repositories. You can do this with the following steps:

    a. Take a copy of the package list in the FSL release manifest.

    b. Remove any externally hosted/published packages (e.g. fsleyes, openblas, libboost etc).

    c. Prefix the package names with fsl/conda/, corresponding to their full repository name in Gitlab.

    d. Add the "meta" projects fsl/conda/fsl-ci-rules, fsl/conda/manifest-rules, and fsl/conda/manifest.

    e. Save this list to a file, e.g. recipes.txt.

  3. Get the correspoding source code repository for each recipe repository. You can do this with the following code (after installing the fsl-ci-rules Python package). This will create a file called repos.txt:

import os
from fsl_ci        import tempdir
from fsl_ci.conda  import get_project_repository_and_revision
from fsl_ci.gitlab import download_file, gen_project_path

# your new token
token  = os.environ['FSL_CI_API_TOKEN']
server = 'https://git.fmrib.ox.ac.uk'

recipes = open('recipes.txt', 'rt').readlines()
recipes = [r.strip() for r in recipes]
recipes = [r for r in recipes if r != '']
repos   = []

for recipe in recipes:
    with tempdir():
        try:
            meta = download_file(recipe, 'meta.yaml', server, token)
        except Exception as e:
            print(f'Could not download meta.yaml for {recipe} ({e})')
            continue

        with open('meta.yaml', 'wt') as f:
            f.write(meta)

        try:
            repo = get_project_repository_and_revision('meta.yaml',
                                                       ignore_env=True)[0]
        except Exception as e:
            print(f'Could not get source repository for {recipe} ({e})')
            continue

    # ignore external projects
    if 'git.fmrib.ox.ac.uk' in repo:
        repo = gen_project_path(repo)
        repos.append(repo)

with open('repos.txt', 'wt') as f:
    for repo in repos:
        f.write(f'{repo}\n' )
  1. Update the CI access token variable on all of the above project and recipe repositories, e.g.:
import os
from fsl_ci.gitlab import create_or_update_variable

token  = os.environ['FSL_CI_API_TOKEN']
server = 'https://git.fmrib.ox.ac.uk'

targets = open('recipes.txt', 'rt').readlines() + \
          open('repos.txt',   'rt').readlines()
targets = [t.strip() for t in targets]
targets = [t for t in targets if t != '']

for target in targets:
    create_or_update_variable(target, server, token,
                              'FSL_CI_API_TOKEN', token,
                              masked=True)

Package build procedure

The logic used to build FSL conda packages is implemented in the fsl-ci-rules repository. This section describes how FSL packages are built.

When a new package build is triggered (e.g. in response to a new project release, or development build), a GitLab CI / CD job is started on the corresponding recipe repository (a separate job is started for each platform the package is to be built for, e.g. macOS-64, linux-64, etc). This job performs the following steps:

  1. The recipe repository is checked out.

  2. If the build is for a development release, the version in the recipe meta.yaml is replaced with a development version number.

  3. Any global patches that exist are applied to the recipe (see below).

  4. A conda_build_config.yaml file is generated, containing globally pinned packages (see below). This is only done for platform-specific packages (i.e. it is not done for noarch Python packages).

  5. The package is built using a command such as:

    conda build \
      --output-folder=./build \
      --variant-config-files conda_build_config.yaml \
      ./
    

  6. The package is published to one of the FSL conda channels.

There are several CI / CD variables which you can set to influence this process, for example if debugging a build, or making changes to the build system. Some of the more important variables are:

Name Meaning
FSLCONDA_REVISION Git revision (branch name, tag, etc) of the project repository to build
FSL_DEVRELEASE Mark the build as a development release
FSLCONDA_BUILD_EXTRA_ARGS Additional arguments to pass to conda build
FSL_CI_RULES_REVISION Git revision of the fsl/conda/fsl-ci-rules repository to install
FSL_MANIFEST_REVISION Git revision of the fsl/conda/manifest repository to install

See below for a full list of the CI / CD variables that can be set in the FSL build system.

Global patches

The FSL build system implements a patching system, allowing the recipes for all FSL projects to be dynamically adjusted at build time. This allows changes to be made to all FSL conda recipes without having to adjust each recipe individually.

The patch system is implemented in the fsl-ci-rules repository. Just before a recipe is built, all of the patch files located in the fsl_ci/templates/metayaml/ directory are applied to the recipe meta.yaml file; the patch files are applied in alphabetical order.

The patch system is very primitive, and is only able to add entries to the requirements and build sections of a recipe meta.yaml file.

Globally pinned packages

For C++ projects it is important that we build all packages against the same version of some core downstream dependencies, such as zlib and libboost. The FSL build system accomplishes this by generating a conda_build_config.yaml file when a package is built. This file is generated as follows:

  1. The fsl-release.yml file is downloaded from the fsl/conda/manifest repository.

  2. The versions of all packages in the build-packages section of the fsl-release.yml file are extracted.

  3. Those versions are used to populate the template file in fsl_ci/templates/conda_build_config.yaml.

  4. The generated conda_build_config.yaml file is passed to conda build.

Whenever the versions of core dependencies need be updated, a build migration may need to be performed - this is described below.

Platform identifiers

FSL conda packages are built for the following platforms/architectures:

  • noarch: Platform-independent, e.g. Python, TCL, Bash projects
  • linux-64: C/C++ projects compiled for Linux (x86-64)
  • linux-aarch64: C/C++ projects compiled for Linux (arm-64)
  • macos-64: C/C++ projects compiled for macOS (x86-64)
  • macos-M1: C/C++ projects compiled for macOS (Apple Silicon)
  • linux-64-cuda: CUDA projects compiled for Linux (x86-64), with CUDA Toolkit version X.Y.
  • linux-aarch64-cuda: CUDA projects compiled for Linux (arm-64), with CUDA Toolkit version X.Y.

Note: The above platform labels are used as identifiers - they must be used exactly as shown.

The FSLCONDA_BUILD_PLATFORM CI / CD variable is used to determine the platforms for which a particular recipe is built. It must be set on every recipe repository, and must be space-separated string containing all of the platform identifiers for which the recipe should be built.

For CUDA projects, the FSLCONDA_CUDA_VERSION variable specifies which CUDA versions the project should be built against.

For example, the fsl/conda/fsl-avwutils recipe repository is a recipe for the fsl/avwutils project, which is a C++ project. For this recipe, the FSLCONDA_BUILD_PLATFORM variable is set to "linux-64 linux-aarch64 macos-64 macos-M1", and so a package will be built for each of those platforms.

To clarify, the CI conda build jobs are configured so that:

  1. Platform independent recipes will be built as noarch packages.

  2. C/C++ recipes will be built as linux-64, linux-aarch64, macos-64, and macos-M1 packages.

  3. CUDA recipes will be built as linux-64-cuda and linux-aarch64-cuda packages - a separate package is built for each supported CUDA version.

Managing projects/recipes

This section covers a range of procedures for individual FSL projects, which you may need to carry out periodically.

Bootstrapping a new project

Note: The steps below are a suggestion. If you are comfortable working with git repositories, conda environments, and building conda packages by hand, feel free to work in whichever way you see fit.

Let's say we have developed a new FSL project at https://git.fmrib.ox.ac.uk/fsl/my_cool_project. To integrate our new project into the FSL build system, we can follow these steps:

  1. Install the build system locally if you haven't already done so (described above).

  2. If you haven't already done so, create a Gitlab API access token with read+write ("api") access. This can be done via the Gitlab web interface via User settings -> Access Tokens. Set it in your local shell environment like so:

    export FSL_CI_API_TOKEN="<my-token>"
    

  3. Create a conda recipe repository for the new project - the easiest way to do this is to copy the recipe for an existing similar project. For example, if you are creating a recipe for a Python project, you could copy the eddy_qc recipe. Or, if you are creating a recipe for a C++ project, you could copy the avwutils recipe. Your recipe repository must live in the fsl/conda/ GitLab namespace, and be named fsl-<project>, e.g. fsl/conda/fsl-my_cool_project. More details on FSL conda recipes can be found here.

  4. Configure the project and recipe repositories - this will enable integration with the fsl-ci-rules CI configuration on both repositories (the steps that configure_repositories performs are described in detail below):

configure_repositories -t ${FSL_CI_API_TOKEN} \
    fsl/my_cool_project \
    fsl/conda/fsl-my_cool_project
  1. To test that the CI integration is working:
  2. Trigger a pipeline on the master/main branch of the fsl/my_cool_project repository via the trigger_pipeline command, e.g.:

    trigger_pipeline -t ${FSL_CI_API_TOKEN} fsl/my_cool_project
    
    This will run a job on the project repository, which will in turn trigger a pipeline on the recipe repository, building a "development" conda package from the master/main branch of fsl/my_cool_project.

    You can also start a pipeline manually via the Gitlab web interface (CI / CD -> Run Pipeline).

  3. If you're ready to release your new project now, create a tag on the fsl/my_cool_project repository. This will run a job on the project repository which opens a merge request (MR) on the recipe repository, updating the project version number in the recipe meta.yaml file. If you are just testing that things work, you can delete the tag, and close/delete the MR.

  4. Manually edit the recipe at the fsl/conda/fsl-my_cool_project repository (and make changes to the code at fsl/my_cool_project if needed) until your conda package builds successfully.

Project and recipe repository configuration

The configure_repositories command activates the FSL build system on a project and recipe repository by interacting with GitLab through its REST API. It performs the following steps, which can be performed manually via the Gitlab web interface if you prefer.

On both project and recipe repositories you must enable at the following Gitlab CI runners:

  • One runner which is installed on the server that hosts the conda channel directories, tagged with fslconda-channel-host. This runner will be used to run CI jobs that deploy built conda packages to the FSL conda channels.

  • One or more runners with the fsl-ci, linux, and linux-x64 tags. These runners will be used to execute any CI jobs that do not involve deploying conda packages, including building noarch packages, and binary packages for x86-64 Linux.

  • One or more runners with the fsl-ci, linux, and linux-aarch64 tags. These runners will be used to build and test noarch packages, and binary packages for ARM64 linux.

  • One or more runners with the fsl-ci and macOS-64 tags. These runners will be used to build and test binary packages for x86-64 macOS.

  • One or more runners with the fsl-ci and macOS-M1 tags. These runners will be used to build and test binary packages for ARM64 macOS.

See the infrastucture page for more details on the GitLab runners.

Next, on both project and recipe repositories, for a FSL project which does not require any custom CI rules of its own (most FSL projects fall into this category), all that needs to be done is to set the Custom CI configuration path option to refer to this file, by giving it the value:

.gitlab-ci.yml@fsl/conda/fsl-ci-rules

This option can be found under Settings -> CI / CD -> General Pipelines, in the Gitlab web interface for each project.

Finally, you need to set the following variables in the Settings -> CI / CD -> Variables section of the Gitlab web interface:

  • FSL_CI_API_TOKEN: Required on both project and recipe repositories. Gitlab API token which is used by CI jobs for read+write access via the Gitlab REST API.

  • FSLCONDA_RECIPE: Required on the recipe repository. A flag which is used to distinguish project repositories from recipe repsitories. The value is not checked - only whether or not the variable is set.

  • FSLCONDA_RECIPE_URL: Required on the project repository, but only when its accompanying recipe repository is not named according to the fsl/conda/fsl-<project> convention. Contains the full URL to the conda recipe repository.

  • FSLCONDA_BUILD_PLATFORM: Required on the recipe repository - must be set to a space-separated list of platform identifiers, determining the platforms a package should be built for (e.g. noarch linux-64, linux-aarch64 macos-64, macos-M1, linux-64-cuda, and/or linux-aarch64-cuda).

  • FSLCONDA_INTERNAL: Optional. Can be set on the recipe repository. If set, built conda packages are deployed to the internal conda channel, rather than the public channel.

  • FSL_DEVRELEASE: Optional. Can be set on the recipe repository. If set, built conda packages are deployed to the development conda channel, rather than the public channel.

The above instructions should suffice for most FSL projects. However, for a FSL project which already has its own .gitlab-ci.yml configuration file, instead of setting the Custom CI configuration path setting on the project repository:

  1. The .gitlab-ci.yml file of the project should include the .gitlab-ci.yml file of this repository via the following section - this should be at the beginning of the .gitlab-ci.yml:

    include:
     - project: fsl/conda/fsl-ci-rules
       file:    .gitlab-ci.yml
    
  2. fsl-ci-pre fsl-ci-build, fsl-ci-test and fsl-ci-deploy should be added to the CI stages, in that order. For example:

    stages: - build - test - fsl-ci-pre - fsl-ci-build - fsl-ci-test - fsl-ci-deploy

Private/internal projects

To configure a package to be deployed to the internal channel, the following CI / CD variables must be set on the recipe repository:

  • FSLCONDA_INTERNAL: Marks this recipe as an internal package
  • FSLCONDA_INTERNAL_CHANNEL_USERNAME: Username for accessing the internal conda channel
  • FSLCONDA_INTERNAL_CHANNEL_PASSWORD: Password for accessing the internal conda channel

Packages which are deployed to the public FSL conda channel must not depend on packages deployed to the internal channel.

CUDA projects

Note: In principle the build system supports building a FSL package against multiple CUDA versions. However, in practice, we only build against a single CUDA version.

Most FSL CUDA projects usually provide both GPU-enabled and CPU-only executables. For example, the fsl/fdt provides a range of CPU-only executables, including dtifit and vecreg, in addition to providing GPU-enabled executables such as xfibres_gpu.

To accommodate this convention, multiple conda recipes are used for these "hybrid" projects. For example, the fsl/fdt project is built from two separate recipes:

  • fsl/conda/fsl-fdt, which builds the CPU-only executables - these recipes are built as linux-64, linux-aarch64, macos-64, and macos-M1 packages.

  • fsl/conda/fsl-fdt-cuda, which builds the CUDA/GPU-enabled executables - these recipes are built as linux-64-cuda and linux-aarch64-cuda packages.

CUDA packages may be compiled against a range of CUDA Toolkit versions; the resulting conda package will be labelled with the CUDA version it was compiled against, as outlined above. The FSLCONDA_CUDA_VERSION variable can be used to control which CUDA versions a package is built for - this variable must be set on the project recipe repository, and must contain a space-separated list of all CUDA versions that should be built, e.g. "9.2 10.0 11.3".

The standard convention is for CUDA projects to be compiled in such a way as to ensure maximum possible compiatibilty with different GPU hardware:

  • The CUDA Toolkit libraries are statically linked into the executables.
  • CUDA code is built against the widest possible range of GPU architectures, with forward-compatibility for newer architectures.

So a CUDA package compiled against, for example, CUDA 9.2, should work with any GPU driver/hardware which is compatible with CUDA 9.2 or newer.

These are conventions only - it is the responsibility of the project Makefile (e.g. fsl/eddy) and package recipe build.sh scripts (e.g. fsl/conda/fsl-eddy-cuda) to adhere to them.

Forcing use of a specific GitLab runner

The GitLab runners used to build FSL conda packages are each tagged with their respective platform:

  • macOS-64 - Apple Intel
  • macOS-M1 - Apple Silicon
  • linux - Platform-agnostic
  • linux-x64 - Intel Linux (including x64 CUDA packages)
  • linux-aarch64 - AARCH64 (ARM64) Linux (including aarch64 CUDA packages)

These tags will cause CI jobs to be executed on machines with specific hardware resources (CPUs, RAM, etc).

If a particular project requires more resources (e.g. building it requires more RAM), or needs to be built on a particular machine, it is possible to override the gitlab runners that are used with the following CI / CD variables:

  • FSL_CI_RUNNER_PLATFORM_MACOS_64 - defaults to macOS-64
  • FSL_CI_RUNNER_PLATFORM_MACOS_M1 - defaults to macOS-M1
  • FSL_CI_RUNNER_PLATFORM_LINUX - defaults to linux
  • FSL_CI_RUNNER_PLATFORM_LINUX_X64 - defaults to linux-x64
  • FSL_CI_RUNNER_PLATFORM_LINUX_AARCH64 - defaults to linux-aarch64

Of course you must ensure that a GitLab runner with the appropriate platform tag is configured.

Disabling the build system on project repositories

If you are maintaining a project repository in which the fsl-ci-rules have been integrated, and would like to disable automatic package building and recipe updates, you can disable them by setting a CI variable called FSL_CI_SKIP_ALL, and giving it a non-empty value. This may be desirable if you have your own personal fork of a FSL project repository, and do not wish to run the standard FSL CI rules. See the Summary of environment variables section below for more fine-grained customisation options.

Build migrations

FSL is built on top of several "core" dependencies, such as Python, zlib and boost. We periodically need to update the versions of these core dependencies, and when this happens we may need to rebuild many FSL packages against the new versions.

Furthermore, whenever changes are made to low-level FSL packages (newimage, miscmaths etc), the other FSL packages which depende on them may need to be re-built.

This section describes prodedures which allow these "build migrations" to be performed.

Updating core dependencies

Every now and then, all of the C++ FSL packages must be rebuilt. For example, a new version of zlib or boost may be released, or changes to a low level library such as miscmaths or newimage may break ABI compatiblity.

You can follow these steps to manage a full rebuild of all C++ projects (although keep reading, as step 3 can be done semi-automatically).

  1. Create a branch on fsl/conda/manifest called <manifest-branch> (change this to a suitable name) and make the required changes (e.g. bumping the zlib or newimage version).

  2. Compile a list of all projects that need to be rebuilt.

  3. For each project that needs to be rebuilt, create a branch on the recipe repository, and increment the build number. This must be done in order of dependency (e.g. newimage must be built before avwutils).

a. Cancel the CI / CD pipeline that is created

b. Create a new CI / CD pipeline on the recipe branch, setting this variable: FSL_MANIFEST_REVISION=<manifest-branch>

c. If the build succeeds, merge the branch on the recipe repository, repeat steps a and b on the default recipe branch, and then publish the package.

  1. Once all projects have been built and published, you can merge the <manifest-branch> branch in the fsl/conda/manifest repository, and test/release the new FSL version.

The fsl-ci-rules Python package has a command called full_rebuild, which will perform step 3 semi-automatically for you. Use it like so:

  1. Run the full_rebuild command:

    full_rebuild --public \
        -t <token> \
        -m <msg> \
        -v FSL_MANIFEST_REVISION <manifest-branch> \
        <projects>
    
    where:

    • --public causes the packages to be published to the public channel. The default is to publish to the development channel - you may prefer to do this first so you can test the new builds before release.
    • <token> is your GitLab API token
    • <msg> is a descriptive message which gets added to the automatically added merge requests (e.g. "Bump zlib to 1.3")
    • <projects> is a list of all projects (the conda package names) that need to be rebuilt, e.g. fsl-utils fsl-misc_c fsl-miscmaths fsl-newimage fsl-avwutils fsl-mcflirt. You don't need to worry about getting the dependency order right - the full_rebuild script will figure this out for you.
  2. Monitor the build, confirming updates, fixing problems, and restarting as needed.

The full_rebuild command will ensure that the projects are built and published in order of dependence - for example, fsl-utils and fsl-misc_c must be built before fsl-miscmaths, which must be built before fsl-newimage, etc. Each dependency group will be built in parallel (up to four projects at a time). By default, full_rebuild will pause before building each group, and will prompt you to confirm that it should continue.

This is potentially a very error-prone process, and will probably require manual intervention. Therefore, it is important to monitor the build process, fixing problems as needed.

The full_rebuild command will assign a number to each dependency group, - if the build fails or is cancelled, you can use this number to resume the rebuild at a specific group. The projects in the example above would be organised into the following groups. These projects must be built and published in this order, but projects within each group may be built in parallel.

  1. fsl-utils, fsl-misc_c
  2. fsl-miscmaths
  3. fsl-newimage
  4. fsl-avwutils, fsl-mcflirt

If, for example, the fsl-newimage build fails, full_rebuild will exit early, You must then figure out why fsl-newimage failed to build, and resolve the issue, either by updating the code at fsl/newimage and tagging a new version, or by updating the recipe at fsl/conda/fsl-newimage. When you have fixed the problem, you can resume the build by running:

full_rebuild -g 3 <other-options>

The -g 3 option tells the script to resume the build at group 3.

Updating low-level FSL packages

FSL C++ projects pin the versions of their dependencies to specific versions to guarantee ABI compatibility. When a new version of a dependency is released, these version pins must be updated. This is a relatively simple process. For example, if a new version 2412.0 of fsl-utils is released, the fsl-avwutils recipe must be updated.

  1. Create a branch on the fsl/conda/fsl-avwutils repository.

  2. Edit the meta.yaml file, changing fsl-utils 2203 to fsl-utils 2412, and incrementing the recipe build number.

  3. Open a merge request, and merge your change.

  4. Build and publish the new fsl-avwutils package (if necessary).

If a dependency is used by many projects, this can be a tedious process. Instead of doing this by hand, you can use the apply_patch command to update many recipes at once:

  1. Run the apply_patch command:

    apply_patch  \
      -t <token> \
      -m <msg>   \
      -i <title> \
      <patch> <recipe> [<recipe>...]
    
    where:

    • <token> is your GitLab API token
    • <msg> is used in the commit message
    • <title> is used in the merge request title
    • <patch> is a patch file or replacement string
    • <recipe> is the recipe repository path (e.g. fsl/conda/fsl-avwutils)
  2. Go to the recipe repository on gitlab and merge the MR.

  3. Publish the new package (if necessary).

The apply_patch command also has some handy options: - -a: automatically merge the merge request - -c: Cancel the build pipeline(s)

These options are useful if you need to update many recipes, but do not yet want to rebuild or publish new versions of the packages.

For example, if fsl-avwutils and fsl-basisfield are currently built against fsl-newimage 2203, and you need to update them to be built against fsl-newimage 2501, you can run:

apply_patch                               \
  -a -c                                   \
  -t <token>                              \
  -m "Update fsl-newimage to 2501"        \
  -i "Update fsl-newimage to 2501"        \
  "fsl-newimage 2203|||fsl-newimage 2501" \
  fsl-avwutils fsl-basisfield

This command will update the conda recipe, but will not rebuild the packages - you can do this later on using the full_rebuild command.

Keeping track of a build migration

If you are updating many conda recipes in stages (i.e. not updating the recipes all at once), the migration_status command can help you to keep track of which recipes have been updated, and which still need updating. Call migration_status like so:

migration_status -t <token> <package> [<package>..]

The command will print out a list of all packages which depend on <package>, the current state of their conda recipe, and the most recently published version. Some third-party packages may be referred to in different ways (e.g. zlib and libzlib, libboost and libboost-devel), so you can provide different variants of its name.

For example, if you are migrating all recipes to a new version of newimage, you can run:

$ migration_status -t <token> fsl-newimage

This will produce a table which looks something like the following:

Status of packages w.r.t. to [fsl-newimage]
Package                      | Recipe version | Version     | Recipe pin        | Package pin
                             |                |             |                   |
fsl-gps                      | 2211.1         | 2211.1      | n/a               | n/a
fsl-newimage                 | 2501.0         | 2501.0      | n/a               | n/a
fsl-newmesh                  | 2111.2         | 2111.2      | n/a               | n/a
                             |                |             |                   |
fsl-asl_mfree                | v1.0.2         | v1.0.2      | fsl-newimage 2501 | fsl-newimage >=2501.0,<2502.0a0
fsl-avwutils                 | 2209.3         | 2209.3      | fsl-newimage 2501 | fsl-newimage >=2501.0,<2502.0a0
fsl-basisfield               | 2203.1         | 2203.1      | fsl-newimage 2501 | fsl-newimage >=2203.11,<2204.0a0
fsl-bint                     | 2111.1         | 2111.1      | fsl-newimage 2203 | fsl-newimage >=2203.12,<2204.0a0
fsl-dpm                      | 2111.0         | 2111.0      | fsl-newimage 2203 | fsl-newimage >=2203.11,<2204.0a0
...

Packages are grouped according to their build-time dependence. - The Recipe version shows the package recipe as listed in meta.yaml - The Version shows the latest published version. - The Recipe pin column shows the contents of the package's meta.yaml file with respect to fsl-newimage, - The Package pin column shows the fsl-newimage pinning in the most recently published version.

You can see from this table that: - The latest published version of fsl-newimage is 2501.0 - all of the packages up to fsl-avwutils have been built and published against fsl-newimage 2501. - The fsl-basisfield recipe has been updated to fsl-newimage, but the package has not yet been rebuilt. - The fsl-bint and fsl-dpm recipes have not yet been updated to fsl-newimage 2501.

Adding a new CUDA version

When you wish to build FSL projects against newer CUDA versions, follow these steps to enable that CUDA version in the FSL build system:

  1. Create a Dockerfile for the new CUDA version in the docker sub-directory of the fsl/conda/fsl-ci-rules repository.

  2. Update the docker/install_cudatoolkit.sh script so that it supports the new CUDA version.

  3. Update the docker/install_miniconda.sh script to ensure that an appropriate version of GCC is installed.

  4. Add a FSL_CI_IMAGE_LINUX_64_CUDA_X_Y variable in the .gitlab-ci.yml file.

  5. Add a build-docker-image-linux-64-cuda-X.Y job to the rules/fsl-ci-management-rules.yml file.

  6. Add a build-linux-64-cuda-X.Y-conda-package job to the rules/fsl-ci-build-rules.yml file.

  7. Add a build-linux-aarch64-cuda-X.Y-conda-package job to the rules/fsl-ci-build-rules.yml file.

  8. Add a deploy-linux-64-cuda-X.Y-conda-package job to the rules/fsl-ci-deploy-rules.yml file.

  9. Add a deploy-linux-aarch64-cuda-X.Y-conda-package job to the rules/fsl-ci-deploy-rules.yml file.

  10. Update the CUDA_VERSIONS list in fsl_ci/platform.py. This should contain all CUDA versions that you wish to build FSL packages for, rather than all supported CUDA versions, so you would typically just replace its contents with the new CUDA version.

  11. For all existing CUDA recipes update the meta.yaml file if needed to ensure that an appropriate version of GCC is selected.

  12. For all existing CUDA recipes update the FSLCONDA_CUDA_VERSION CI / CI variable - this can be done locally using the set_gitlab_variables command.

  13. Perform a test build of a CUDA project, and make any other changes to the build system as needed until it works.

Managing the FSL conda channels

In normal circumstances, once a package has been published to the FSL public conda channel, it will remain there indefinitely. However, sometimes you may accidentally publish a broken package that you wish to remove from the channel. This can be accomplished by running a CI / CD job through the Gitlab web UI on the fsl/conda/fsl-ci-rules repository:

  • clear-public-channel: Delete packages from the public channel.
  • clear-internal-channel: Delete packages from the internal channel.
  • clear-development-channel: Delete packages from the development channel.
  • purge-public-channel-index: Delete and re-generate the index (conda channel metadata) for the public channel.
  • purge-internal-channel-index: Delete and re-generate the index for the internal channel.
  • purge-development-channel-index: Delete and re-generate the index for the development channel.

It should go without saying that you must be extremely careful when deleting packages from the public and internal channels, and always perform a DRY_RUN first.

When running any of the clear-* jobs, you must set some CI / CD variables: - DRY_RUN: Optional, defaults to true which doesn't delete anything, but just prints out what would be deleted. When set to false, will delete the requested package files. It is very wise to perform a dry run first and check the result, before performing a real run.

  • PATTERN: Specifies which packages to remove - this should be be a semi-colon-separated list of glob-style patterns, matched against package file names, which indicate the packages to be deleted. For example, to remove all packages starting with abc-, and all packages with -misc in their name, you would set PATTERN="abc-*;*-misc*".

  • CLEAR: Must be set to either all or old - when set to all, all packages (or all packages matching PATTERN) are deleted. When set to old, all except the most recent version of each package (and which match PATTERN, if it is set) are deleted.

Managing the FSL release page

FSL release files (manifest.json and environment.yml files) are published to https://fsl.fmrib.ox.ac.uk/fsldownloads/fslconda/releases/. These files are automatically generated and published via CI / CD jobs running on the fsl/conda/manifest/ repository, and normally need no manual intervention. However, you may sometimes wish to clear out files for old development releases, or you may need to make changes to the official release manifest.json file.

This can be accomplished via manually triggered CI / CD jobs on the fsl/conda/manifest repository, which should be executed with extreme caution - you should always perform a DRY_RUN before making any changes to the release page.

  • clear-release-files allows you to delete files from the release page. You must set some CI / CD variables:

    • DRY_RUN: Defaults to true, which does not delete any files, but prints the files that would be deleted. When set to false, will delete the requested release files.
    • PATTERN: A semi-colon-separated list of glob-style patterns, specifying which files to delete.
  • replace-manifest allows you to replace the official FSL release manifest.json file. You must set the following CI / CD variables:

    • DRY_RUN: Defaults to true, which doesn't replace the manifest, but prints the contents of the new manifest. When set to false, will replace the manifest.json file.
    • MANIFEST_CONTENTS: The new contents of the manifest.json file.

Summary of CI / CD variables

This table contains a summary of all CI / CD variables which can be used to control / customise the behaviour of the FSL build system.

Name Repository Required Purpose
FSL_CI_RULES_REPOSITORY Both No Install CI rules from a different repository.
FSL_CI_RULES_REVISION Both No Install CI rules from a branch other than master.
FSL_CI_API_TOKEN Both Yes GitLab API token used for interacting with GitLab.
FSL_CI_SKIP_ALL Both No Skip all FSL CI jobs (set to any non-empty value).
FSL_CI_RUN_TESTS Recipe No Include test stage, which runs any pyfeeds unit tests in the project source repository (set to any non-empty value).
FSL_CI_TEST_REQUIRES Recipe No Space-separated list of conda packages install when running tests (in addition to those required by the package).
FSL_CI_RUNNER_PLATFORM_LINUX Recipe No Override the GitLab runner used to build/test noarch packages.
FSL_CI_RUNNER_PLATFORM_LINUX_X64 Recipe No Override the GitLab runner used to build/test Intel Linux packages.
FSL_CI_RUNNER_PLATFORM_LINUX_AARCH64 Recipe No Override the GitLab runner used to build/test ARM64 linux packages.
FSL_CI_RUNNER_PLATFORM_MACOS_64 Recipe No Override the GitLab runner used to build/test Intel Apple packages.
FSL_CI_RUNNER_PLATFORM_MACOS_M1 Recipe No Override the GitLab runner used to build/test Apple Silicon packages.
FSL_DEVRELEASE Recipe No Mark the package as a development release (set to any non-empty value).
FSL_MANIFEST_REPOSITORY Recipe No Download fsl-release.yml from this repository when building a package (versions of base/core packages are specified in this file, and pinned at build time).
FSL_MANIFEST_REVISION Recipe No Download fsl-release.yml from this branch when building a package.
FSLCONDA_RECIPE Recipe Yes Used to differentiate recipe repositories from project repositories (set to any non-empty value).
FSLCONDA_REPOSITORY Recipe No Build a conda package from this repository, instead of the repository specified in meta.yaml.
FSLCONDA_REVISION Recipe No Build a conda package from this revision, instead of the revision specified in meta.yaml.
FSLCONDA_RECIPE_URL Project No Space separated list of recipe repository URLs, where the fsl/<project> / fsl/conda/fsl-<project> naming convention is not followed, or where multiple recipes are associated with one project.
FSLCONDA_BUILD_EXTRA_ARGS Recipe No Additional arguments to pass to conda build.
FSLCONDA_BUILD_CONFIG_TEMPLATE Recipe No Jinja2 conda_build_config.yaml template, overriding fsl_ci/templates/conda_build_config.yaml.
FSLCONDA_BUILD_PLATFORM Recipe Yes Space-separated list of conda package platforms which should be built - see below.
FSLCONDA_CUDA_VERSION Recipe No Space-separated list of CUDA versions (e.g. "9.2 10.2") denoting which CUDA versions a project should be built against.
FSLCONDA_SKIP_RECIPE_UPDATE Project No Do not open a merge request on the recipe repository when new tags are added to the project repository (set to any non-empty value).
FSLCONDA_INTERNAL Recipe No Marks this conda package as internal - builds will be deployed to the internal channel, rather than the public channel (set to any non-empty value).
FSLCONDA_INTERNAL_CHANNEL_USERNAME Recipe No Username for accessing the internal conda channel - required for packages which depend on internal-only packages .
FSLCONDA_INTERNAL_CHANNEL_PASSWORD Recipe No Password for accessing the internal conda channel - required for packages which depend on internal-only packages .