<normal_arglist> ::= " <module_name> "
[ , name, " <calls> " ]
[ , <module_data> ]
where module_name is the name of the module file; as soon as the file
is checked and the binding of the structure with function bindings
succeeded, a function called read is invoked, and passed the input
stream.
This function is in charge of reading module_data following the
general syntax of the input file.
An alternative form is
<normal_arglist> ::= reference , " <name> "
[ , <module_data> ]
where name is the name by which the loadable element recorded itself
when registered via the module load directive, as described
in Section 2.3.6.
As a consequence, the following forms are equivalent:
# direct runtime loading
loadable: 1, "/some/module.so";
# "/some/module.so" registers itself as "some_module"
module load: "/some/module.so";
loadable: 2, reference, "some_module";
# works also as joint (might obsolete loadable elements)
joint: 3, some_module;
It is advisable that the function read prints some help message when the first field of module_data is the keyword help. All the helpers and the high-level structures are available, such as drivers, constitutive laws, reference frames. Refer to each module for a description (if available) of the features and of the input/output format. module_name should be a full path to the module function. If the name starts with a slash ``/'', the full path name is used. Otherwise the module is searched in the colon-separated list of directories contained in the environment variable LD_LIBRARY, then among the libraries listed in /etc/ld.so.cache, and finally in /usr/lib and in /lib (see dlopen(3)). At last, it is searched in the current directory, and the extension .so is added if missing. The string calls represents the name of the structure that contains the bindings to the functions. The default is calls.
Refer to $(BASE)/mbdyn/base/loadable.h for a description of the functions that are allowed. An example module is given in directory
$(BASE)/modules/module-template/
which can be used as a starting point for building a custom module.
The loadable element interface allows to link modules in different
languages, e.g. C or FORTRAN77; simply use module-template
as a guideline to providing callbacks to the loadable element
interface and to collect required info from the main program
(e.g. node positions, equation indices and everything else that is
required for appropriate connection), then call the functions that
actually do the work in other languages from inside the callbacks.
Note that, in general, to call external functions from C++ one needs
to declare them as
#include <sys/types.h>
extern "C" {
int a_C_function(int arg, double darg);
int a_F77_subroutine(int32_t *iarg, double *darg);
}
The same applies to FORTRAN 77 functions; only, the naming convention
usually is compiler dependent; some compilers turn all the names to
uppercase or lowercase (remember that FORTRAN 77 is case insensitive);
other compilers add underscores at the beginning or at the end of the
names.
Check what is the behavior of your compiler, by compiling a simple
program with your favorite FORTRAN 77 compiler, then looking at it
with the utility nm(1), which will show how the symbols are represented
internally.
For instance, the code
C This is a compiler test
SUBROUTINE F77SUB(I, D)
INTEGER*4 I
REAL*8 D(*)
D(I) = 0.0
END
when compiled with g77(1) on a GNU/Linux system, yields:
[masarati@mbdyn manual]$ g77 -c f77sub.f [masarati@mbdyn manual]$ nm f77sub.o 00000000 T f77sub_That is, g77(1) lowercases all symbols, and adds a trailing underscore. Macros to automatically detect and take care of this behavior will be added.
To compile loadable modules, one needs to configure the package as follows:
./configure --with-module=<module_name>
where module_name is the name of the directory the module
is placed in with the module- part stripped; e.g. to compile
the tire module that resides in $(BASE)/modules/module-wheel2
one must type
./configure --with-module=wheel2
Multiple modules can be compiled by typing the list of the names
separated by blanks.
The modules need to resolve some of the symbols that are in the
main executable; until a full working libtool support is implemented,
this must be done by hand.
For the g++(1) compiler one requires the switch -rdynamic
to be added to the loader flags, e.g.
LDFLAGS="-rdynamic" ./configure --with-module=<module_name>
with sh(1) and compatible shells like bash(1), or
env LDFLAGS="-rdynamic" ./configure --with-module=<module_name>
with csh(1) and compatible shells.