C++ modules using clang

3.9k views Asked by At

As it looks like Clang is providing support for the modules TS. I tried this out using Clang, compiled from SVN (trunk), and it worked as expected.

I want to take it to the next step wrapping the catch library in to a module.

I tried to declare a module.modulemap in this way:

module Catch {
  header "catch/catch.hpp"
  export *
}

and main.cpp containing:

import Catch;

int main(int argc, char* const argv[])
{
  int result = Catch::Session().run(argc, argv);
  return result;
}

The compilation model states that "the binary representation of modules is automatically generated by the compiler on an as-needed basis."

Compiling main.cpp using clang-4.0 -std=c++1z -fmodules-ts main.cpp I get:

main.cpp:1:8: fatal error: module 'Catch' not found
import Catch;
~~~~~~~^~~~~
1 error generated.

Any idea how it could be solved?

1

There are 1 answers

0
Johan Boulé On BEST ANSWER

What is described on the documentation page you refer to (http://clang.llvm.org/docs/Modules.html) is actually not the module TS.

It's the non-standard hack of clang to leverage the precompiled headers infrastructure to make them modularly reusable. The trick is simply to allow precompiled headers to be loaded in any order, or even loaded after having already parsed some code. That's based on the assumption that previously parsed/loaded code shouldn't have any side effect of further precompiled code. Other more traditional PCH handlings can be considered too much pedantic in this regard and end up being far less flexible (i.e. far less modular) in that they require either one monolithic PCH that needs the be the first thing loaded (e.g. MSVC), or a chain of PCH with a fixed ordering (GCC).

The objective-C language is augmented with an @import keyword that effectively "include" all the files listed in the corresponding module.modulemap file (which actually means generating and/or loading the corresponding PCH file).

When the objective-C extension is not enabled, there's no import keyword, but you still have another trick in place: it intercepts #include preprocessor directives so that they instead "include" all the files listed in the corresponding module.modulemap file (which, again, actually means generating and/or loading the corresponding PCH file).

There are no module and export keywords (these only appear in module.modulemap files); everything is exported.

This modular-PCH hack is enabled with the -fmodules compiler flag.

It's valuable in that it helps with speeding up the build process on large codebases, and it also allows lazily preparing the transition of an old codebase towards the future modular structure, without requiring an instant rewrite of the whole world.

I doubt that it's being much used in production, apart from a few very-involved companies like google, which has knowable clang developers who can fix the bugs if needed.

To actually make your code work with this system, you need to either:

  • edit your main.cpp to use @import Catch; and use the following command to compile clang++ -fmodules -I . -xobjective-c++ main.cpp

  • edit you main.cpp to use #include "catch/catch.hpp" and use the following command to compile clang++ -fmodules main.cpp

With the first usage, notice the importance of correctly setting the preprocessor include paths with -I since the system will under the hood lookup for your module.modulemap files on the preprocessor paths, even if you don't write any #include directive in your code.

Technically, you can verify that the module system was effectively enabled by looking at the generated PCH files under the /tmp/org.llvm.clang.$USER/ModuleCache/ dir, as Catch-$HASHSUM.pcm. You may end up with several ones for the same module since the PCH are dependent (amgonst other things) on the compiler options that were used (e.g. the objective-C support in the above example). Clang manages this cache dir by itself; it even removes old unused files (anyway /tmp/ is also wiped out during boot).

As you found out, the new -fmodules-ts compiler flag effectively asks for the future module TS support we're all looking for. Note that it's hardly usable currently.

A question on how to use it was already asked and answered: Clangs C++ Module TS support: How to tell clang++ where to find the module file?