Building containers

Table of contents

  1. Building with sudo rights
  2. Building without sudo rights
  3. Building with small temporary directories
  4. Building a generic container
  5. Building an optimised container

Rebuilding containers is necessary if you want to change or add software, or optimise for a specific machine.


The recipes offer customisation options through environment variables near the top. Environment variables that a user may want to modify are summarised in the table below. Other variables should not requrie modification unless there are specific reasons for doing so.

Variable Values Purpose
CPPSTD C++ standard Passed to GCC’s -std option when building C++ code, specifying which C++ standard to use.
DEBUG true/false Installs GDB and Valgrind, adds -g to GCC, and increases CMake verbosity.
HAS_CUDA true/false Install Nvidia CUDA and link IDG to it if set to true.
HAS_MKL true/false Install the Intel Math Kernel Library en link IDG to it if set to true.
INSTALL_CASA true/false Installs CASA if enabled. Disabling this saves space.
MARCH GCC compatible architecture Passed to GCC’s -march option to generate code optimised for the specified CPU architecture.
MTUNE GCC compatible architecture Passed to GCC’s -mtune option to optimise code for the specified CPU architecture.
NOAVX512 true/false Disables the use of AVX512 instructions if set to true. Recommended when building for older or generic hardware on a modern machine, or when building AMD-specific containers on an Intel machine.
OPENBLASTARGET OpenBLAS arch names Sets the target for which OpenBLAS will be built (only when not using MKL).

In 2021 Singularity was renamed to Apptainer. There is little if any change in functionality, but if apptainer-related commands or environment variables mentioned below do not work for you, replace instances of apptainer with singularity and instances of APPTAINER_ with SINGULARITY_. See the official announcement for more information.

Building with sudo rights

If have root permissions on the machine you are building on, a container can be built with

sudo apptainer build <container name> <recipe file>

Building without sudo rights

If you do not have root permissions on the machine you are building on, the Singularity/Apptainer installation has to have the fakeroot feature enabled. Once that is available, a container can be built by running

apptainer build --fakeroot <container name> <recipe file>

There is a potential issue surrounding getopt and the Fedora base container on which FLoCs is built. If you encounter the following error during build:

INFO:    User not listed in /etc/subuid, trying root-mapped namespace
INFO:    The %post section will be run under fakeroot
INFO:    Starting build...
Copying blob 633a2a041c85 skipped: already exists  
Copying config 15e89348c0 done   | 
Writing manifest to image destination
2024/07/05 11:30:56  info unpack layer: sha256:633a2a041c85d22a814d80c8fd43a885066522afeea82db646cff81983f3dbaf
INFO:    Running post scriptlet
/.singularity.d/libs/fakeroot: line 46: getopt: command not found
/.singularity.d/libs/fakeroot: line 50: getopt: command not found
fakeroot, create a fake root environment.
   usage: fakeroot [-l|--lib fakerootlib] [-f|--faked fakedbin]
                   [-i file] [-s file] [-u|--unknown-is-real]
		   [-b|--fd-base fd] [-h|--help] [-v|--version]
                   [--] [command]
FATAL:   While performing build: while running engine: exit status 1

and getopt is available on your host machine, try including the following at the top of the recipe file as a stop-gap:

%files
    /usr/bin/getopt /usr/bin/getopt

Building with small temporary directories

If the machine you are running at has little space available on e.g. /var or /tmp you may run into trouble during the build. To avoid this, the build’s temporary and cache directories can be set as follows:

sudo APPTAINER_TMPDIR=<custom tempdir> APPTAINER_CACHEDIR=<custom cachedir> apptainer build <container name> <recipe file>

Building a generic container

A generic container is intended to be compatible with a wide variety of systems. This entails:

  1. Setting MARCH=x86-64 and MTUNE=generic to disable CPU architecture optmisation by setting.
  2. Setting NOAVX512=true to disable AVX512 instructions.
  3. Setting HAS_MKL=false to not use Intel MKL.

This should produce a container capable of running on a reasonably wide range of CPUs launched in the past decade or so.

Building an optimised container

Enabling compiler optimisations can result is a substantial performance increase over a generic container. This entails:

  1. Setting MARCH and MTUNE to values suitable for your CPU.
  2. Setting NOAVX512=false if your CPU supports AVX512 instructions.
  3. Setting HAS_MKL=true if you have an Intel CPU.

You can find the recommended march, mtune and AVX512 settings by running obtain_march_mtune.sh. This will run the following:

MARCH=$(gcc -march=native -Q --help=target | grep '\-march=  ' | awk -F" " '{print $2}')
MTUNE=$(gcc -march=native -Q --help=target | grep '\-mtune=  ' | awk -F" " '{print $2}')

echo Use \"-march=$MARCH -mtune=$MTUNE\" flags for native compilation.

AVX512=$(gcc -march=$MARCH -mtune=$MTUNE -dM -E - < /dev/null | egrep "AVX512")
if [[ $AVX512 == *"AVX512"* ]]; then
    echo -march=$MARCH -mtune=$MTUNE supports AVX512
else
    echo -march=$MARCH -mtune=$MTUNE does _NOT_ support AVX512
fi

It is important to use a recent GCC such that it can recognise your CPU properly.


This site uses Just the Docs, a documentation theme for Jekyll.