Modules cannot mutually import each other. Consequently there's always a
linear, non-circular module hierarchy, which should be acknowledged when
compiling files defining and using modules. In this section the requirements
for projects using modules are covered, as well as a procedure that can be
adopted when constructing such projects.

With modules traditional headers (tt(.h) files) should be avoided.  System
header files (cf. section ref(MODHDR)) still exist, but for those tt(import)
statements should be used or made available. For locally developed libraries
module-compiled header files can also be used (cf. section ref(LOCHDR)).

It can be difficult to determine which module sections can
immediately be compiled, and which ones depend on already compiled
sections. Moreover, source files belonging to modules but not defining their
interface units may import modules which aren't yet available when
compiling the module's interface unit. For example, module
tt(Basic's) interface unit is independent of other modules:
        verbinsert(-as4 examples/modmapdemo/basic/modbasic.cc)
    But a module tt(Second) imports tt(Basic) and therefore the compilation of
its module interface file depends on the availability of
tt(gcm.cache/Basic.gcm):
        verbinsert(-as4 examples/modmapdemo/second/modsecond.cc)
    Consequently tt(basic/modbasic.cc) must be compiled before compiling
tt(second/modsecond.cc). However, em(module) tt(Second) may export a em(class)
tt(Second), and an object of tt(class Second) em(could) be defined by a member
of the em(class) tt(Basic), exported by the tt(Basic) module:
        verbinsert(-as4 examples/modmapdemo/basic/hello.cc)

In such situations the module interface units must first, and in the right
order, be compiled. Then, once they are available the remaining source files
of the modules can be compiled.

This two-step process (first compile the module interface units in the right
order and then compile the remaining source files) quickly becomes a
challenge, which is commonly handled by using a emi(module mapper). Module
mappers inspect the modules of a project, building their dependency tree, and
maybe compiling the module interface units in the right order. The module
mapper bf(icmodmap)(1), a utility program of the bf(icmake)(1) project, is
such a module mapper.

By default (but configurable via options) bf(icmodmap)(1) expect projects
using modules to be organized as follows:
    itemization(
    it() The project's top-level directory contains a file tt(CLASSES), where
        each line (ignoring empty lines and bf(C++) comment) specifies the
        name of a sub-directory implementing one of the project's
        components. Partitions can be defined in their own sub-directories or
        in sub-directories of the module to which they belong. Sub-directories
        do not have to define modules, but all of the project's source files
        em(may) import modules;
    it() The top-level directory itself may also define a module;
    it() If the project defines a program, the project's top-level directory
        contains source files (like tt(main.cc) defining the tt(main)
        function);
    it() To simplify locating source files defining module or partition
        interface units it is advises to start their names with tt(mod),
        followed by the (optionally lower-case) name of the module or
        partition they define. Following this convention a module tt(Support)
        is defined in the file tt(modsupport.cc);
    it() It's considered good practice to export only a single class from a
        module or parition unit, but (like traditional header files) this is
        not a formal requirement.
    )

bf(Icmodmap)(1) inspects each of the source files in the project's top-level
directory and in each sub-directory specified in the tt(CLASSES) file. If a
source file's first line starts with tt(export module) it's a module or
partition interface unit. If so, its module or partition name is stored in a
data-base. Since module and partition interface units may themselves import
modules and/or partitions the current interface depends on those imported
components. Those imported components are declared in its data-base
registering that the current interface unit depends on those imported
components.

Likewise, if another source file imports modules or implements a component of
a module or partition then those modules (and/or paritions) are also declared
in its data-base.

Once all source files were inspected bf(icmodmap)(1) determines the module
dependencies: its data-base must indicate that each imported module or
partition also has a module/partition interface unit, and that there are no
circular dependencies among the module/partition interface units. If these
requirement are satified then bf(icmodmap) by default calls the compiler to
compile the interface units in their proper order. By default the object files
are stored in the standard bf(icmake)(1) fashion: each compiled interface unit
is stored in the project's tt(tmp/o) sub-directory and their names begin with
a number which is equal to the line number in the tt(CLASSES) file specifying
the inspected sub-directory (like tt(1modfirst.o, 2modsecond.o,)) using prefix
0 for module(s) defined in the project's top-level directory.

When the inspection and compilation successfully completes then the interface
units' object files are stoed in tt(tmp/o), and the project's top-level
directory contains a sub-directory tt(gcm.cache) containing the tt(.gcm) files
of all modules and partitions. In addition each inspected sub-directory has
received a soft-link tt(gcm.cache) to its parent's tt(gcm.cache)
sub-directory, so each of the project's source files can import each module.

Now that the module and parition interface files are available the remaining
source files can be compiled as usual. They can import and use the components
of the the defined modules (and where applicable the defined paritions).


COMMENT(
When files are modified the construction process recompiles those files as
usual. However, if a module's interface file is modified in such a way that
its interface is modified in such a way that its existing components (like the
data member organization of classes defined by the module or the parameters of
its functions) are modified then that module as well as the modules depending
on it must be recompiled. Merely adding new components to a module's interface
only requires recompilation of its tt(module.cc) file. bf(Icmodmap) by
default looks for a file tt(a) in a module's directory. If it exists then
tt(icmodmap) first checks whether this file exists. If so the module's files
as well as all components depending on the module are recompiled.
END)
