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.
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 … |
|
|
|
|
|
|
|
|
|
|
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.