C/C++ and Fortran

 View Only

Calling common POSIX functions from Fortran

By Archive User posted Tue November 08, 2011 01:35 PM

  

Originally posted by: Rafik_Zurob


If you've tried calling system functions from a Fortran program, you might have run into difficulties because these functions don't have a Fortran interface. For example, the following code will fail execution:
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:

  • alarm
  • calloc
  • clock
  • errno (even on systems where errno is a macro)
  • exit
  • free
  • getgid
  • getpid
  • getuid
  • malloc
  • qsort
  • realloc
  • sleep
  • time (tloc argument should be loaded via C_LOC from iso_c_binding)
  • umask
  • usleep

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_posix_bindings.tgz. I hope that you find it useful.

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.


0 comments
1 view

Permalink