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 $@ $^

Using the C++ bool type in HPC codes

When writing C++ code, you are probably inclined to use data types that are closest to what you are trying to express, expecting that this allows the compiler to provide the most efficient implementation possible. So, when processing boolean values, i.e., single-bit information distinguishing between true and false, you will likely want to use the bool type in C++. However, this bool type may behave in unexpected ways, in particular if you are working with codes that have to perform well and correctly in multi-threaded codes.

Read More