Building a shared library (The GNU Modula-2 Compiler)

### 2.14 Building a shared library ¶

This section describes building a tiny shared library implemented in Modula-2 and built with `libtool`. Consider a project consisting of three definition modules and three implementation modules `a.def`, `a.mod`, `b.def`, `b.mod`, `c.def` and `c.mod`.

    DEFINITION MODULE a ;

    END a.

    IMPLEMENTATION MODULE a ;

    FROM libc IMPORT printf ;

    BEGIN
       printf ("init: module a\n")
    FINALLY
       printf ("finish: module a\n")
    END a.

Module `b` is almost identical, but it imports module `a`.

    DEFINITION MODULE b ;

    END b.

    IMPLEMENTATION MODULE b ;

    IMPORT a ;
    FROM libc IMPORT printf ;

    BEGIN
       printf ("init: module b\n")
    FINALLY
       printf ("finish: module b\n")
    END b.

Likewise Module `c` is almost identical, but it imports from module `b`.

    DEFINITION MODULE c ;

    END c.

    IMPLEMENTATION MODULE c ;

    IMPORT b ;
    FROM libc IMPORT printf ;

    BEGIN
       printf ("init: module c\n")
    FINALLY
       printf ("finish: module c\n")
    END c.

The first step is to compile the modules using position independent code. This can be achieved by the following three commands:

    libtool --tag=CC --mode=compile gm2 -g -c a.mod -o a.lo
    libtool --tag=CC --mode=compile gm2 -g -c b.mod -o b.lo
    libtool --tag=CC --mode=compile gm2 -g -c c.mod -o c.lo

The second step is to link these objects into a shared library.

    export LIBDIR=$(gm2 -print-file-name=)../../../../lib64

    libtool --tag=CC --mode=link gcc -g a.lo b.lo c.lo \
      -L${LIBDIR} -rpath `pwd` -lm2pim -lm2iso -lstdc++ \
      -lm -o libabc.la

At this point the shared library `libabc.so` will have been created inside the directory `.libs`.

This library can be called from C++ using the following technique. The define `USER_LIB` is the name of the library dialect and maybe changed if required. The `DEFAULT_RUNTIME_MODULE_OVERRIDE` is a predefined string containing the default base core module initialization order.

    #include <stdio.h>
    #include <m2rts.h>

    #define USER_LIB NULL

    /* Add the runtime dependency for this file on modules a, b and c.  */

    void
    dep (void)
    {
      m2iso_M2RTS_RequestDependant (__FILE__, USER_LIB, "c", USER_LIB);
      m2iso_M2RTS_RequestDependant (__FILE__, USER_LIB, "b", USER_LIB);
      m2iso_M2RTS_RequestDependant (__FILE__, USER_LIB, "a", USER_LIB);
    }

    void
    init (int, char *[], char *[])
    {
      printf ("test.c:init\n");
    }

    void
    fini (int, char *[], char *[])
    {
      printf ("test.c:fini\n");
    }

    void
    construct_scaffold (int argc, char *argv[], char *envp[])
    {
      m2iso_M2RTS_RegisterModule (__FILE__, USER_LIB,
                                  init, fini, dep);
      m2iso_M2RTS_ConstructModules (__FILE__, USER_LIB,
                                    DEFAULT_RUNTIME_MODULE_OVERRIDE,
                                    argc, argv, envp);
    }

    void
    deconstruct_scaffold (int argc, char *argv[], char *envp[])
    {
      m2iso_M2RTS_DeconstructModules (__FILE__, USER_LIB,
                                      argc, argv, envp);
    }

    int
    main (int argc, char *argv[], char *envp[])
    {
      printf ("main starts\n");
      construct_scaffold (argc, argv, envp);
      printf ("main application goes here\n");
      deconstruct_scaffold (argc, argv, envp);
      printf ("main tidying up\n");
      return 0;
    }

This source file can be compiled and linked using the following command:

    export INCLUDE=$(gm2 -print-file-name=)/m2/m2iso
    g++ -I${INCLUDE} -g test.c -L. -l:.libs/libabc.so -L${LIBDIR} -lm2iso

and finally run using:

    LD_LIBRARY_PATH=.libs:${LIBDIR} ./a.out

    main starts
    init: module a
    init: module b
    init: module c
    test.c:init
    main application goes here
    test.c:fini
    finish: module c
    finish: module b
    finish: module a
    main tidying up