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

Viewed 589

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")?

2 Answers

[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.

I do not know any way for gcc to do it, but i would suggest writing a helper script that expands the file and looks for everything named import, then you might need to sort imports using " and < and output them as headers.

Then you need to find which files exporting the selected module to match that with your import. That is you need to go through the expanded files and find statements beginning with export module.

You expand files with

g++ -E {include flags, standard version etc} > tmpfile

-E works with clang++ aswell, but for msvc you need /E

If there is a direct way to do this with gcc I would also be interested to know, but the question then arises: How do gcc know where to look for the modules?

On the contrary if you have a build system that keeps track of where each module is located you can specify that as with compile commands. (With clang you specify this with -fmodule-file= i think it is the same with gcc, but have not tested). At least that is how I have done in my build system.

But to summarize my answer to your question. I think you need to:

  • Expand your source files
  • Find all files with import, export import and export module in them and process them.
Related