0xStubs

System Administration, Programming and Reconfigurable Computing

Using the C++23 std Module with Clang 18

A feature introduced in C++20 is modules. With C++23, the standard library is now supposed to provide an std module that can be used instead of all the #includes that we are used to. This allows code like the following:

import std;

int main() {
  std::print("Hello world!\n");
}

While (partial) support for modules is included in GCC since version 11 and Clang since version 8, support for the std module is currently still lacking in libstdc++ and only included in libc++ since version 17 (see https://en.cppreference.com/w/cpp/compiler_support). But since I have Clang 18 and libc++ installed, I wanted to give it a try.

Simply trying to compile above code, unfortunately leads to an error:

% clang++ -std=c++23 -stdlib=libc++ -o test test.cpp 
test.cpp:1:8: fatal error: module 'std' not found
    1 | import std;
      | ~~~~~~~^~~
1 error generated.

One might be tempted to try Clang’s -fmodules flag but in fact this does not refer to modules as defined by the C++ standard and using it actually causes more issues:

% clang++ -std=c++23 -stdlib=libc++ -fmodules -o test test.cpp
test.cpp:1:1: error: import of module 'std' imported non C++20 importable modules
    1 | import std;
      | ^
test.cpp:4:8: error: no member named 'print' in namespace 'std'
    4 |   std::print("Hello world!\n");
      |   ~~~~~^
2 errors generated.

Most people experimenting with modules use CMake as build system and this is what is suggested by the libc++ documentation. However, the page also generally describes that we need to generate a BMI (Built Module Interface) file (.pcm) from the module sources (.cppm). A script posted in the LLVM discourse was very helpful in determining the necessary steps. First, the module header needs to be precompiled:

clang++ -std=c++23 -stdlib=libc++ \
    -Wno-reserved-identifier -Wno-reserved-module-identifier \
    --precompile -o std.pcm /usr/share/libc++/v1/std.cppm

The location of the cppm file may of course differ on different systems. Also, shipping the module source currently must be explicitly activated when building libc++. After precompiling the module, we can compile our program as follows:

clang++ -std=c++23 -stdlib=libc++ \
    -fmodule-file=std=std.pcm -o test std.pcm test.cpp

Note that we need to specify where the std module can be found via -fmodule-file and also need to specify it as an input file. All of this can of course be automated in a Makefile:

CXX = clang++
CXXFLAGS += -Weverything -Wno-c++98-compat -Wno-pre-c++20-compat
CXXFLAGS += -std=c++23 -stdlib=libc++

test: std.pcm test.cpp
	$(CXX) $(CXXFLAGS) -fmodule-file=std=std.pcm -o $@ $^

std.pcm: /usr/share/libc++/v1/std.cppm
	$(CXX) $(CXXFLAGS) -Wno-reserved-identifier -Wno-reserved-module-identifier --precompile -o $@ $^

Leave a Reply

Your email address will not be published. Required fields are marked *

Captcha loading...