Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ list(APPEND tests
type_bn
type_check
f2f_kind
test_abort_buffer
)

foreach(test ${tests})
Expand Down
3 changes: 2 additions & 1 deletion examples/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ EXAMPLES = \
subroutine_contains_issue101 \
type_bn \
type_check \
f2f_kind
f2f_kind \
test_abort_buffer

# Append callback_print_function_issue93 only if Python >= 3.11
# This test is known not to work with older python version
Expand Down
10 changes: 9 additions & 1 deletion examples/meson.build.template
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,18 @@ endif

link_args = []
if ff.get_id() == 'nvidia_hpc'
link_args = ['-lnvf', '-lrt']
link_args += ['-lnvf', '-lrt']
endif

py = import('python').find_installation(pure: false)
py_dep = py.dependency()

dir_f90wrap = run_command(py,
['-c', 'import os; import f90wrap; print(os.path.dirname(f90wrap.__file__))'],
check : true
).stdout().strip()
link_args += ['-l_abort_buffers', '-L'+dir_f90wrap]

incdir_numpy = run_command(py,
['-c', 'import os; os.chdir(".."); import numpy; print(numpy.get_include())'],
check : true
Expand Down Expand Up @@ -48,4 +54,6 @@ py.extension_module(name,
dependencies : [py_dep, quadmath_dep],
install : true,
link_args: link_args,
install_rpath: dir_f90wrap,
build_rpath: dir_f90wrap,
)
59 changes: 59 additions & 0 deletions examples/test_abort_buffer/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#=======================================================================
# define the compiler names
#=======================================================================
include ../make.inc

UNAME = $(shell uname)

PY_MOD = pywrapper
WRAPFLAGS = -v
F2PY = f2py-f90wrap
F90_SRC = main_A.f90 main_B.f90
F90WRAP_SRC = $(addprefix f90wrap_,${F90_SRC})
OBJ = $(F90_SRC:.f90=.o)
F90WRAP_OBJ = $(F90WRAP_SRC:.f90=.o)
SRC_LIB = src
F90WRAP_LIB = f90wrap
ifeq ($(UNAME),Darwin)
LDFLAGS = -Wl,-undefined,dynamic_lookup
endif

.PHONY: all clean

all: test

clean:
rm -rf *.mod *.smod *.o lib*.a lib*.so f90wrap*.f90 ${PY_MOD}.py _${PY_MOD}*.so __pycache__/ .f2py_f2cmap build ${PY_MOD}* signatures_*

# This can be done in parallel as previously
%.o: %.f90
${F90} ${F90FLAGS} -c $< -o $@

# This can be done in parallel as previously
f90wrap_%.f90: %.o
${F90WRAP} -m ${PY_MOD}_$(patsubst %.o,%,$<) ${WRAPFLAGS} $(patsubst %.o,%.f90,$<)

# Using 2 f2py-f90wrap steps enables to compile f90wrap_*.f90 separately rather than compiling them through f2py-f90wrap invocation. Compiling them separatly enables to compile them in parallel.
# This can also be done in parallel but probably not critical
signatures_%.pyf: f90wrap_%.f90
${F2PY} $< -m _${PY_MOD}_$(patsubst f90wrap_%.f90,%,$<) -h $@

# This only compile c interfaces no fortran interfaces
# This can now be done in parallel
f2py_%: signatures_%.pyf lib${SRC_LIB}.so lib${F90WRAP_LIB}.so
${F2PY} ${F2PYFLAGS} -c $< -L. -l${SRC_LIB} -l${F90WRAP_LIB}

# Compile f90wrap generated interfaces
# This can now be done in parallel
# This also ease support for fortran compiler other than gfortran
f90wrap_%.o: f90wrap_%.f90
${F90} ${F90FLAGS} -c $< -o $@

lib${SRC_LIB}.so: ${OBJ}
${F90} ${F90FLAGS} -shared -o lib${SRC_LIB}.so ${OBJ} ${LDFLAGS}

lib${F90WRAP_LIB}.so: ${F90WRAP_OBJ} lib${SRC_LIB}.so
${F90} ${F90FLAGS} -shared -o lib${F90WRAP_LIB}.so ${F90WRAP_OBJ} -L. -l${SRC_LIB} ${LDFLAGS}

test: f2py_main_A f2py_main_B
LD_LIBRARY_PATH=. ${PYTHON} tests.py
2 changes: 2 additions & 0 deletions examples/test_abort_buffer/Makefile.meson
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Just include the regular makefile for now
include Makefile
14 changes: 14 additions & 0 deletions examples/test_abort_buffer/main_A.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module m_test_A
implicit none
private

public :: calling_abort_A
contains

subroutine calling_abort_A()

call f90wrap_abort("Aborting from A")

end subroutine

end module m_test_A
14 changes: 14 additions & 0 deletions examples/test_abort_buffer/main_B.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module m_test_B
implicit none
private

public :: calling_abort_B
contains

subroutine calling_abort_B()

call f90wrap_abort("Aborting from B")

end subroutine

end module m_test_B
21 changes: 21 additions & 0 deletions examples/test_abort_buffer/tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import unittest

# The import order is important here
# If pywrapper_main_A is imported first everything is good
# If pywrapper_main_B is imported first a segmentation fault occurs
from pywrapper_main_B import m_test_b
from pywrapper_main_A import m_test_a

class TestCallAbort(unittest.TestCase):

def test_call_abort_a(self):
with self.assertRaises(RuntimeError):
m_test_a.calling_abort_a()

def test_call_abort_b(self):
with self.assertRaises(RuntimeError):
m_test_b.calling_abort_b()

if __name__ == '__main__':

unittest.main()
43 changes: 43 additions & 0 deletions f90wrap/abort_buffers.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/* custom abort handler - James Kermode <james.kermode@gmail.com> */

#ifdef __cplusplus
extern "C"
{
#endif

#include <setjmp.h>
#include <stdlib.h>
#include <string.h>

#define ABORT_BUFFER_SIZE 1024
jmp_buf environment_buffer;
char abort_message[ABORT_BUFFER_SIZE];

void f90wrap_abort_(char *message, int len_message)
{
int copy_len = len_message < ABORT_BUFFER_SIZE - 1 ? len_message : ABORT_BUFFER_SIZE - 1;
strncpy(abort_message, message, copy_len);
abort_message[copy_len] = '\0';
longjmp(environment_buffer, 0);
}

// copy of f90wrap_abort_ with a second underscore
void f90wrap_abort__(char *message, int len_message)
{
int copy_len = len_message < ABORT_BUFFER_SIZE - 1 ? len_message : ABORT_BUFFER_SIZE - 1;
strncpy(abort_message, message, copy_len);
abort_message[copy_len] = '\0';
longjmp(environment_buffer, 0);
}

void f90wrap_abort_int_handler(int signum)
{
char message[] = "Interrupt occured";
f90wrap_abort_(message, strlen(message));
}

#ifdef __cplusplus
}
#endif

/* end of custom abort handler */
7 changes: 7 additions & 0 deletions f90wrap/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@ py3.extension_module(
link_args: link_args,
)

shared_library(
'_abort_buffers',
'abort_buffers.c',
install: true,
install_dir: py3.get_install_dir() / 'f90wrap',
)

py3.install_sources(
'build.py',
'codegen.py',
Expand Down
Loading
Loading