5

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.

Arty
  • 14,883
  • 6
  • 36
  • 69

1 Answers1

7

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.

Arty
  • 14,883
  • 6
  • 36
  • 69
  • Nice answer. With `Clang` under any Unix system, I never had problem of `import ;` since `Clang13`. Problems arises with Windows always. No matters the fact of using gnu on the triple or msvc. Did you faced redefinition problems before implement your solution? Meaning... did you try to put all (or some) system headers in your `module.modulemap` file? – Alex Vergara Oct 14 '22 at 16:41
  • 1
    @AlexVergara I have written my own Build System (CMake is an example of build system, but my is a lot different). So in my Build System I was struggling for compile speed, hence I created pre-compiled module of ALL std headers, actually almost all. There were like 30 std lib headers in one module. Then my system was rewriting source files to remove ALL std lib `#include` lines and replacing them all with single `import std_lib;`. This worked for me for dozens of my huge C++ projects. No problems with **redefinition**. All used from std lib functions worked very well. – Arty Oct 14 '22 at 16:59
  • Do you know a similar solution for GCC? I tried to `export import` all standard headers from a `std` module. But it gives a lot of 'internal compiler error's. – Sourav Kannantha B Feb 08 '23 at 20:48
  • 1
    @SouravKannanthaB Unfortunately I don't. I only investigated solutions for MSVC and Clang. Never tried to work out solution on how modules work in GCC. Maybe some time later I'll put a look into that area. – Arty Feb 08 '23 at 20:51