icmodmap(1)

πŸ“¦
version 13.07.00 Β· 4 versions
, in arch rolling

πŸ’… icmodmap(1) β€” initializes C++ projects using modules ✨

okay bestie so this is the manual page for icmodmap, and it literally initializes the maintenance of C++ projects using modules. yes that's the whole NAME section, we move 🫢


🌸 SYNOPSIS 🌸

icmodmap [Options] [arg]

✨ DESCRIPTION ✨

so modules have been A Thing for a while now, but the Gnu g++ compiler still has a whole collection of bugs related to C++ modules (cf. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103524 😭). it's honestly possible that you'll stumble across some of these (or brand new ones, surprise!) when you're using modules. the good news? the number of reported bugs is gradually reducing, and the current state of affairs at least lets you gain some experience using modules. we love a work in progress πŸ”₯

here's the key thing: modules cannot mutually import each other. so there's always a linear, non-circular module hierarchy, and you have to acknowledge that when compiling files that define and use modules. icmodmap determines this order and prepares the construction of programs using modules. once icmodmap has done its job your favorite build-utility can be used as before, no cap.

just make sure that compilation uses the same C++ standard as used by icmodmap, and provide the -fmodules-ts compiler option when compiling source files. that part is not optional, bestie πŸ’…

icmodmap assumes that modules are defined in separate sub-directories. for your own documentation it's advised that filenames containing module (and partition) interface units start with mod (e.g., modsupport.cc). if a program defines two modules First and Second (e.g., in sub-directories first and second, and second/modsecond.cc imports module First) then first/modfirst.cc must be compiled before compiling second/modsecond.cc. this requirement is handled by icmodmap, so you don't have to think about it 🧚 once the source files containing module interface units have been compiled, the program's remaining source files can be compiled as usual.

by default icmodmap expects projects using modules to be organized this way:

  • 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. each sub-directory can (but does not have to) define a module, a module partition, a class (not part of a module, but maybe using modules), or other (source) files, maybe using modules;
  • if the project defines a program, the project's top-level directory contains source files (like main.cc) defining the main function. icmodmap also recognizes module interface units defined in the top-level directory (but, for clarity, module interface units should probably be defined in their own sub-directories πŸ‘‘);
  • since partitions define sub-components of modules, consider defining partitions in sub-directories of their module asub-directories. when adopting this organization then these sub-sub-directories are specified in the CLASSES file. e.g.,
module
module/part1
module/part2
  • modules and partitions may define classes (preferably one class per module, one class per partition). if so the member functions of those classes can be defined in the module or partition's directory.

icmodmap inspects each directory specified in the CLASSES file, including the top-level directory. it recognizes interface units and source files implementing module components. it ignores comment, but the individual parts of specifications can be separated by spaces or tabs but not by comment. e.g., export /* */ module Support; is not recognized. πŸ’€

when compiling source files containing interface units the compiler is called using at least the following options (see also the options --colors, --extension and --subdir in section Options):

/bin/g++ ${ICMAKE_CPPSTD} -fmodules-ts -c -Wall

if the environment variable ICMAKE_CPPSTD standard is not defined then the C++ standard used by default by the compiler is used. to define it use e.g., export ICMAKE_CPPSTD=--std=c++26.


πŸ¦‹ The program's argument πŸ¦‹

the program's argument can be omitted, or it can be specified in various ways:

  • when not specified icmodmap starts its mapping process, according to its default or explicitly specified options. e.g., when merely calling icmodmap it locates the project's source files containing interface units, determines their compilation order, and compiles those files in the determined order;
  • when specified as clean the project's gcm.cache sub-directory and the gcm.cache soft-links are removed. compiled object files (e.g., files under tmp/o) are not removed; removing those files is left to the used build-utility πŸ™ˆ;
  • when specified as - interface unit files are not compiled but their source file names are written in the required compilation order to the standard output stream;
  • otherwise icmodmap's argument is a filename to receive the names of the source files that would have been written to the standard output stream when argument - would have been specified.

πŸŽ€ OPTIONS πŸŽ€

icmodmap supports the following options:

  • --colors (-c) β€” by default the compiler is called using the option -fdiagnostics-color=never. when this option is specified the compiler messages may use colors 🌈;
  • --dependencies (-d) β€” the dependencies between modules are shown using this option. module defining source files are not compiled. icmodmap's output may look like this:
Dependencies:
   LOCAL module Square
   LOCAL module DepSquare
       imports LOCAL module Square

indicating that modules Square and DepSquare are defined by the current project, and the module DepSquare depends on the module Square.

it's also possible that modules depend on modules defined by other projects. in that case the output may look like this:

Dependencies:
   LOCAL module Square
       imports EXTERN module RectAngle
   LOCAL module DepSquare
       imports LOCAL module Square
   EXTERN module RectAngle

in this example module RectAngle is a module made available by some other project. the local module DepSquare, as before, depends on Square. in this example the RectAngle.gcm file must be available in the project's gcm.cache directory before module Square can be compiled (it's normally made available via a soft-link to the actual file) ⭐;

  • --extension=ext (-x) β€” ext is the extension of the source files inspected by icmodmap. by default it is .cc;
  • --extern=arg (-e) β€” when modules depend on externally available modules then the locations of the directories containing those .gcm files can be specified using this option. if those external .gcm files are all located in a single directory then the location of that directory (absolute or relative to the current project's top-level directory) can be specified by arg.

if those external .gcm files are located in multiple directories then the locations of those directories are specified in a file which is specified by arg. in this case each of arg's lines specifies the location of an external directory, ignoring empty lines and lines starting with //;

  • --help (-h) β€” provides usage info, returning 0 to the operating system πŸ’–;
  • --ignore=list (-i) β€” use this option instead of using the CLASSES file. when using this option all (one-level deep) sub-directories (and the project's top-level directory) are inspected except for those listed in the list argument. if list must specify multiple directories then surround the space-separated sub-directory names by quotes. to visit all sub-directories use '';
  • --library=lib (-l) β€” lib specifies the path (relative to the project's top-level directory) of a (library) file containing the project's .o files. to determine whether source files defining interface units must be (re)compiled their timestamps are not only compared to the timestamps of their object files but also to the timestamp of the library;
  • --mark=arg (-m) β€” arg can be +, ++, or a filename. when this option is used interface units depending on other modified interface units are also compiled πŸ”₯

if arg is ++ then the last write times of all files implementing or using those interface units are set to the current time.

if arg is neither + nor ++ then arg is the name of a file it receiving the names of the files otherwise processed by ++;

  • --quiet=what (-q) β€” by default the compiler calls and the dependencies are written to the std. output stream. specify what as:
    • c β€” to suppress showing the compiler commands;
    • d β€” to suppress showing the dependencies;
    • any other argument: both c and d.

--verbose suppresses --quiet;

  • --subdir (-s) β€” by default the project's tmp/o sub-directory receives the compiled interface unit files, using their CLASSES' compilation order number prefix (e.g., tmp/o/1modsquare.o, tmp/o/2modepquare.o, ...). when this options is specified the compiled files are located in the same sub-directory as their source files (in which case an order number prefix is not used);
  • --version (-v) β€” displays icmodmap's version πŸŽ€;
  • --verbose (-V) β€” shows additional output when determining the module compilation order and compiling the module definition files.

🌸 EXAMPLE 🌸

okay bestie, this is the part where it all comes together and honestly? it ate. πŸ’…

So the example defines a module Square living in its own sub-directory square, and that sub-directory contains this here modsquare.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;

main character module energy, no cap. ✨

Then there's the main function β€” it imports the Square module and uses its facilities. It also imports the iostream module-compiled system header. Heads up: icmodmap does not inspect that header, and it has to be available before main.cc can even be compiled. πŸ™ˆ Important! Here's 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’;

}

So when you run icmodmap -d, Square shows up as a local module, like this:

    Dependencies:
       LOCAL module Square

local legend behaviour honestly 🫢


And when you run icmodmap -V, it goes ahead and performs and shows you the compilation of square/module.cc, plus the names of all the source files that implement (declare) its components or that merely import the module. It's giving full receipts:

Defining a soft-link from gcm.cache/usr -> /usr
Inspecting square/
   scanning square1.cc
       declares module Square
   scanning amount1.cc
       declares module Square
   scanning square.cc
       declares module Square
   scanning square2.cc
       declares module Square
   scanning modsquare.cc
       defines module Square
   scanning amount2.cc
       declares module Square
   scanning lastsquared.cc
       declares module Square
Inspecting ./
   scanning main.cc
       imports module Square
Compiling...
   in square: /bin/g++ --std=c++26 -fdiagnostics-color=never  -c
        -fmodules-ts -Wall -o ../tmp/o/1modsquare.o modsquare.cc

like, it scanned everything and then compiled. main character energy fr fr πŸ”₯


πŸ‘€ SEE ALSO πŸ‘€

that's the whole list, bestie β€” one icon, but it's the blueprint πŸ’œ


πŸ’€ BUGS πŸ’€

None reported.

not a single one?? we love a clean sheet πŸŽ€ (if you find one though, that's a whole other conversation)


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

free as in freedom, periodt ✨


πŸ’– AUTHOR πŸ’–

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

the icon behind the icon, we stan 🫢


and that's a wrap on icmodmap(1), bestie!! this page is icmake.13.07.00, dated 1992-2026 β€” yeah, it's been iconic since before some of us were even born πŸ˜­πŸ’… go forth and map those modules. πŸ¦‹

πŸ“¦ where this page comes from