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

It is said in docs that modules support in CLang is partial. I'm using CLang under Windows 64-bit from recent release of LLVM 12.0.

I successfully managed to use regular modules, (that you import through import modulename;).

But I haven't managed to create and use header unit modules, those that you import through import "header.hpp";. Can you suggest how to do that with examples?

For trying header units I created next toy files:

hello.hpp:

#include <vector>

use.cpp:

import "hello.hpp";

int main() {
    std::vector<int> v(123);
}

Then I successfully (I hope) compiled header unit hello.hpp into PCM file:

clang++ -std=c++20 -Xclang -emit-header-module -I. hello.hpp -o hello.pcm

Command ran without errors and produced hello.pcm. If you run command above without -o flag then file hello.hpp.gch is created.

Then I tried to compile use.cpp, but without success, somehow it can't recognize my header unit and/or can't find corresponding hello.pcm. I think I'm missing some special flags that show compiler that it is header unit. Next command was used:

clang++ -std=c++20 -fprebuilt-module-path=. -fmodule-file=hello.hpp=hello.pcm -I. use.cpp

Which gave compile error:

use.cpp:1:8: error: header file "hello.hpp" (aka './hello.hpp') cannot be imported because it is not known to be a header unit
import "hello.hpp";
       ^

Under MSVC I successfully managed to use regular modules and header unit modules. But not in CLang. Can you help me with that? Or tell me maybe CLang header units are not yet supported.



Solution 1:[1]

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.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1