next up previous contents
Next: Output Elements Up: Elements Previous: Joint Regularization   Contents


Loadable Element

The loadable element is a wrapper for a user-defined element that is compiled in a separated module and linked run-time. The module should provide a comprehensive set of functions with a specified API; default functions are available if no special features are required. Implementation of modules can be very easy, but a deep knowledge of the internals of the code is required if special tasks are required. There are virtually no limits on what a loadable element can do. The syntax is simply:
    <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.


next up previous contents
Next: Output Elements Up: Elements Previous: Joint Regularization   Contents
MBDyn: MultiBody Dynamics Software
Document version: 1.3.13
Last update: Wed Mar 3, 2010
Maintained by mbdyn@aero.polimi.it