Introduction

Fortran is a well-known traditional language for scientific and engineering numerical simulations.

Lua (http://www.lua.org) is a modern lightweight embeddable language.

Luaf is the set of Fortran bindings to Lua.

Tip
Why to bind Fortran and Lua together?

Fortran has poor abilities to deal with intricate data structures. It is convenient to use Lua for configuration and some pre/postprocessing steps.

Or, for example, you want to specify some input functions (for example, material properties, space- and time-dependent terms etc). It’s better to take advantage of mature language for dealing with formulas instead of DIY interpeter in Fortran. See also: Greenspun’s tenth rule.

Fortran 2003/2008 provides so-called “interoperability with C” that allows creating transparent bindings to most of procedures with C interface. Thus some projects of Lua bindings in Fortran have been recently developed.

Similar projects

Rationale

This project aims to implement full-scale bindings of Lua API including facitilites to read configuration files and call user-defined functions. However, it can (and shall!) be used for configuration and extension of Fortran programs.

The secondary objectives include minimal dependencies and automation of bindings generation.

To do

The current version supports Lua 5.1. It is planned to make the bindings for Lua 5.2.

Lua API implemented

Almost all Lua 5.1 API functions, macros and constant defined in the Lua manual are implemented. In the following sections I describe the differences from C API.

Important
Please read the Interoperability issues section also. When in doublt, please read source file luaf.f90.

Functions

Bindings to all Lua functions including debug and auxiliary libraries are implemented, with the exception of variadic functions:

  • lua_pushfstring

  • lua_pushvfstring

  • luaL_error.

Variadic functions are not “interoperable” in the state-of-art Fortran standard and implementations.

Note
The bindings have the same names as corresponding C functions, except lua_yield. The latter was renamed to lua_yield1 to avoid conflicts with LUA_YIELD constant.

Macros

Almost all macros are implemented as Fortran functions. For some macros, it’s better to use corresponding Fortran wrapper. See the table below.

Instead of …​

Use …​

lua_pushliteral

lua_pushstring_f

lua_tostring

lua_tostring_f

lua_checkstring

lua_checkstring_f

lua_optstring

lua_optstring_f

lua_typename

lua_typename_f

Note
Rationale
All macros that return C string are replaced with wrappers returning Fortran string. As for lua_pushliteral, the length of Fortran string is always known. So there is no point to discriminate between “literals” and “strings”.
Warning
Macros luaL_addchar and luaL_addsize use C pointer arithmetics. They are implemented in a not completely portable way. See C pointers.
Important
Implemented macros use Fortran integral types and C strings. This is subject to change in the future.

Call-by-reference versions

For some functions:

  • lua_getallocf

  • luaL_register

  • luaL_checkoption

  • luaL_loadfile

  • luaL_dofile

argument can either point to input/output variable or be NULL. Therefore in addition to the “basic” binding which declares this argument as C pointer, the special version with suffix _r (e.g., luaL_loadfile_r) where the argument is passed by reference.

Fortran wrappers

I have written convenience wrappers for some functions and macros. The first reason to write wrapper is the conversion of function return value from C string passed as char * to Fortran string passed as INTENT(INOUT) dummy argument with some assumed length. The second reason is to pass the length of Fortran string (which is certainly known during the call) to lua…​lstring…​ functions where the explicit string length is desired.

All wrappers have the _f suffix appended to their names. They are declared as subroutines accepting Fortran integers and strings. Please consult the source file luaf.f90 for information.

Here is the list of convenience wrappers:

  • lua_typename_f

  • lua_tolstring_f

  • lua_pushstring_f

  • luaL_checklstring_f

  • luaL_optlstring_f

  • luaL_gsub_f

  • luaL_addstring_f

  • lua_tostring_f

  • luaL_checkstring_f

  • luaL_optstring_f

  • luaL_typename_f

Interoperability issues

C and Fortran have different type systems. This section deals with some explicit and implicit points of difference.

C and Fortran integers

Lua uses the four C integer types: int, long, size_t and lua_Integer, which is the same as ptrdiff_t.

In function bindings and their call-by-reference counterparts these types are mapped to Fortran kinds “as is”: C_INT, C_SIZE_T, C_INTPTR_T. See Fortran 2003/2008 reference for details. long is not used there.

In macros and convenience wrappers, INTEGER(8) is used for long and default INTEGER is used otherwise. This is reasonable assumption for present-day Fortran compilers.

C and Fortran strings

C strings are arrays of chars terminated by null char with the length unknown a priori. Fortran strings are special variant of CHARACTER type with LENGTH parameter greater than one. Their length is always known if the string variable is accessible.

Conversion subroutines

I have written four conversion subroutines between C and Fortran strings.

F_C_STR takes Fortran string and appends null char making it alike the C string. Note that it doesn’t return CHARACTER array but rather returns Fortran string of kind C_CHAR with length increased by one. Such string can be implicitly converted to CHARACTER(KIND=C_CHAR) array when passed as argument (see below).

Warning
C_CHAR character kind is assumed to be the same as default one. This is valid at least for GNU Fortran and Intel Fortran. Also, the length of C character is supposed to be 1 byte in the luaL_addchar and luaL_addsize macro implementations.

F_C_STRT does the same after trimming the original string.

C_F_STR unpacks the C string from TYPE(C_PTR) pointer to Fortran character buffer. The end of string occurs at the null char or if the buffer ends. The truncation flag and actual length are specified as dummy optional output arguments.

C_F_STRL does the same but actual string length is specified as input. Null character is ignored. Truncation is signalled as optional output flag.

String arguments

For function bindings (including call-by-value versions), C strings are mapped either as TYPE(C_PTR) pointers or as CHARACTER(KIND=C_CHAR, LEN=1) assumed-size arrays. In the latter case, Fortran 2003/2008 standard permits passing of CHARACTER(KIND=C_CHAR, LEN=*) strings as actual arguments by the so-called sequence association. So, you can just wrap the Fortran string with F_C_STR/F_C_STRT and pass it to function.

For macros, the things are currently the same.

Note
If the string length needs to be specified (e.g., in lua_pushlstring), use a wrapper.

Convenience wrappers expect Fortran strings as arguments.

String return values

For bindings, C strings returned by Lua functions are mapped to opaque TYPE(C_PTR) handle. The subroutines C_F_STR and C_F_STRL convert it to Fortran string. For simplicity, such functions always have wrappers.

C pointers

When C pointer doesn’t mean that argument is passed by reference, it is passed and returned as opaque TYPE(C_PTR) entity. This is sufficient for the most functions and macros. However, luaL_addchar and luaL_addsize macros use pointer arithmetics. To make it, the pointers are converted to (and back) C_INTPTR_T addresses with the TRANSFER intrinsic.

Warning
We assume that the TYPE(C_PTR) datum is physically the same as corresponding C pointer value and as the INTEGER(C_INTPTR_T) value. This assumption was tested for GNU and Intel Fortran compilers.

Fortran constants

Lua has constants which are defined in header files. Some are chosen during installation: LUA_MINSTACK and LUA_IDSIZE. The constant LUAL_BUFFERSIZE depends on OS parameters.

Since there is no way to read these header files in Fortran, you should specify the configuration constants in Fortran file luaf_conf.fi manually or generate this file with genconf utility (see Sources, Installation sections).

Source structure

The project consists of main file luaf.f90 and include files:

  • luaf_int.fi contains generated bindings,

  • luaf_const.fi contains generated definitions of constants,

  • luaf_conf.fi contains definition of configuration constants.

genconf (compiled from genconf.c source) is a simple tool to generate luaf_conf.fi from current Lua installation and system settings. It writes contents of luaf_conf.fi to stdout. The typical usage is:

gcc genconf.c -o genconf -I /usr/include/lua5.1
./genconf > luaf_conf.fi

Templates of configuration file are called luaf_conf_linux.fi and luaf_conf_win.fi. They contain default Lua values of LUA_MINSTACK and LUA_IDSIZE and system-specific buffer sizes LUAL_BUFFERSIZE.

There is also test directory which contains test file and build file for CMake.

Installation

No special installation is intended.

First, generate the file luaf_conf.fi. Or use template file and edit it by hand. Next, just copy the following files to your project:

  • luaf.f90

  • luaf_int.fi

  • luaf_const.fi

  • luaf_conf.fi

Then, include USE LUAF in your project where the bindings are required.

Please see test/CMakeLists.txt for example of compilation scenario. It includes auto-generation of luaf_conf.fi file.