2.14 Building a shared library

This section describes building a tiny shared library implemented in Modula-2 and built with libtool. Suppose a project consists of three definition modules and three implementation modules a.def, a.mod, b.def, b.mod and c.mod. 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 INIT_ORDER should not be changed as it defines the initialization order of the core base modules. The define USER_LIB is the name of the library dialect and maybe changed if required.

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

#define INIT_ORDER "m2iso:RTentity,m2iso:Storage," \
                   "m2iso:SYSTEM,m2iso:M2RTS," \
                   "m2iso:RTExceptions,m2iso:IOLink"

#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,
                                INIT_ORDER, 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