Calling common POSIX functions from Fortran
Rafik_Zurob 270003B2DK Visits (2019)
real x(10) pointer(p, x) p = malloc(40) if (p == 0) then ! malloc error. Print errno print *, "malloc failed. errno=", errno() call exit(1) endif x = [10.0, 5.0, 4.0, 7.0, 2.0, 1.0, 3.0, 6.0, 9.0, 8.0] print *, x call free(p) end
The reason is that malloc, errno, exit, and free do not have an explicit interface. So the compiler assumes that the arguments are passed by reference. For malloc, the compiler assumes that the argument and the result are of type integer(4). The call to exit will not clean up Fortran I/O buffers. The call to errno might not always work because on some systems errno is a C macro, not a function.
XLF 3.1 provided some wrappers in the XL Fortran library for some of these functions. For example, exit_ in the XL Fortran library cleans up Fortran I/O buffers and then calls the system's exit function. ierrno_ in the XL Fortran library provides access to the system's errno, even when it's a macro. To use these wrappers, however, you have to remember to add the underscore suffix or use the -qextname compiler option. Since -qextname appends an underscore suffix to all user procedure names, this might lead to complications when linking to third party libraries that don't provide names with a trailing underscore.
I think a better solution is to use the C interoperability features of the Fortran 2003 standard to provide proper interfaces for these system functions. I've done just that: I've created a module called xlf_posix_bindings that provides bindings for the following POSIX functions:
This module is designed to work even without the -qextname compiler option, so you don't have to worry about the effect of -qextname on your link step.
The code above can be rewritten using the module as follows:
use xlf_posix_bindings use, intrinsic :: iso_c_binding, only: c_size_t implicit none real x(10) pointer(p, x) p = malloc(40_c_size_t) if (p == 0) then ! malloc error. Print errno print *, "malloc failed. errno=", errno() call exit(1) endif x = [10.0, 5.0, 4.0, 7.0, 2.0, 1.0, 3.0, 6.0, 9.0, 8.0] print *, x call free(p) end
The module source, .mod files (for use with XL Fortran 11.1 and above), and usage example are available from the downloads section: xlf_
If you look at the module source, you'll notice I used one non-standard feature, namely the IGNORE_TKR directive. This feature allowed me to skip argument checking for arguments corresponding to void * in C. Looking forward, the Fortran Standards body is working on a technical report for further C interoperability that provides a standard way of interoperating with void * types.