Compiling and Linking#
This page describes how to build software on Levante, i.e. to generate executable files from source code files typically written in C, C++ or Fortran and parallelised using MPI and/or OpenMP.
Compilers#
Different release versions of the following compiler suites are available on Levante:
This variety of compilers supports different use cases, such as generating highly optimised binaries for CPUs or GPUs or debugging complex Fortran codes.
Important
Compilers are not available by default in your shell environment; you must load the appropriate module file to access them. We recommend specifying the version number explicitly. Otherwise, either the default version (if one is defined for that module) or the lexicographically highest available version will be loaded.
Intel Compilers#
For most applications we recommend to use the Intel compilers, which are part of the Intel oneAPI Toolkit. The compiler version can be selected by loading the corresponding module file, for example:
# Use a specific version of Intel compiler
$ module load intel-oneapi-compilers/2022.0.1-gcc-11.2.0
$ module load intel-oneapi-compilers/2025.3.2-gcc-13.4.0
The specific compiler names are summarized in the table below. The Intel classic compilers are no longer available in newer versions of the Intel OneAPI Toolkits distributions.
Classic |
OneAPI |
Purpose |
|---|---|---|
icc |
icx |
for C source code |
ifort |
ifx |
for Fortran source code |
icpc |
icpx |
for C++ source code |
Compiler options that are commonly used for the Intel compilers are:
Option |
Descripion |
|---|---|
-qopenmp |
Generates multi-threaded code based on the OpenMP directives |
-g |
Creates debugging information in the object files. This is necessary if you want to debug your program |
-O[0-3] |
Sets the optimization level |
-I/path/to/include |
Adds directories to search for include files |
-L/path/to/lib |
A path can be given in which the linker searches for libraries |
-Wl,-rpath,/path/to/lib |
Pass |
-D |
Defines a CPP macro |
-U |
Undefines a CPP macro |
-ipo |
Inter-procedural optimization |
-march=core-avx2 |
Indicates the processor for which code is generated |
-mtune=core-avx2 |
Indicates the processor for which optimizations are performed |
-sox |
Stores information like compiler version, options used etc. in the executable file |
-help |
Displays available compiler options |
For further information on optimisation flags and other Intel oneAPI compiler options, please refer to the manual pages of the respective compiler, e.g.:
$ man ifx
$ man icx
$ man icpx
or the comprehensive documentation on Intel website.
Note
Using the compiler option -march=core-avx2 forces the Intel
compiler to use full AVX2 support/vectorization (with FMA
instructions) which might results in binaries that do not produce
MPI decomposition independent results. Adding the option
-no-fma should solve this issue but could result in slightly
longer runtime.
GNU Compiler Collection (GCC)#
GCC is a suite of compilers for C (gcc),
C++ (g++), Fortran (gfortran), D (gcd) and some other programming
languages. You need to load an environment module for gcc to access a more
recent version of the GNU compiler suite. The use of the older system
gcc located in /usr/bin and provided as part of the base Linux
operating system is generally inadvisable. Example for loading a
specific version of gcc:
# Use a specific version of gcc compiler
$ module load gcc/11.2.0-gcc-11.2.0
nAG#
nAG Fortran Compiler
(nagfor) has proved to be very useful for debugging und checking
if the source code is standard conforming. It is not appropriate to
create model binaries for production runs. To make nAG compilers
available in your shell environment, you need to load an nag
environment module, e.g.:
# Use a specific version of nag compiler
$ module load nag/7.2-gcc-11.2.0
NVIDIA HPC SDK#
The NVIDIA HPC Software development Kit (SDK) contains a compiler suite that is of special interest for users and developers of GPU-ready codes. It supports GPU offloading using OpenMP, OpenACC and CUDA. Please refer to the section on GPU Programming for more information. Since 2020 NVIDIA HPC compilers replace the PGI compilers.
Compiling and Linking MPI programs#
MPI Libraries#
Currently, two implementations of Message Passing Interface (MPI) library are available on Levante:
No MPI libraries are available by default. Similar to compilers, you have to explicitly load an appropriate environment module for a certain MPI implementation.
Important
Since Fortran module files (.mod) are compiler-specific, you
must use an MPI installation built with the same compiler that you
use to build your code. The compiler used for each MPI installation
is indicated by suffixes in the MPI modulefile names, such as
intel-2021.5.0, oneapi-2025.3.2, gcc-11.2.0 or
nvhpc-24.7 etc.
MPI Compiler Wrappers#
It is highly advisabe to use MPI compiler wrappers to compile and link MPI parallel programs. Such wrappers are provided with each MPI library implementation. They automatically build up the MPI environment (i.e. set paths to MPI include files and MPI libraries) to facilitate the compilation and linking steps. The following table shows the names of the Open MPI and Intel MPI compiler wrappers:
Language |
Open MPI wrapper |
Intel MPI wrapper |
|---|---|---|
Fortran |
|
|
C++ |
|
|
C |
|
|
Examples#
Compile a MPI parallel program in Fortran using Intel oneAPI Fortran compiler and Open MPI:
$ module load intel-oneapi-compilers/2025.3.2-gcc-13.4.0
$ module load openmpi/5.0.10-oneapi-2025.3.2
$ mpifort -O2 -march=core-avx2 -fp-model source -o myprog myprog.f90
Compile a hybrid parallel (MPI + OpenMP) program in Fortran using Intel oneAPI Fortran compiler and Open MPI:
$ module load intel-oneapi-compilers/2025.3.2-gcc-13.4.0
$ module load openmpi/5.0.10-oneapi-2025.3.2
$ mpifort -qopenmp -O2 -march=core-avx2 -fp-model source -o myprog myprog.f90
Compile a hybrid MPI/OpenMP program in Fortran using GCC Fortran compiler and Open MPI:
$ module load gcc/11.2.0-gcc-11.2.0
$ module load openmpi/4.1.2-gcc-11.2.0
$ mpifort -fopenmp -O2 -march=native -mpc64 -o myprog myprog.f90
Compile a MPI program in Fortran using Intel Fortran compiler and Intel MPI:
$ module load intel-oneapi-compilers/2022.0.1-gcc-11.2.0
$ module load intel-oneapi-mpi/2021.5.0-intel-2021.5.0
$ mpiifort -O2 -march=core-avx2 -fp-model source -o myprog myprog.f90
Note
The computational performance and scalability of MPI applications on Levante can be considerably improved by an optimal choice of the runtime parameters provided by MPI libraries. The appropriate MPI run time settings strongly depend on the type of application and MPI library used. For most MPI versions installed on Levante, we provide some recommendations for MPI environment settings that proved to be beneficial for different model codes commonly used at DKRZ.
Libraries from the software tree#
Many commonly used libraries are available from the central software
tree located at /sw/spack-levante. They are all installed in
individual directories so we can provide different versions and
configurations of the same library. This means that you should
carefully chose which library to link and run your model with.
For many libraries, you can find a module file which tells you where to find the library for compiling and linking. More detailed information can be inquired with the spack command for all installed libraries.
How to build software with netCDF#
NetCDF libraries
are commonly used in climate models for data input and output. If only
the Fortran interface is directly accessed in your program, it is
sufficient to know the installation path of the netcdf-fortran
library and to use this information for building your
software. Netcdf-fortran installations available on Levante can be
inquired with the module avail command:
$ module avail netcdf-fortran
Based on the compiler and MPI you want to use, you need to select one
of the available libraries that is compatible and meets your
requirements. The installation path of that library can then be
inferred with the module show command. For example, if you use
Intel oneAPI compiler and Open MPI, and you find that
netcdf-fortran/4.6.2-openmpi-5.0.10-oneapi-2025.3.2 matches your
setup, the following module show command:
$ module show netcdf-fortran/4.6.2-openmpi-5.0.10-oneapi-2025.3.2
-------------------------------------------------------------------
/sw/spack-levante/spack/modules/netcdf-fortran/4.6.2-openmpi-5.0.10-oneapi-2025.3.2:
module-whatis {NetCDF (network Common Data Form) is a set of software libraries...}
conflict netcdf-fortran
prepend-path --delim : PATH /sw/spack-levante/netcdf-fortran-4.6.2-yuo6bc/bin
prepend-path --delim : MANPATH /sw/spack-levante/netcdf-fortran-4.6.2-yuo6bc/share/man
prepend-path --delim : PKG_CONFIG_PATH /sw/spack-levante/netcdf-fortran-4.6.2-yuo6bc/lib/pkgconfig
prepend-path --delim : CMAKE_PREFIX_PATH /sw/spack-levante/netcdf-fortran-4.6.2-yuo6bc/.
append-path --delim : MANPATH {}
-------------------------------------------------------------------
provides the installation path of the library:
/sw/spack-levante/netcdf-fortran-4.6.2-yuo6bc
The directory containing include files is then:
/sw/spack-levante/netcdf-fortran-4.6.2-yuo6bc/include
and the path to the library files is:
/sw/spack-levante/netcdf-fortran-4.6.2-yuo6bc/lib
In a usual setting, you can instruct your compiler and linker to use the netCDF library from this path both for compiling and when running your program using the following options:
$ mpifort -I/sw/spack-levante/netcdf-fortran-4.6.2-yuo6bc/include \
-L/sw/spack-levante/netcdf-fortran-4.6.2-yuo6bc/lib -lnetcdff \
-Wl,-rpath,/sw/spack-levante/netcdf-fortran-4.6.2-yuo6bc/lib \
-o myprog myprog.f90
The -I option tells the Intel compiler where to find include files
and Fortran module description files (.mod) for
netcdf-fortran. The -L option tells the link editor where to
find the netcdf-fortran library (libnetcdff) itself.
Since the dynamic version of the library is linked by default, you
must also encode its runtime search path in the generated binary using
the -Wl,-rpath, option. This is necessary because netcdf-fortran is
not installed in a standard directory, such as /usr/lib64, that is
automatically searched by the dynamic linker. Otherwise, you will
encounter the following error at runtime:
myprog: error while loading shared libraries: libnetcdff.so.7:
cannot open shared object file: No such file or directory
In general, you will have to add options corresponding to the above for each library you are going to use.
On Levante, libraries in the software tree already include link
information indicating where their respective dependencies can be
found. For example, netcdf-fortran contains the correct paths to
netcdf-c, hdf5, libaec, and other dependencies. You do not need to
provide this information again unless your program also calls
functions from those libraries directly. In that case, we recommend
using the spack command as follows to obtain information about the
dependency libraries:
$ spack find -dp netcdf-fortran %oneapi@2025.3.2 ^openmpi@5.0.10
The above command will list the installation of the netcdf-fortran
library built with the specified version of the Intel oneAPI compiler
and depending on the chosen Open MPI installation and subsequently all
of its dependencies plus the corresponding installation paths:
-- linux-rhel8-zen3 / oneapi@2025.3.2 ---------------------------
netcdf-fortran@4.6.2 /sw/spack-levante/netcdf-fortran-4.6.2-yuo6bc
netcdf-c@4.10.0 /sw/spack-levante/netcdf-c-4.10.0-wplcog
...
hdf5@1.14.6 /sw/spack-levante/hdf5-1.14.6-cz2y6n
cmake@3.31.11 /sw/spack-levante/cmake-3.31.11-3zz4ku
ncurses@6.4 /sw/spack-levante/ncurses-6.4-vpcjt5
gmake@4.4.1 /sw/spack-levante/gmake-4.4.1-zwphlx
libaec@1.1.3 /sw/spack-levante/libaec-1.1.3-qhqvrk
libxml2@2.9.7 /usr
parallel-netcdf@1.14.1 /sw/spack-levante/parallel-netcdf-1.14.1-wshell
m4@1.4.18 /usr
zlib@1.2.11 /usr
zstd@1.5.7 /sw/spack-levante/zstd-1.5.7-3trffm
openmpi@5.0.10 /sw/spack-levante/openmpi-5.0.10-pjjvwl
hcoll@4.7.3199 /opt/mellanox/hcoll
...
==> 1 installed package
You can alternatively use the spack hash (which is also part of the package installation path) to infer the above information about dependencies and paths:
$ spack find -dp /yuo6bc
These paths can then be used to fill in additional information needed by build systems for packages that also directly interact with one or more of these other libraries (or just require that information because it is needed on other systems where libraries are not installed completely linked), for example:
$ mpifort -I/sw/spack-levante/netcdf-fortran-4.6.2-yuo6bc/include \
-L /sw/spack-levante/netcdf-fortran-4.6.2-yuo6bc/lib \
-L/sw/spack-levante/netcdf-c-4.10.0-wplcog/lib -lnetcdff -lnetcdf \
-Wl,-rpath,/sw/spack-levante/netcdf-fortran-4.6.2-yuo6bc/lib \
-Wl,-rpath,/sw/spack-levante/netcdf-c-4.10.0-wplcoglib \
-o myprog myprog.f90 util.o
Many libraries provide utilities to facilitate compiling and linking,
e.g. netcdf-c contains the nc-config command to query several
bits of information. You can use
$ module load netcdf-c/4.10.0-openmpi-5.0.10-oneapi-2025.3.2
$ nc-config --all
to see all details. A similar tool is also available for the
netcdf-fortran library:
$ module load netcdf-fortran/4.6.2-openmpi-5.0.10-oneapi-2025.3.2
$ nf-config --all
It is advisable to use the ldd program to verify that your program
has been correctly linked. Check that all library paths match the
dependency information and, in particular, that no library is reported
as “not found”:
$ LD_LIBRARY_PATH= ldd myprog