How to Use C++ Modules in Clang

How do I use C++ modules in Clang?

Like you mentioned, clang does not yet have a C++ syntax for imports,
so I doubt that #include directives are going to be literally rewritten as imports when preprocessing a file, so that may not be the best way to test if modules are working as intended.

However, if you set -fmodules-cache-path=<path> explicitly, you can observe clang populating it with precompiled module files (*.pcm) during a build - if there are any modules involved.

You'll need to use libc++ (which seems to come with a module.modulemap as of version 3.7.0) if you want to use a modules enabled standard library right now - though in my experience this isn't working entirely just yet.
(Visual Studio 2015's C++ compiler is also supposed to get some form of module support with Update 1 in November)

Independently of the stdlib, you could still use modules in your own code. The clang docs contain a detailed description of the Module Map Language.

C++20 import modules with dot notation from main file in Clang

Solution it's pretty straightforward. In Clang, (at least in versions up to 14.0.4), you must explicitly include the -fmodule-file=<some_interface> for the module files that includes the dot notation in it's identifier.

So, for the main.cpp file build process, it must include -fmodule-file=./out/modules/interfaces/testing_core.pcm in the command line arguments.

Note: When an interface or implementation file depends on another module interface unit, you also must include the -fmodule-file indicating the dependency, even if the module identifier does not contains any dot in it's export module module_name.

Import std lib as modules with clang

The C++20 standard does not include module definitions for the C++ standard library. Visual Studio does (unfortunately), and a lot of bad sites out there will act like this is standard. But it's not; it's just a Microsoft thing.

If you want to include the C++ standard library through a module across platforms, you will have to either use import <header-name> syntax or write your own standard library modules that import the headers and export specific C++ declarations.

Link clang++ modules: Function exported using C++20 modules is not visible (clang++): Cannot compile executable file that uses module

You want to compile a module twice. Once to emit a module interface file (which should not have the .o suffix BTW; the customary suffix is .pcm, for "precompiled module") and once to emit an object file (with the customary .o suffix).

clang++ -std=c++20 -c f1_module.cpp -o target/f1_module.o # plain old object
clang++ -std=c++20 -Xclang -emit-module-interface \
-c f1_module.cpp -o target/f1_module.pcm # module interface

Now your module (consisting of two files) is ready, you can use it.

You need to compile the main file against the .pcm file and link the resulting objects against the .o file to produce an executable.

clang++ -std=c++20 -fprebuilt-module-path=./target \
-c f1_demo.cpp -o target/f1_demo.o
clang++ -std=c++20 target/f1_demo.o target/f1_module.o -o target/f1.exe

This is not strictly necessary. With clang, the precompiled module can be used as an object file. The linker however won't recognize it, so clang will need to convert .pcm to .o and feed the temporary .o to the linker, each time you link. This is somewhat of a waste so you may want to eliminate this conversion step by building a separate .o file as above. If you choose not to, you still need to mention the module file on the link line. The simplified process is like this:

clang++ -std=c++20 -Xclang -emit-module-interface \
-c f1_module.cpp -o target/f1_module.pcm # compile module once
clang++ -std=c++20 -fprebuilt-module-path=./target \
-c f1_demo.cpp -o target/f1_demo.o # compile main just as before
clang++ -std=c++20 target/f1_demo.o target/f1_module.pcm \
-o target/f1.exe # mention .pcm explicitly

As far as I know (and I don't know very much), there is currently no way to have clang find out automatically which modules to link against.

Clang can't find C++ module with `-fprebuilt-module-path`

For the following, I added some output to your main.cc so it looks like this, to demonstrate it's all working.

import S_mod;

#include <iostream>

int main() {
S s = { 1, 2 };
std::cout << s.x << " " << s.y << std::endl;
return 0;
}

You need to make sure all the names of your module artifacts are correct. For you, main.cc expects to find S_mod, and by default, Clang expects to find something named S_mod.pcm for compilation.

So, for example, this set of commands would work correctly because you'd be outputting a .pcm file with the same name as the module you're trying to import.

clang++ -std=c++20 -fmodules-ts --precompile -x c++-module S.cc -o S_mod.pcm
clang++ -std=c++20 -fmodules-ts -c S_mod.pcm -o S_mod.o -fprebuilt-module-path=.
clang++ -std=c++20 -fmodules-ts -fprebuilt-module-path=. main.cc -o test
./test
1 2

Alternatively, you can specify -fmodule-file which allows you to specify the mapping of module_name=module_file.

clang++ -std=c++20 -fmodules-ts --precompile -x c++-module S.cc -o S.pcm
clang++ -std=c++20 -fmodules-ts -c S.pcm -o S.o

# Notice that we map S_mod=S.pcm - you could just say S.pcm but
# then clang will always load the module file regardless of whether
# or not it needs to
clang++ -std=c++20 -fmodules-ts -fprebuilt-module-path=. -fmodule-file="S_mod=S.pcm" main.cc -o test
./test
1 2

How to compile/use header unit modules under CLang C++?

Finally I managed to solve almost task above.

Instructions below are for Windows 64-bit, most recent CLang from LLVM 12.0 release (which you can get here) and most recent MSVC Community Build Tools 2019 v16.9.4 (which you can get from here).

Note. This answer is for CLang only, I also wrote similar answer for MSVC.

I solved task not exactly for header units but for header modules, which behave almost same, there is no difference in their usage.

Toy example files below:

module.modulemap:

module mod {
requires cplusplus17
header "mod.hpp"
export *
}

mod.hpp:

#include <iostream>

use.cpp:

import mod;

int main() {
std::cout << "Hello, world!" << std::endl;
}

I used next 3 commands:

clang++.exe -cc1 module.modulemap -o prebuilt/mod.pcm -emit-module -fmodules -fmodule-name=mod -std=c++20 ^
-internal-isystem "d:\\bin2\\Microsoft Visual Studio\\2019\\BuildTools\\VC\\Tools\\MSVC\\14.28.29910\\include" ^
-internal-isystem "C:\\Program Files (x86)\\Windows Kits\\10\\Include\\10.0.19041.0\\ucrt" ^
-debug-info-kind=limited -fms-extensions -fms-compatibility -fms-compatibility-version=19.28 -xc++ ^
-fmath-errno -fexceptions -fcxx-exceptions -triple x86_64-pc-windows-msvc || exit /b

clang++.exe -cc1 -emit-obj use.cpp -fmodule-file=prebuilt/mod.pcm -std=c++20 ^
-internal-isystem "d:\\bin2\\Microsoft Visual Studio\\2019\\BuildTools\\VC\\Tools\\MSVC\\14.28.29910\\include" ^
-internal-isystem "C:\\Program Files (x86)\\Windows Kits\\10\\Include\\10.0.19041.0\\ucrt" ^
-debug-info-kind=limited -fms-extensions -fms-compatibility -fms-compatibility-version=19.28 -xc++ ^
-fmath-errno -fexceptions -fcxx-exceptions -triple x86_64-pc-windows-msvc || exit /b

clang++.exe use.o -o use.exe || exit /b

which all worked without errors. You can see that there are full paths to include directories of standard library, these paths are specific to my system. This is needed because in commands I used -cc1 option which enabled to use low level CLang front end instead of simplified driver, this front end needs a lot of low-level options to work.

You can get all options just by doing clang++ -### use.cpp, this will dump to console all options that are needed for your system.

Commands above can be used with -cc1 front end only, driver doesn't support module map file.

Actually among those 3 commands above second command can be simplified, compiling object file doesn't need low-level front-end. But it can be simplified only in the case if 1st command has default params obtained by clang -### command, then 2nd command can be short-written as clang++ use.cpp -o use.o -c -std=c++20 -fmodule-file=prebuilt/mod.pcm.

Result of these commands is that use.o is compiled within a fraction of a second. It is known that iostream takes a lot of time to compile. Very fast compilation of use.o means that we used modules correctly and boosted our speed.

Why I wanted header units in the first place? To be able to upgrade my old code, just by automated replacing regular old-style includes with imports, to greatly improve compilation time. This replacement is only possible with header units or header modules. Regular modules can't export other full header as I know.

For further instructions regarding modules see CLang's Modules Doc and CommandLine Doc.

How to use Clang with C++ Modules in Windows 10

CMake does not support C++ modules. Once it is officially supported, you can expect it to work. Until than, the compiler or msbuild might do some magic, but you cannot rely on it.



Related Topics



Leave a reply



Submit