Compiling and Linking with Libraries¶
Objectives
- Learn about the compilers at HPC2N
- How to load the compiler toolchains
- How to use the compilers
- What are the popular flags
- How to link with libraries.
Installed compilers¶
There are compilers available for Fortran 77, Fortran 90, Fortran 95, C, and C++. The compilers can produce both general-purpose code and architecture-specific optimized code to improve performance (loop-level optimizations, inter-procedural analysis and cache optimizations).
Loading compilers¶
Note
You need to load a compiler suite (and possibly libraries, depending on what you need) before you can compile and link.
Use ml av
to get a list of available compiler toolchains
as mentioned in the modules - compiler toolchains section.
You load a compiler toolchain the same way you load any other module. They are always available directly, without the need to load prerequisites first.
Hint
Code-along!
Example: Loading foss/2023b
This compiler toolchain contains: GCC/13.2.0
, BLAS
(with LAPACK
), ScaLAPACK
, and FFTW
.
b-an01 [~]$ ml foss/2023b
b-an01 [~]$ ml
Currently Loaded Modules:
1) snicenvironment (S) 7) numactl/2.0.16 13) libevent/2.1.12 19) FlexiBLAS/3.3.1
2) systemdefault (S) 8) XZ/5.4.4 14) UCX/1.15.0 20) FFTW/3.3.10
3) GCCcore/13.2.0 9) libxml2/2.11.5 15) PMIx/4.2.6 21) FFTW.MPI/3.3.10
4) zlib/1.2.13 10) libpciaccess/0.17 16) UCC/1.2.0 22) ScaLAPACK/2.2.0-fb
5) binutils/2.40 11) hwloc/2.9.2 17) OpenMPI/4.1.6 23) foss/2023b
6) GCC/13.2.0 12) OpenSSL/1.1 18) OpenBLAS/0.3.24
Where:
S: Module is Sticky, requires --force to unload or purge
b-an01 [~]$
Compiling¶
Note
OpenMP: All compilers has this included, so it is enough to load the module for a specific compiler toolchain and then add the appropriate flag.
Note
If you do not name the executable (with the flag -o SOMENAME
, it will be named a.out
as default.
This also means that the next time you compile something, if you also do not name that executable, it will overwrite the previous a.out
file.
Compiling with GCC¶
Language | Compiler name | MPI |
---|---|---|
Fortran77 | gfortran | mpif77 |
Fortran90 | gfortran | mpif90 |
Fortran95 | gfortran | N/A |
C | gcc | mpicc |
C++ | g++ | mpiCC |
In order to access the MPI compilers, load a compiler toolchain which contains an MPI library.
Hint
Code-along!
Example: compiling a C program
You can find the file hello.c
in the exercises directory, in the subdirectory “simple”. Or you can download it here: hello.c.
In this example we compile the C program hello.c
and name the output (the executable) hello
.
You can run the executable with ./hello
Example: compiling an MPI C program
You can find the file mpi_hello.c
in the exercises directory, in the subdirectory “simple”. Or you can download it here: mpi_hello.c.
In this example we compile the MPI C program mpi_hello.c
and name the output (the executable) mpi_hello
.
You then run with `mpirun mpi_hello
Important
If you later have loaded a different compiler than the one your program was compiled with, you should recompile your program before running it.
Exercise
Try loading foss/2023b
and compiling mpi_hello.c
, then unload the module and instead load the module intel/2023b
and see what happens if you try to run with mpirun mpi_hello
.
Flags¶
Note
List of commonly used flags:
- -o file Place output in file ‘file’.
- -c Compile or assemble the source files, but do not link.
- -fopenmp Enable handling of the OpenMP directives.
- -g Produce debugging information in the operating systems native format.
- -O or -O1 Optimize. The compiler tried to reduce code size and execution time.
- -O2 Optimize even more. GCC performs nearly all supported optimizations that do not involve a space-speed tradeoff.
- -O3 Optimize even more. The compiler will also do loop unrolling and function inlining. RECOMMENDED
- -O0 Do not optimize. This is the default.
- -Os Optimize for size.
- -Ofast Disregard strict standards compliance. -Ofast enables all -O3 optimizations. It also enables optimizations that are not valid for all standard-compliant programs. It turns on -ffast-math and the Fortran-specific -fno-protect-parens and -fstack-arrays.
- -ffast-math Sets the options -fno-math-errno, -funsafe-math-optimizations, -ffinite-math-only, -fno-rounding-math, -fno-signaling-nans and -fcx-limited-range.
- -l library Search the library named ‘library’ when linking.
Hint
Code-along!
Example: compiling an OpenMP C program
You can find the file omp_hello.c
in the exercises directory, in the subdirectory “simple”. Or you can download it here: omp_hello.c.
In this example we compile the OpenMP C program omp_hello.c
and name the output (executable) omp_hello
.
Note
You can change the number of threads with export OMP_NUM_THREADS=#threads
Hint
Code-along!
Example
Run the binary omp_hello
that we got in the previous example. Set the number of threads to 4 and then rerun the binary.
b-an01 [~]$ ./omp_hello
Thread 0 says: Hello World
Thread 0 reports: the number of threads are 1
b-an01 [~]$ export OMP_NUM_THREADS=4
b-an01 [~]$ ./omp_hello
Thread 1 says: Hello World
Thread 0 says: Hello World
Thread 0 reports: the number of threads are 4
Thread 3 says: Hello World
Thread 2 says: Hello World
b-an01 [~]$
Exercise
Try yourself! Rerun with OMP_NUM_THREADS set to 1, 2, 4, 8.
NOTE: Normally you are not supposed to run anything on the command line, but these are very short and light-weight programs.
Exercise
You could try with a different toolchain (or version). Remember to unload/purge, load the new toolchain, compile the program again, and then run.
Compiling with Intel¶
Language | Compiler name | MPI |
---|---|---|
Fortran77 | ifort | mpiifort |
Fortran90 | ifort | mpiifort |
Fortran95 | ifort | N/A |
C | icc | mpiicc |
C++ | icpc | mpiicc |
In order to access the MPI compilers, load a compiler toolchain which contains an MPI library.
Example: compiling a C program
We are again compiling the hello.c
program from before. This time we name the executable hello_intel
to not overwrite the previously created executable.
Flags¶
Note
List of commonly used flags:
- -fast This option maximizes speed across the entire program.
- -g Produce symbolic debug information in an object file. The -g option changes the default optimization from -O2 to -O0. It is often a good idea to add -traceback also, so the compiler generates extra information in the object file to provide source file traceback information.
- -debug all Enables generation of enhanced debugging information. You need to also specify -g
- -O0 Disable optimizations. Use if you want to be certain of getting correct code. Otherwise use -O2 for speed.
- -O Same as -O2
- -O1 Optimize to favor code size and code locality. Disables loop unrolling. -O1 may improve performance for applications with very large code size, many branches, and execution time not dominated by code within loops. In most cases, -O2 is recommended over -O1.
- -O2 (default) Optimize for code speed. This is the generally recommended optimization level.
- -O3 Enable -O2 optimizations and in addition, enable more aggressive optimizations such as loop and memory access transformation, and prefetching. The -O3 option optimizes for maximum speed, but may not improve performance for some programs and may in some cases even slow down code.
- -Os Enable speed optimizations, but disable some optimizations that increase code size for small speed benefit.
- -fpe{0,1,3} Allows some control over floating-point exception (divide by zero, overflow, invalid operation, underflow, denormalized number, positive infinity, negative infinity or a NaN) handling for the main program at runtime. Fortran only.
- -qopenmp Enable the parallelizer to generate multi-threaded code based on the OpenMP directives.
- -parallel Enable the auto-parallelizer to generate multi-threaded code for loops that can be safely executed in parallel.
Linking¶
Build environment¶
Using a compiler toolchain by itself is possible but requires a fair bit of manual work, figuring out which paths to add to -I or -L for including files and libraries, and similar.
To make life as a software builder easier there is a special module available, buildenv
, that can be loaded on top of any toolchain. If it is missing for some toolchain, send a mail to support@hpc2n.umu.se and let us know.
This module defines a large number of environment variables with the relevant settings for the used toolchain. Among other things it sets CC, CXX, F90, FC, MPICC, MPICXX, MPIF90, CFLAGS, FFLAGS, and much more.
To see all of them, after loading a toolchain do:
To use the environment variables, load buildenv:
Using the environment variable (prefaced with $) for linking is highly recommended!
Example
Linking with LAPACK (gcc, C program).
OR use the environment variable $LIBLAPACK
:
Note
You can see a list of all the libraries on Kebnekaise (June 2024) here: https://docs.hpc2n.umu.se/documentation/compiling/#libraries.
Keypoints
- In order to compile a program, you must first load a “compiler toolchain” module
- Kebnekaise has both GCC and Intel compilers installed
- The GCC compilers are:
- gfortran
- gcc
- g++
- The Intel compilers are:
- ifort
- icc
- icpc
- Compiling MPI programs can be done after loading a compiler toolchains which contains MPI libraries
- The easiest way to figure out how to link with a library is to use
ml show buildenv
after loading a compiler toolchain