Skip to content

Commit cebd7b1

Browse files
committed
add error handling example
cmake/meson: add linker language parameter meson needs link fortran
1 parent b81799b commit cebd7b1

File tree

9 files changed

+100
-14
lines changed

9 files changed

+100
-14
lines changed

README.md

+14-9
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,17 @@ https://stackoverflow.com/tags/fortran-iso-c-binding/info
2525
In general, CMake >= 3.14 has better link resolution than CMake 3.13.
2626
In general, strongly avoid the FortranCInterface of CMake and mangling function names--just use Fortran 2003 standard `bind(C)`
2727

28-
## MacOS
28+
## build
29+
30+
```sh
31+
cmake -B build
32+
33+
cmake --build build
34+
35+
ctest --test-dir build
36+
```
37+
38+
### MacOS
2939

3040
For MacOS with Apple's Clang and Homebrew GCC,
3141
be sure you have in ~/.zshrc like the following:
@@ -38,12 +48,7 @@ export CXXFLAGS=-I$CPLUS_INCLUDE_PATH
3848
export CFLAGS=$CXXFLAGS
3949
```
4050

41-
## build
42-
43-
```sh
44-
cmake -B build
51+
## Error handling in Fortran with C/C++ main program
4552

46-
cmake --build build
47-
48-
ctest --test-dir build
49-
```
53+
Using Fortran statement "stop" or "error stop" with a C/C++ main program results in segmentation fault across compilers and operating systems.
54+
Instead, return an error code from Fortran subroutine to the C/C++ main program, and let C/C++ handle the error.

cmake/compilers.cmake

+5
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,8 @@ if(CMAKE_Fortran_COMPILER_ID STREQUAL GNU)
1818
string(APPEND CMAKE_Fortran_FLAGS " -fimplicit-none")
1919
add_compile_options(-Wextra -Wall)
2020
endif()
21+
22+
23+
if(NOT EXISTS ${PROJECT_BINARY_DIR}/.gitignore)
24+
file(WRITE ${PROJECT_BINARY_DIR}/.gitignore "*")
25+
endif()

src/CMakeLists.txt

+19-2
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,28 @@ add_executable(fortran_call_c fortran/main.f90)
1616
target_link_libraries(fortran_call_c PRIVATE math_c)
1717
add_test(NAME Fortran_call_C COMMAND fortran_call_c)
1818

19+
# -- C calling Fortran
20+
add_executable(c_fortran_error c/error_main.c)
21+
target_link_libraries(c_fortran_error PRIVATE error_fortran)
22+
# LINKER_LANGUAGE option is necessary for ifort at least
23+
set_target_properties(c_fortran_error PROPERTIES LINKER_LANGUAGE C)
24+
add_test(NAME C_Fortran_error COMMAND c_fortran_error)
25+
1926
# -- C++ calling Fortran
2027
add_executable(cxx_call_fortran cxx/main.cxx)
2128
target_link_libraries(cxx_call_fortran PRIVATE math_fortran)
22-
add_test(NAME C++_call_Fortran COMMAND cxx_call_fortran)
29+
add_test(NAME C++_Fortran_math COMMAND cxx_call_fortran)
30+
31+
add_executable(cxx_fortran_error cxx/error_main.cxx)
32+
target_link_libraries(cxx_fortran_error PRIVATE error_fortran)
33+
# LINKER_LANGUAGE option is necessary for ifort at least
34+
set_target_properties(cxx_fortran_error PROPERTIES LINKER_LANGUAGE CXX)
35+
add_test(NAME C++_Fortran_error COMMAND cxx_fortran_error)
36+
37+
# -- test wrapup
38+
39+
set_tests_properties(C++_Fortran_error C_Fortran_error PROPERTIES WILL_FAIL TRUE)
2340

24-
set_tests_properties(C++_call_Fortran Fortran_call_C Fortran_call_C++ PROPERTIES
41+
set_tests_properties(C++_Fortran_math C++_Fortran_error Fortran_call_C Fortran_call_C++ PROPERTIES
2542
TIMEOUT 5
2643
)

src/c/error_main.c

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// Example of Fortran erroring with C main
2+
3+
extern void error_fortran(int*);
4+
5+
int main(void) {
6+
int code = 42;
7+
error_fortran(&code);
8+
return 0;
9+
}

src/cxx/error_main.cxx

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// Example of Fortran erroring with C++ main
2+
3+
extern "C" void error_fortran(int*);
4+
5+
int main() {
6+
int code = 42;
7+
error_fortran(&code);
8+
return 0;
9+
}

src/fortran/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
add_library(math_fortran OBJECT math.f90)
2+
3+
add_library(error_fortran OBJECT error.f90)

src/fortran/error.f90

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
module utils
2+
3+
use, intrinsic :: iso_c_binding, only : c_int
4+
implicit none (type, external)
5+
6+
contains
7+
8+
subroutine error_fortran(value) bind(C)
9+
10+
integer(c_int), intent(in) :: value
11+
12+
error stop value
13+
14+
end subroutine error_fortran
15+
16+
end module utils

src/fortran/meson.build

+2
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
math_fortran = library('math_fortran', 'math.f90')
2+
3+
error_fortran = library('error_fortran', 'error.f90')

src/meson.build

+24-3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ subdir('fortran')
88
fortran_call_cxx = executable('fortran_call_cxx',
99
sources: files('fortran/main.f90'),
1010
link_with: math_cxx,
11-
link_language: 'fortran')
11+
link_language: 'fortran'
12+
)
1213
test('Fortran call C++', fortran_call_cxx, timeout: 5)
1314

1415
# -- Fortran calling C
@@ -19,8 +20,28 @@ fortran_call_c = executable('fortran_call_c',
1920
)
2021
test('Fortran call C', fortran_call_c, timeout: 5)
2122

23+
# -- C calling Fortran
24+
c_fortran_error = executable('c_fortran_error',
25+
sources: files('c/error_main.c'),
26+
link_with: error_fortran,
27+
link_language: 'fortran'
28+
)
29+
test('C Fortran error', c_fortran_error,
30+
timeout: 5,
31+
should_fail: true)
32+
2233
# -- C++ calling Fortran
2334
cxx_call_fortran = executable('cxx_call_fortran',
2435
sources: files('cxx/main.cxx'),
25-
link_with: math_fortran)
26-
test('C++ calling Fortran', cxx_call_fortran, timeout: 10)
36+
link_with: math_fortran
37+
)
38+
test('C++ call Fortran', cxx_call_fortran, timeout: 5)
39+
40+
cxx_fortran_error = executable('cxx_fortran_error',
41+
sources: files('cxx/error_main.cxx'),
42+
link_with: error_fortran,
43+
link_language: 'fortran'
44+
)
45+
test('C++ Fortran error', cxx_fortran_error,
46+
timeout: 5,
47+
should_fail: true)

0 commit comments

Comments
 (0)