Skip to content

SINTEF/fortran-stacktrace

Repository files navigation

Fortran Stacktrace

Generate stacktraces in Fortran

badge fortran stacktrace?label=version&sort=semver

This library enables generation of stacktraces for Fortran. It does so by providing a Fortran wrapper around the C++ library backward-cpp.

It also integrates with the Fortran error-handling library in order to generate errors that includes a stacktrace. This means that you can easily make even old legacy code output errors messages like this:

stacktrace example

The source code snippets are of course voluntary and only available on a machine with access to the source code itself.

Building

A fairly recent Fortran and C++ compiler is required to build this library. The following compilers are known to work:

  • gfortran version 9 or later

  • Intel Fortran 2021 or later

Note
Stacktraces are currently not enabled for gcc/gfortran when using MinGW on Windows. It seems like backward-cpp should support this, but I haven’t figured out how to get it working. Pull requests are welcome if anyone wants to have a look at this!

In order to get proper stacktraces you also need to compile your source code with debug information. To do this use the following compiler flags

Compiler Vendor

Operating System

Compiler flag

Link flag

GCC

Linux

-g

Intel

Linux

-g

Intel

Windows

-Z7

-debug

This will increase the binary size slightly, but contrary to popular belief it should not impact performance of your code!

On Linux, you also need to install binutils-dev which contains libbfd:

apt-get install binutils-dev # or the equivalent for your distro

For more information see also the backward-cpp documentation.

CMake

First, enable both Fortran and CXX as languages in your project:

project(<your project name> LANGUAGES Fortran CXX)

Or:

enable_language("Fortran")
enable_language("CXX")

To use the recommended compiler and link flags you can for example do the following:

if(CMAKE_Fortran_COMPILER_ID MATCHES "GNU")
    set(CMAKE_Fortran_FLAGS "-g")
    if(WIN32)
        set(CMAKE_EXE_LINKER_FLAGS "-debug")
    endif(WIN32)
elseif(CMAKE_Fortran_COMPILER_ID MATCHES "Intel")
    if(WIN32)
        set(CMAKE_Fortran_FLAGS "-Z7")
        set(CMAKE_EXE_LINKER_FLAGS "-debug")
    else(WIN32)
        set(CMAKE_Fortran_FLAGS "-g")
    endif(WIN32)
endif()

This example is not complete, but can be used as a starting point. Add other compiler flags depending on your project needs.

The recommended way of getting the source code for this library when using CMake is to add it as a dependency using CMake Package Manager (CPM):

CPMAddPackage("https://github.com/SINTEF/[email protected]")
target_link_libraries(<your target> stacktrace)

CMake Without CPM

If you don’t want to use CPM you can either use FetchContent manually or add this repo as a git submodule to your project. Then in your CMakeLists.txt add it as a subdirectory and use target_link_libraries to link against stacktrace.

Do however note that this library will still use CPM to add fortran-error-handling as its dependency.

Fortran Package Manager (FPM)

FPM is currently not supported as it is not yet able to compile C++ sources.

Usage

Warning
The procedures for loading and displaying a stacktrace is declared as pure however they do invoke C++ code which by definition cannot be pure. This is possible because the c-bindings are declared pure which is done by hand. The procedures does not have any side effects, which is the intent for of pure procedures in Fortran. If you are not comfortable with this way of stretching the definition of pure, don’t use stacktrace_t in pure procedures!
Warning
As of this writing, the latest gfortran versions has bugs related to user defined finalization of derived types. In order to avoid crashes like segmentation faults due to this, finalization is currently disabled when gfortran is used. As a result there will be a memory leak if a loaded stacktrace_t is deallocated or goes out of scope.

Error Handling Integration

It is possible to make errors created with the fortran-error-handling library contain a stacktrace. To do this, add the following code near the top of your program, preferably before any errors may occur:

program main
    use error_handling, only: set_error_hook
    use stacktrace_mod, only: stacktrace_error_hook_t
    implicit none

    call set_error_hook(stacktrace_error_hook_t())

    ! (...)
end program

For a complete example, see error-handling-integration.f90.

Generating Stacktraces

To generate a stacktrace from an arbitrary code location, do the following:

use stacktrace_mod, only: stacktrace_t

type(stacktrace_t) :: st
character(len=:), allocatable :: chars

! Load a stacktrace from this point
call st%load_here()

! Convert the stacktrace into character, e.g. for writing to a log file.
! `snippet=.false.` disables snippet generation even when sources are available
chars = st%to_chars(snippet=.false.)
write(*,'(a)') chars

Contributions

Feel free to submit Feedback, suggestions or any problems in the issue tracker.

Copyright 2022 SINTEF Ocean AS. All Rights Reserved. MIT License.

backward-cpp is redistributed by this project. Copyright 2013-2017 Google Inc. All Rights Reserved. MIT License.