icmodmap(1)

NAME
icmodmap - Initializes the maintenance of C++ projects using modules

SYNOPSIS
icmodmap [Options] start-directory

DESCRIPTION

Although modules have already been available for quite some time, the gnu g++ compiler still shows a number of bugs related to C++ modules (cf. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103524). So it’s possible that when using modules you will encounter some of these (or new) bugs. The bugs will probabably have been repaired in future releases of the compiler, and the current state of affairs at least allows you to gain some experience in using modules.

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. The icmodmap program determines this order and prepares the construction of modules used by programs.

Icmodmap assumes that modules are defined in separate sub-directories, and that module interfaces are defined in (by default) files named module.cc. If a program defines two modules First and Second (e.g., in sub-directories first and second and the second/module.cc imports module First then first/module.cc must be compiled before compiling second/module.cc. This is handled by icmodmap. Once the module.cc files have been compiled the remaining source files of the program can be compiled as usual.

Icmodmap expect projects using modules to be organized as follows:

o   The project’s top-level directory contains a file CLASSES, where each line (ignoring (C++) comment) specifies the name of a sub-directory implementing one of the project’s components. Alternatively a (subset) of the directory’s sub-directories can be specified. Each sub-directory can define a module, a module partition, a class (not part of a module, but maybe using modules), or global-level functions (also maybe using modules);

o   If the project defines a program, the project’s top-level directory contains source files (like main.cc) defining the main function. The top-level directory does not define a module, but its sources may use modules;

o   Sub-directories defining modules or partitions by default contain a file module.cc, defining the module’s name and its interface (instead of module.cc another file name can be specified);

o   Modules and partitions may define classes (one class per module, one class per partition). If so the member functions of those classes are defined in the module or partition’s sub-directory.

Icmodmap(1) inspects each specified sub-directory. If it contains the file module.cc (or its alternative name), then that file (having the following structure) is inspected:

o   its first non-empty line: defines the name of the module or partition;

o   import lines can specify system headers, modules and/or partitions.

OPTIONS

Icmodmap supports the following options:

o   --colors (-c)
    by default the compiler is called using the -fdiagnostics-color=never option. Use this option to suppress this option;

o   --dependencies (-d)
    the dependencies between modules is shown using this option. Module defining source files are not compiled. Icmodmap’s output may look like this:
        Square:l
        DepSquare: Square
    here, the :l suffix indicates that Square is a module defined by the project, not depending on other modules. When module definitions do depend on other modules they’re listed next: DepSquare is another module defined by the project, depending on the Square module.

    It’s also possible that modules depend on modules defined by other projects. In that case the output may look like this:
        Square:e
        Mod1: Square:e
        Mod2: Square:e Mod1
        Mod3: Square:e Mod1  Mod2
    In this example module Square is an external module, indicated by the :e suffix. All other modules depend on Square, and (e.g.,) Mod3 also depnds on the locally defined modules Mod1 and Mod2. In this latter example the Square.gcm file must be available in the project’s gcm.cache directory (it could be a soft-link to the actual file);

o   --help (-h)
    Provides usage info, returning 0 to the operating system;

o   --module=file (-m)
    By default modules are defined in module.cc source files. If modules are defined in source files having other names then those names can be specified using this option. E.g., when modules are defined in interface.cc files then specify option --module interface.cc. Using differently named module definition files is not supported;

o   --subdir (-s)
    By default the compiled module defining files are located in the project’s tmp/o sub-directory where each compiled file has received an compilation order number prefix (e.g., tmp/o/1module.o, tmp/o/2module.o, ...). When specifying the --subdir option the compiled files are located in the same sub-directory as the module defining files themselves (not using the order number prefix);

o   --version (-v)
    Displays icmodmap’s version.

o   --verbose (-V)
    Shows additional output when determining the module compilation order and compiling the module definition files.

EXAMPLE

The following program defines a module Square in its sub-directory square, containing this module.cc file:

export module Square;
export
{
    double square(double value);
    class Square
    {
        double d_amount;
        public:
            Square(double amount = 0);          // initialize
            void amount(double value);          // change d_amount
            double amount() const;              // return d_amount
            double lastSquared() const;         // returns g_squared
            double square() const;              // returns sqr(d_amount)
    };
}
double g_squared;

The main function imports the Square module and uses its facilities. It also imports the iostream module-compiled system header. That header is not inspected by icmodmap, and must be available before the main.cc file can be compiled. Here is the main.cc source file:

import Square;
import <iostream>;
int main(int argc, char **argv)
{
    std::cout << "the square of " << argc << " is "
                                        << square(argc) << ’\n’;
    Square obj{12};
    std::cout << "the square of 12 is " << obj.square() << "\n"
                "the last computed square is " <<
                obj.lastSquared() << ’\n’;
}

Executing icmodmap -d . shows Square as a local module:

    Square:l

Executing icmodmap -V . shows the compilation of square/module.cc:

    Module: Square
    square:
    /bin/g++ --std=c++26 -fdiagnostics-color=never  -c -fmodules-ts
            -Wall -o ../tmp/o/1module.o module.cc

It also defines the gcm.cache subdirectory, containing Square.gcm and a soft-link usr -> /usr, and because of this soft-link the compiler finds the module-compiled system header files. It also defines the soft-link square/gcm.cache -> ../gcm.cache: those soft-links are defined in all sub-directories used by the program, allowing all source files in all of the program’s sub-directories to import all modules defined in the main directory’s gcm.cache directory.

SEE ALSO
icmake(1).

BUGS
None reported.

COPYRIGHT
This is free software, distributed under the terms of the GNU General Public License (GPL).

AUTHOR
Frank B. Brokken (f.b.brokken@rug.nl).