'Import std lib as modules with clang

I am experimenting with modules in clang, and would like to include the standard lib as modules instead of as includes.

Currently I do this

#include <iostream>
#include <string>

It seems that you in msvc should be able to import standard libs with for example

import std.core;

When using clang however this does not seem to be implemented, or implemented in another way.

My question is: Is it possible to import stl-includes like microsoft suggest, or is it possible to map standard lib includes to modules somhow.

Note: The reason I cannot use #include <...> or #import <...> is because of other errors that might get its own question. So I think that getting import std.core or similar is the way to go now if it is possible.

ModernesCpp also mentions std.core.



Solution 1:[1]

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.

Solution 2:[2]

I solved your task. Below are instructions for doing this. I did this on my Win 10 64-bit using CLang from current release of LLVM 12.0 (taken from here), also I have MSVC 2019 v16.9.4 Community installed (taken from here).

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

First create following files:

module.modulemap:

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

std_mod.hpp:

#include <iostream>
#include <map>
#include <set>
#include <vector>

use.cpp:

import std_mod;

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

In above file std_mod.hpp you can put any std headers that you need. You should put all possible STD headers that you use in all your projects, to be able to share same precomiled STD module everywhere.

Then execute command:

clang++ -### use.cpp -c -std=c++20 -m64 -g -O3 >use.txt 2>&1

Here instead of -std=c++20 -m64 -g -O3 you may use any options needed for your project. Every precompiled module should have same compilation options as other .cpp files to be able to be linked into final binary.

Command above will produce use.txt with options that you need to copy. In this options you should remove -emit-obj option, -o option (and path after it), also remove use.cpp. Then add to this command options string module.modulemap -o std_mod.pcm -emit-module -fmodules -fmodule-name=std_mod. On my system I got following resulting command:

"D:\\bin\\llvm\\bin\\clang++.exe" "-cc1" module.modulemap -o std_mod.pcm -emit-module -fmodules -fmodule-name=std_mod  "-triple" "x86_64-pc-windows-msvc19.28.29914" "-mincremental-linker-compatible" "--mrelax-relocations" "-disable-free" "-disable-llvm-verifier" "-discard-value-names" "-main-file-name" "use.cpp" "-mrelocation-model" "pic" "-pic-level" "2" "-mframe-pointer=none" "-fmath-errno" "-fno-rounding-math" "-mconstructor-aliases" "-munwind-tables" "-target-cpu" "x86-64" "-tune-cpu" "generic" "-gno-column-info" "-gcodeview" "-debug-info-kind=limited" "-resource-dir" "D:\\bin\\llvm\\lib\\clang\\12.0.0" "-internal-isystem" "D:\\bin\\llvm\\lib\\clang\\12.0.0\\include" "-internal-isystem" "d:\\bin2\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.28.29910\\include" "-internal-isystem" "d:\\bin2\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.28.29910\\atlmfc\\include" "-internal-isystem" "D:\\Windows Kits\\10\\Include\\10.0.19041.0\\ucrt" "-internal-isystem" "D:\\Windows Kits\\10\\include\\10.0.19041.0\\shared" "-internal-isystem" "D:\\Windows Kits\\10\\include\\10.0.19041.0\\um" "-internal-isystem" "D:\\Windows Kits\\10\\include\\10.0.19041.0\\winrt" "-O3" "-std=c++20" "-fdeprecated-macro" "-fdebug-compilation-dir" "D:\\t\\t4" "-ferror-limit" "19" "-fno-use-cxa-atexit" "-fms-extensions" "-fms-compatibility" "-fms-compatibility-version=19.28.29914" "-fdelayed-template-parsing" "-fno-implicit-modules" "-fcxx-exceptions" "-fexceptions" "-vectorize-loops" "-vectorize-slp" "-faddrsig" "-x" "c++"

As you can see this command contains full paths to includes, they are necessary. Execute command above, it will produce std_mod.pcm that you can use in your projects everywhere with same compilation options.

Why long command above is needed? Because using .modulemap file is possible only through -cc1 command, which executes low-level CLang front end instead of simplified CLang driver (driver is without -cc1 option). This low level front-end is possible to do many tricks which driver can't do.

Now you can compile your final program use.cpp that does import std_mod; by next command:

clang++ use.cpp -o use.exe -std=c++20 -m64 -g -O3 -fmodule-file=std_mod.pcm

See that I added -fmodule-file=std_mod.pcm - such option is needed for every imported module. As alternative you can use -fprebuilt-module-path=<directory> to specify where to search for all prebuilt modules.

Not long time ago I also created question and answer here regarding how to make modules out of headers in CLang.

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

PS. Why I implemented quite long solution above? Because at least on Windows' CLang next simple program

import <iostream>;
int main() {}

doesn't compile, it says use.cpp:1:8: error: header file <iostream> (aka 'd:\bin2\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.28.29910\include\iostream') cannot be imported because it is not known to be a header unit. So at least on Win one needs a special solution, solution with import <header-name>; doesn't work here.

All headers imported through import <header>; or import "header"; syntax should have special compiled header unit modules placed into special folder to be able to use. And on Win STD headers don't have corresponding compiled header unit modules. Also after spending many hours I didn't find a way in CLang how to create these so-called header units on Win. Only solution above solved my task of importing headers as modules.

Solution 3:[3]

I found where I got the Idea, llvms documentation. There is a section stating

"As an example, the module map file for the C standard library might look a bit like this:"

module std [system] [extern_c] {
  module assert {
    textual header "assert.h"
    header "bits/assert-decls.h"
    export *
  }

  module complex {
    header "complex.h"
    export *
  }

  module ctype {
    header "ctype.h"
    export *
  }

  module errno {
    header "errno.h"
    header "sys/errno.h"
    export *
  }

  module fenv {
    header "fenv.h"
    export *
  }

  // ...more headers follow...
}

It seems that you then name this file something.modulemap and send it to the compiler. A quick googling did not find any similar solution for msvc (other than std.io discussed earlier).

I have not tried it out yet, i guess i will accept my own answer when I have, or if somebody else comes up with something better.

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 Nicol Bolas
Solution 2
Solution 3 Lasersköld