Build Automation

Source code written in Fortran can be easily build by executing the compiler from the command-line. This build process can be automated by various tools. A common way on Unix are Makefiles, which specify all steps for compilation, linking, and installation of your project.

In many cases, Makefiles are not platform-independent. Therefore, it may be necessary to write distiguished Makefiles for each targeted system. Even if a POSIX standard for Makefiles exists, two implementations are used in the wild instead: BSD make and GNU make. Often, a Makefile written for BSD make won’t be accepted by GNU make, and vice versa.

The CMake build utility bypasses these limitations and allows the generation of Makefiles with respect to the currently used environment and the compilers available on the system.

Make

Makefiles are an easy way to maintain the build process of a Fortran project. Once written, the file can executed by the make utility (either BSD make or GNU make). The following very simplistic Makefile for BSD make below is used to compile an example Fortran program example.f90 with Flang. Please note the hard tabs in the source.

FC     = flang
SRC    = example.f90
TARGET = example

.PHONY: all clean

all: $(TARGET)

$(TARGET):
	$(FC) -o $(TARGET) $(SRC)

clean:
	rm $(OBJ)

Save the file as Makefile in the directory that locates your source code files. Execute make or make all inside the directory to compile the example:

$ make
flang -o example example.f90

To change the defined compiler to GNU Fortran, run:

$ make FC=gfortran9

Running make clean will delete the built executable. On Linux, you may have to call bmake.

Linking

The example Makefile below also links the program against required dependencies. At first, the object files ncurses.o and macros.o will be compiled. Then, the main program is build and linked against the objects (see the ncurses section for a complete example).

CC      = clang
FC      = flang
CFLAGS  = -Wall
FFLAGS  = -Wall
LDLIBS  = -lncurses
OBJ     = macros.o ncurses.o
SRC     = main.f90
TARGET  = example

.PHONY: all clean

all: $(TARGET)

$(TARGET): $(OBJ)
	$(FC) -o $@ $(SRC) $(OBJ) $(LDLIBS)

macros.o: $*.c
	$(CC) $(CFLAGS) -c $?

ncurses.o: $*.f90
	$(FC) $(FFLAGS) -c $?

clean:
	rm $(TARGET) *.o *.mod

CMake

Using CMake to generate a fresh Makefile allows to regard the used computer platform and to set compiler-specific options. In the following example, the source file main.f90 will be compiled and statically linked against a library in f90getopt.f90.

Please be aware that the ending of all Fortran source files must either be set to .f90 or .f95 to be recognised by CMake. The CMake configuration has to be saved to file CMakeLists.txt in your source code path:

cmake_minimum_required(VERSION 3.5)
project(Example)
set(VERSION 1.0)

if(NOT CMAKE_BUILD_TYPE)
    set(CMAKE_BUILD_TYPE RELEASE)
endif()

if(CMAKE_Fortran_COMPILER MATCHES "gfortran*")
    set(CMAKE_SKIP_BUILD_RPATH            FALSE)
    set(CMAKE_BUILD_WITH_INSTALL_RPATH    TRUE)
    set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)

    set(CMAKE_Fortran_FLAGS         "${CMAKE_Fortran_FLAGS} -std=f2003 -fimplicit-none")
    set(CMAKE_Fortran_FLAGS_DEBUG   "-Wall -O0 -g3 -fbounds-check")
    set(CMAKE_Fortran_FLAGS_RELEASE "-O2")
endif()

set(TARGET example)
set(SOURCE_FILES main.f90)

add_library(f90getopt STATIC f90getopt.f90)

add_executable(${TARGET} ${SOURCE_FILES})
target_link_libraries(${TARGET} f90getopt)
set_target_properties(${TARGET} PROPERTIES LINKER_LANGUAGE Fortran)

Generate a Makefile and build the project with:

$ mkdir build
$ cd build/
$ cmake ..
$ make

You can force a specific compiler by using the -DCMAKE_Fortran_COMPILER flag:

$ cmake -DCMAKE_Fortran_COMPILER=gfortran9 -DCMAKE_INSTALL_RPATH=/usr/local/lib/gcc9/ ..