Search code examples
c++gccc++20c++-modules

Is there a way to query direct module dependencies with gcc?


Given a module

// a-m.cc
export module A;

import B;
import C;

import "D.h";

...

Is there a way of invoking gcc (similar to what -M does for headers) that will list the direct dependencies on other modules and imported headers (i.e. B, C, and "D.h")?


Solution

  • [Edit]

    It seems we can invoke gcc with the flag -MMD, which also tracks module dependencies. Given an example project I have, I generated it like this:

    // partition.cpp
    export module partition;
    
    import :partition1;
    export import :partition2;
    export import :partition3;
    
    export void Hello1() { _Hello1(); }
    

    For some reason I needed to compile the module partitions before compiling the primary module interface (file shown above), but perhaps this can somehow be circumvented. I compile the above file like this:

    g++-11 -std=c++20 -fmodules-ts -c -MMD partition.cpp
    

    This generates a file partition.d listing module dependencies:

    partition.o gcm.cache/partition.gcm: partition.cpp
    partition.o gcm.cache/partition.gcm: partition:partition3.c++m \
     partition:partition2.c++m partition:partition1.c++m
    partition.c++m: gcm.cache/partition.gcm
    .PHONY: partition.c++m
    gcm.cache/partition.gcm:| partition.o
    CXX_IMPORTS += partition:partition3.c++m partition:partition2.c++m \
     partition:partition1.c++m
    

    Seems promising, but more research is needed.

    My own solution

    I have written / am writing such a tool. It can be found on github: https://github.com/alexpanter/cpp_module_parser.

    It is unfinished, but is actually working. If interest is shown, I will continue expanding it.

    I also have a bundle of small example projects with modules, intended as a starting point for further research: https://github.com/alexpanter/modules_testing

    GCC

    GCC looks for precompiled modules (BMI's) in a local directory: ./gcm.cache/usr/include/c++/11/iostream.gcm or (for local module units) ./gcm.cache/,/my-module.gcm.

    If user code imports a module, the the precompiled module unit must be already present in this directory, otherwise compilation will fail. It is, unfortunately (at least currently) not possible to specify another directory, or a custom directory per build command. This would be very practical, and I'm hoping the GCC devs will add it at some point. The gcm.cache/ directory is used by the default module mapper. It is possible to create one's own module mapper, but from the reading I have done this sounds like a complicated procedure since a module mapper is essentially a web server:

    Comparison

    Comparing to @Laserskjöld's answer, I think collecting preprocessor output would be a viable solution as well, since module import/export commands are recognized by the preprocessor. However, I do not think it is a good solution since it would be much slower than a tool such as what I have written. An example:

    module;
    
    #include <iostream>
    
    export module mymodule;
    
    import myothermodule;
    
    export
    {
        [...]
    }
    

    After preprocessing, this file will be ~100000 lines long, and all lines need to be processed by the preprocessor. But with my tool (or one that is potentially more efficient), only the first 9 lines will be read by the module-parsing tool, rest of the file will be ignored. Besides, the point of having modules is to be less dependent upon the preprocessor.