10

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.

Lasersköld
  • 2,028
  • 14
  • 20
  • 2
    "*this does not seem to be implemented*" Of course it isn't; Clang generally does not implement random Microsoft extensions. And you *really* shouldn't use them. – Nicol Bolas Feb 28 '21 at 16:24
  • Possible dup: https://stackoverflow.com/q/33307657/6865932 – anastaciu Feb 28 '21 at 16:26
  • 1
    *The reason I cannot use #include <...> or #import <...> is because of other errors that might get its own question.* A very strange reason. Your code has errors and you are going to resolve them by using import. – 273K Feb 28 '21 at 16:44
  • 3
    @NicolBolas are you trying to missunderstand the question? To my understanding there should be some way to map stl-includes to c++20 imports, but I cannot find the page anymore, where i red it anymore. – Lasersköld Feb 28 '21 at 17:16
  • @S.M. Well if you want to solve that problem instead, please try. I do not think it is strange to ask if there is a standard way to solve problems: https://stackoverflow.com/questions/66411765/c-module-import-chain-results-in-strange-compiler-errorshttps://stackoverflow.com/questions/66411765/c-module-import-chain-results-in-strange-compiler-errors – Lasersköld Feb 28 '21 at 17:18
  • @anastaciu Hmm.. Will check if that solves the problem. – Lasersköld Feb 28 '21 at 17:21
  • https://stackoverflow.com/questions/66411765/c-module-import-chain-results-in-strange-compiler-errors – Lasersköld Feb 28 '21 at 17:35
  • Does [this page](https://learnmoderncpp.com/2020/09/05/where-are-c-modules/) help? – heap underrun Feb 28 '21 at 17:56
  • @Lasersköld: "*To my understanding there should be some way to map stl-includes to c++20 imports*" There is; it's called `import `. – Nicol Bolas Feb 28 '21 at 18:03
  • @NicolBolas, `import
    ` seems to be more a workaround until there is a standard way to import headers with for example `import std`. `import
    – Lasersköld Feb 28 '21 at 20:37
  • @NicolBolas If you know how to precompile multiple regular headers in a single translation unit please answer this question that I asked a long time ago. https://stackoverflow.com/questions/65236079/how-to-include-multiple-precompiled-headers-in-with-c20-with-modules-enabled – Lasersköld Feb 28 '21 at 20:40
  • @Lasersköld: "*import
    – Nicol Bolas Feb 28 '21 at 23:12
  • @NicolBolas when you say "the system" do you mean the build system, or that the headers should be precompiled already or that the compiler figures it out while compiling in multiple different processes. I can also guess how it could work, but some actual links to some documentation would be appreciated. – Lasersköld Mar 01 '21 at 11:07
  • @Lasersköld: "*do you mean the build system*" Yes, the build system. – Nicol Bolas Mar 01 '21 at 14:23
  • @NicolBolas And what flags do the build system send to the compiler to prepare and use it? (As you might know there is not very many build systems that supports c++-20 modules) – Lasersköld Mar 01 '21 at 21:04
  • 2
    Modularized standard Library is in priority list for c++23 – 0xB00B Nov 24 '21 at 16:14

3 Answers3

14

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 use import <header-name> syntax.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • That is probably right. Do you have any good idea how to export symbols from a included header file, you might be able to answer an older question nobody seemed to crack on the subject: https://stackoverflow.com/questions/66239902/using-legacy-header-files-as-c20-modules – Lasersköld Feb 28 '21 at 18:18
  • At least on Windows' CLang next simple program `import ; int main() {}` doesn't compile, it says `use2.cpp:1:8: error: header file (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 your solution with `import ;` doesn't work. Only my solution [described here](https://stackoverflow.com/a/67323138/941531) works on Win's CLang. – Arty Apr 29 '21 at 18:58
  • @Arty: "*Only my solution described here works on Win's CLang.*" This question is about the C++20 feature. And C++20 says that `import ;` works. If it doesn't work on a particular compiler, that is the fault of the *compiler* in failing to implement C++20 correctly. Clang's C++20 module support is not fully functional. – Nicol Bolas Apr 29 '21 at 20:31
  • 2
    @NicolBolas Thanks for reply! I though OP's question was very practical, meaning how to solve it on CLang (there is CLang in title and tags), also talking about MSVC means that OP is on Win. I didn't think it was theoretical about how it SHOULD be in standard C++20 on all compilers. – Arty Apr 29 '21 at 20:35
  • @Arty yes. When I asked the question I thought that `import std.xxx;` was the way to go, then I realized that `import ;` really was the right syntax. – Lasersköld Apr 30 '21 at 08:18
  • @Lasersköld Understood. I see you mentioned MSVC, so I thought you're on Windows, are you? Does `import ;` work for you on Windows Clang? – Arty Apr 30 '21 at 08:25
  • @Arty its a good guess, I should have specified it in the question. I mostly use msvc on windows, (somtimes i use msvc in linux too through a hack with wine) and I dont really use clang on windows. I have never solved how to use `import ;`. I posted a question here on SO, but nobody reacted to it: https://stackoverflow.com/questions/66577868/how-to-compile-c20-module-header-unit-with-clang – Lasersköld Apr 30 '21 at 08:30
  • @Lasersköld Actually I spent many hours trying to solve exact task of `import ;` and header units. And my final conclusion that in CLang it is only possible to create a-kind-of header unit through [this instructions](https://stackoverflow.com/a/67323138/941531). In fact described in these instructions resulting module is identical by behaviour to header unit. `import std_mod;` in my description is totally same as doing `import ;` and other headers. So I finally decided that in CLang I would use `import std_mod;` instead of `import ;`. – Arty Apr 30 '21 at 08:53
  • @Arty ok, maybe that is good enough for now then, At least the headers are precompiled. – Lasersköld Apr 30 '21 at 08:58
  • @Lasersköld Also just a notice - on MSVC I found a way to create my own header units. Of cause you can import Microsoft's `import std.io;` module, but it is nice to have ability to create your own header unit. For example on MSVC I managed to do `import ;` while providing my own precompiled header unit. – Arty Apr 30 '21 at 09:01
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/231775/discussion-between-laserskold-and-arty). – Lasersköld Apr 30 '21 at 09:06
  • so I write `import ;` and still get compiler errors in clang 17 and gcc 12. I don't see how that is an answer. – FalcoGer Jul 06 '23 at 10:38
  • @FalcoGer: Because it's supposed to work. The fact that some compilers aren't implementing it correctly doesn't change that the C++20 standard says that it ought to work. – Nicol Bolas Jul 06 '23 at 15:10
7

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.

Arty
  • 14,883
  • 6
  • 36
  • 69
  • 1
    After @NicolBolas response I started to realize that what we really want is to make the `import
    ;` syntax to work. And as you write, it's a bit sad that it is so hard to create compiler header units. I think it is nice to have a reference to how you could do in practice to import headers as modules, though so thanks for sharing your work.
    – Lasersköld Apr 30 '21 at 08:14
  • I did not write it in my, answer, but I am running clang on linux. But I guess that the syntax is somewhat the same. – Lasersköld Apr 30 '21 at 08:19
  • 1
    If you rename `module.modulemap` to `module.cc` then this command will generate `std_mod.pcm`: `clang -Xclang -emit-module -std=c++20 -c module.cc -o std_mod.pcm -fmodules -fmodule-name=std_mod` (tested on OS X, hopefully also works on Windows) – jjrv Dec 09 '21 at 16:20
  • @jjrv Thanks for trying out this on OS X. Didn't know that `.modulemap` can be successfully compiled as `.cc`, seems to be totally different languages. And what happens if you run same command but don't rename to `.cc`? Doesn't compile with some error? – Arty Dec 09 '21 at 16:25
  • @arty it's not compiled as `.cc`, but if the extension is `.modulemap` then the clang frontend will try to feed it to the linker which whines about an unsupported "binary" format. The cc1 backend will apparently notice it's a module map even if the extension is `.cc`. And `-emit-module` can be passed to cc1 through `-Xclang`. Also, at least on my machine you can actually leave out `-fmodules`. – jjrv Dec 09 '21 at 16:38
  • @arty Maybe this is better, this way you can still call it `module.modulemap`: `clang -Xclang -emit-module -std=c++20 -x c++ -c module.modulemap -o std_mod.pcm -fmodules -fmodule-name=std_mod` – jjrv Dec 09 '21 at 16:50
  • @jjrv Strange, now you pass option `-x c++` so for compiler it means that it is actually C++ format of source. Probably it has some heuristic how it guesses that it is actually modulemap format. Or maybe it is really some special flavor of C++ language (valid C++ program) inside CLang. – Arty Dec 09 '21 at 16:55
-1

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.

Lasersköld
  • 2,028
  • 14
  • 20
  • 1
    The site you are referencing is an older form of modules, based on an older, unaccepted proposal. I have no idea if it represents functionality in Clang, but it *definitely* doesn't represent C++20 modules. – Nicol Bolas Feb 28 '21 at 18:18
  • 2
    Ok, nice to know, but the question is about clang. Its sad that there is no standard way to do it though :/ – Lasersköld Feb 28 '21 at 18:20
  • "*Without even knowing if it is currently part of clang?*" Does it matter? Your question pertains to C++20's modules feature, and the document you're citing does not pertain to that. Whether it's still available in Clang or not is irrelevant; C++20 modules *don't work like that*. – Nicol Bolas Feb 28 '21 at 18:40
  • 1
    @NicolBolas Well if the topic of the question is "Import std lib as modules with clang" one could assume that the question is about clang, and not necessary about c++ in general. – Lasersköld Feb 28 '21 at 20:42
  • If that's the case, you shouldn't have tagged it with C++20 and C++-modules. You are either asking about the C++20 modules feature, as it applies to some version of Clang, or you're asking about Clang. – Nicol Bolas Feb 28 '21 at 23:13
  • @NicolBolas Well it is the c++20 module parts of clang I am asking about, so I cannot se the problem with those tags, but for what it is worth: sure, I could add a clang++-tag too. – Lasersköld Mar 01 '21 at 10:53
  • @NicolBolas Ok, After reading on reddit and seeing how people tries to grasp after all information they can get about modules, I have realized that your point is important. Its a bummer that the `import <...>` syntax is not that well implemented in compilers yet. – Lasersköld Mar 30 '21 at 16:05