Modules and exports (The GNU Algol 68 Compiler)

#### 2.2.4 Modules and exports ¶

As we have seen, each Algol 68 source file contains either a particular program or a prelude packet. Prelude packets consist on the definition of a single top-level module, that is itself identified by a module indicant.

Consider for example a source file called `trilean.a68` that implements strong Kleene three-valued (“trilean”) logic. It does so by the mean of a definition module called `Trilean`. A sketch of such a file may look like this:

    module Trilean =
    def
        pub mode Tril = int;

        pub Tril dontknow = 0, yes = 1, no = 2;

        pub prio AND3 = 3, OR3 = 3, XOR3 = 3;

        pub op NOT3 = (Tril a) Tril:
           (a + 1 | dontknow, no, yes);

        C ... other definitions ... C

        skip
    fed

The module indicant `Trilean` identifies the module. If we now compile this file to an object file using GCC:

    $ ga68 -c trilean.a68

The result of the compilation is an object file `trilean.o`, plus some exports information which is placed in a section in the object file, named `.a68_exports`. The exports information describes the interface provided by the `Trilean` module defined in the compilation unit. This includes all the modes, identifiers, priorities, operators, etc, that are publicized by the module. The particular encoding used to hold these exports is highly compact and not easy readable by persons; instead, it is designed to be read back by GCC when it builds another compilation unit that, in turn, needs to access the `Trilean` module.

Consider the following sketched particular program that resides in a source file `main.a68`, and that uses trilean logic:

    access Trilean
    begin
          C ... C
    end

When this program gets compiled by GCC using `ga68 -c program.a68`, the compiler finds the access clause and needs to locate some exports for the module `Trilean`. To do so, it searches in the modules search path, composed by the current working directory, some system directories and all directories specified in `-I` and `-L` options, looking for files called `trilean.m68`, `trilean.so`, `trilean.a` and `trilean.o`, in that order, where:

`trilean.m68`

  Is a stand-alone file expected to contain export data for one or more modules.

`trilean.so`

  Is a DSO, or shared object, expected to contain a `.a68_exports` section with exports data for one or more modules.

`trilean.a`

  Is an archive, whose constituent object files may contain `.a68_exports` sections with exports data for one or more modules.

`trilean.o`

  Is an object file expected to contain export data for one or more modules in a `.a68_exports` section.

The files are tried in order, and if export data for the requested module `Trilean` is found, it is read in, decoded, and used to compile `main.a68` into `main.o`.

The last step in obtaining an executable for our program would be to use GCC to do a link like `ga68 trilean.o main.o -o main`.

Module indicants such as `Trilean` are bold words in the language. This means that, independently of the stropping regime used, they are constituted by a bold letter followed by a sequence of zero or more bold letters and digits. Using the modern stropping supported by the GNU Algol 68 compiler, this means that all of `Trilean`, `TRILEAN` and `Tri_lean` denote exactly the same module indicant, trilean.

The mapping from module indicant to the “base name” used to locate the module exports is quite straightforward: the bold letters are transformed to lower-case letters, and the bold digits are just normal digits. Therefore, the exports for the module `GRAMP_Grammar` would looked in files `grampgrammar.m68`, `libgrampgrammar.so`, etc.

But often this default, straightforward mapping, is not what we need.

Suppose for example that a shared object installed in the system, `liba68goodies.so`, provides many facilities in the form of several modules, including a `Trilean` module. We want to use the trilean implementation of liba68goodies in our program `main.a68`. If we just `access Trilean` GCC will look for `trilean.m68` etc, but wont even consider looking in `liba68goodies.so`. Accessing `A68Goodies` is obviously not a solution, as the module we want is `Trilean` and there may not even be a module called `A68Goodies` in `liba68goodies.so`.

The solution for this is to use the modules map of the compiler. This map is an association or map between module indicants and base-names. When it comes to access some module, the compiler looks in the map. If there is an entry for the module’s indicant, then it fetches the base-name to use for looking for the module’s export data. If there is not an entry for the module’s indicant then the default, straightforward mapping described above is attempted.

By default the map is empty, but we can add entries by using the `-fmodules-map=` and `-fmodules-map-file=` command-line options. The first option expects entries to be added to the map in a string in the command-line, whereas the second option expects the name of a file containing the entries to add to the map. In both cases the format describing the entries is exactly the same (see Module search options).

In our case, we could compile our main program specifying an entry in the map telling the compiler where to find the trilean and logging modules:

    $ ga68 -fmodules-map="a68goodies=Trilean,Logger" -c main.a68