Generate stacktraces in Fortran
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:
The source code snippets are of course voluntary and only available on a machine with access to the source code itself.
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 |
|
|
Intel |
Linux |
|
|
Intel |
Windows |
|
|
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.
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/fortran-stacktrace.git@0.1.0")
target_link_libraries(<your target> stacktrace)
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.
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.
|
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
.
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
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.