C++ Standard Library: A Matter of Import

C++ Standard Library: A Matter of Import

By Ian Bruntlett

Overload, 34(192):18-21, April 2026


Modules are a relatively new C++ feature. Ian Bruntlett documents what he did to get them working with an older gcc compiler.

Motivation

Bjarne Stroustrup’s current C++ primer, Programming: Principles and Practice Using C++ (PPP3) [Stroustrup24] uses C++ modules and my system’s gcc compiler does not support them. Bjarne has a habit of referring to very new facilities in his books – TC++PL2 (exceptions on Sun Workstations), I’m thinking of you! This article documents what I had to do to get ‘Hello World’ from PPP3 to build successfully on a different system’s Ubuntu Linux 24.04.3 (or later) LTS x86_64 with not much additional software installed.

Learners using PPP3 who are using the Gnu Compiler Collection (gcc) either have to resort to using #includes or somehow get to grips with using modules. The problem with #includes is that they can be really inefficient. This is because when a #include is encountered, that file’s contents – and the contents of any nested #includes – are compiled for each C++ source file (aka translation unit) being built that includes them. Modules provide a way to reduce that workload on the compiler whilst increasing the demands made on compiler authors.

This article relies on a collection of files to work. They will be made available on Github [Bruntlett].

Other build systems

There are all sorts of ways to optimise builds other than make. CMake is apparently the most popular build system generator but I am completely unfamiliar with it and my current goal is to work my way through Bjarne Stroustrup’s book (PPP3), so I used GNU Make.

Before you start

By the time you read this, your compiler might already support modules and so most of this article will be redundant to you. Try building greetings.cpp, included as Listing 5 in this article. If it fails and you get told to install a newer compiler, to misquote Lestat “I’m going to give you the article I never had”.

Getting import std; to work

For this article, initially I used Jonathan Wakely’s ‘Binary packages for GCC snapshots’ [Wakely] web page to get a more up to date, if somewhat experimental, compiler. To get access to the compiler, you download the latest snapshot .deb file from the web page.

I had to install a package, make, as well as the compiler. To install make, I used these commands:

  # get information on current packages
  sudo apt update 
  # update the system with current packages
  sudo apt upgrade 
  sudo apt install make

I created a makefile to automate building programmes and perform other tasks as well. In make, these tasks are called targets. For the sake of convenience, I added some extra targets in the makefile. If you’re not sure what targets are, simply view these extra targets as commands you can request from the makefile at the command line. (See Figure 1 for the usage of make.)

$ make help
makefile to build executables and also a bit of housework.
make hello-std  - make Hello World programme that does an import std;
make greetings  - a more modern Hello World programme.
make hello-ppp3 - make Hello World programme that uses the PPP module.
make all        - make module files and the example programmes.
make std.o      - make the standard library module files.
make PPP.o      - make utility module for the book PPP3 \(Stroustrup\).
make              from the book PPP3.
make clean      - delete the executable files and object files, typically done after updating the compiler.
make look-for-compiler - see what the current compiler version is
make get-the-compiler  - download the most recent compiler
module_std = /opt/gcc-latest/include/c++/16.0.0/bits/std.cc
g++ (GCC) 16.0.0 20260111 (experimental)
Figure 1

The command make look-for-compiler looks at the gcc-latest web page and tells you what the latest version is.

  $ make look-for-compiler
  Checking the current version of the compiler
  =================================================
  wget --spider --content-disposition https://
  kayari.org/gcc-latest/gcc-latest.deb 2>&1 | grep
  Location
  Location: https://kayari.org/gcc-latest/
  gcc-latest_16.0.1-20260222git6e35a5d5b297.deb
  [following]

The command make get-the-compiler downloads the latest gcc-latest .deb file only if it hasn’t been downloaded into the current directory already. (See Figure 2.)

$ make get-the-compiler
Only downloading the compiler if we don't already have it.
=================================================
wget --no-clobber  --content-disposition https://kayari.org/gcc-latest/gcc-latest.deb
--2026-02-26 09:17:08--  https://kayari.org/gcc-latest/gcc-latest.deb
Resolving kayari.org (kayari.org)... 176.126.242.131
Connecting to kayari.org (kayari.org)|176.126.242.131|:443... connected.
HTTP request sent, awaiting response... 302 Found
Location: https://kayari.org/gcc-latest/gcc-latest_16.0.1-20260222git6e35a5d5b297.deb [following]
--2026-02-26 09:17:08--  https://kayari.org/gcc-latest/gcc-latest_16.0.1-20260222git6e35a5d5b297.deb
Reusing existing connection to kayari.org:443.
HTTP request sent, awaiting response... 200 OK
Length: 463517736 (442M) [application/vnd.debian.binary-package]
Saving to: 'gcc-latest_16.0.1-20260222git6e35a5d5b297.deb'
gcc-latest_16.0.1-20260222git6e35a5d5b2 100%[========================================================================>] 442.04M  11.2MB/s    in 40s
2026-02-26 09:17:48 (11.2 MB/s) - 'gcc-latest_16.0.1-20260222git6e35a5d5b297.deb' saved [463517736/463517736]
Figure 2

The command to install the compiler, where ‘name-of-gcc-latest-file.deb’is replaced by the name of the .deb file you downloaded is:

  sudo apt install ./name-of-gcc-latest-file.deb

The makefile used in this article doesn’t need /opt/gcc-latest/bin to be on the PATH. However, I found it convenient. I used the shell script in Listing 1 to do so and to change to a working directory.

#!/bin/bash
if ! echo $PATH | grep gcc-latest/bin: - ; then
    echo gcc-latest not on path... putting it on
    set -x
    PATH=/opt/gcc-latest/bin:$PATH
    cd ~/gcc-new
    set +x
else
    echo gcc-latest already on path
fi
Listing 1

I invoke it on the command line with:

  source prepare-for-gcc-latest

or the briefer:

  . prepare-for-gcc-latest

I do this at the command line rather than in .bashrc because I don’t want to hide the standard gcc, which is relied upon by vlc and other packages.

You can use ‘TAB-completion’ for the command line as well. Type in the shortest unique prefix and then press tab for the command line to be auto-completed.

You can compile your own code (e.g. for another-example.cpp that uses the PPP module) by editing the makefile (see Listing 2) and adding something like this line:

  another-example: std.o PPP.o another-example.cpp
# makefile to use when working on examples for 
# Bjarne Stroustrup's book, "Programming 
# Principles and Practice Using C++" (3rd 
# Edition), working on examples using Ubuntu 
# 24.04.4 LTS x86_64.
#
# Ian Bruntlett, January 2026 - 26th February 
# 2026 9:50ish
# with help on the accu-general mailing list from 
# Jonathan Wakely
# and on the accu-members for people to test 
# these example programmes.
# Tell the C++ compiler to include debugging 
# information (-g), have # some useful warnings, 
# that modules are in use (-fmodules), and
# that we are using a bleeding edge version of 
# the C++ language.
# tell make where to find the C++ compiler
CXX = /opt/gcc-latest/bin/g++

# flags for the C++ compiler
CXXFLAGS = -g -Wall -Wshadow -Wconversion -fmodules -std=c++23

# the names of the programmes built using this 
# makefile
executables = hello-std hello-ppp3 greetings

# website address for gcc-latest, so we can check 
# its version - $ make look-for-compiler
# or download it - make get-the-compiler
compiler_link = https://kayari.org/gcc-latest/gcc-latest.deb

module_std=$(shell find /opt/gcc-latest/ -iname std.cc)

# linker flags, to locate library files without 
# having to set:
# export LD_LIBRARY_PATH=/opt/gcc-latest/lib64
LDFLAGS += -Wl,-rpath,/opt/gcc-latest/lib64

# if you want to create a linker map file for 
# extra info on your executables then uncomment 
# this line below:
# LDFLAGS += -Wl,-Map=$@.map
all : $(executables)

# Note that commands are preceded by a TAB 
# character and not a sequence of space 
# characters.
# Build a module for using the Standard C++ 
# Library
# gcm.cache/std.gcm - the 
# 'compiled module interface'
# std.o - contains the modules definitions.
std.o: $(module_std)
	$(CXX) $(CXXFLAGS) -c $(module_std)

# Build a module for using the examples from the 
# book PPP
# gcm.cache/ppp.gcm - the ‘compiled module 
# interface' for PPP extensions
# PPP.o - contains the PPP extensions definitions.
PPP.o: PPP.ixx
	$(CXX) $(CXXFLAGS) -c PPP.ixx

# build an executable file that uses the Standard # Library module
hello-std: std.o hello-std.cpp

# build an executable file that greets the user 
# using modern C++ facilities
greetings : std.o greetings.cpp

# build an executable file that uses the PPP 
# module from the book PPP3
hello-ppp3: std.o PPP.o hello-ppp3.cpp
.PHONY: clean
clean:
	rm -rfv gcm.cache/
	rm -fv $(executables) *.o *.map

# check to see the version information of the
# current compiler
.PHONY: look-for-compiler
look-for-compiler:
	@echo Checking the current version of the compiler
	@echo ====================================
	wget --spider --content-disposition $(compiler_link) 2>&1 | grep Location

# download the current compiler
.PHONY: get-the-compiler
get-the-compiler:
	@echo Only downloading the compiler if we don\'t already have it.
	@echo =========================================
	wget --no-clobber  --content-disposition $(compiler_link)
# display help message
.PHONY: help
help:
	@echo makefile to build executables and also a bit of housework.
	@echo "make hello-std  - make Hello World programme that does an import std;"
	@echo "make greetings  - a more modern Hello World programme."
	@echo "make hello-ppp3 - make Hello World programme that uses the PPP module."
	@echo "make all        - make module files and the example programmes."
	@echo "make std.o      - make the standard library module files."
	@echo "make PPP.o      - make utility module for the book PPP3 \(Stroustrup\)."
	@echo "make              from the book PPP3."
	@echo "make clean      - delete the executable files and object files"
	@echo "                  typically done after updating the compiler."
	@echo "make look-for-compiler - see what the current compiler version is"
	@echo "make get-the-compiler  - download the most recent compiler"
	@echo module_std = $(module_std)
	@$(CXX) --version | head -1

# PPP files from 
# https://stroustrup.com/programming.html
# a few programmes by me, a makefile, a 
# supporting shell script, and my draft article
module-article.tar.gz : PPP.ixx PPP.h PPP_support.h PPPheaders.h\
	hello-std.cpp hello-ppp3.cpp greetings.cpp \
	makefile prepare-for-gcc-latest \
	irb-cpp-stdlib-a-matter-of-import.odt \
	irb-delete-elves
	tar -czf $@ $^
Listing 2

Listing 3 contains is the code (hello-std.cpp) I used to test my environment.

/* hello-std.cpp
compile with:
make hello-std
Whilst Bjarne Stroustrup likes to use this in his examples:
  using namespace std;
I prefer not to do so. This is because in medium-sized programmes and larger, this can cause name collisions and headaches so I have to prefix names from the standard library with std::
*/
import std;
int main()
{
  std::cout << "System  : " ;
  std::flush(std::cout);
  std::system ("hostname");
  std::cout << "FILE    : "  __FILE__ " " 
    __DATE__  " " __TIME__ "\n";
  
  std::cout << "gcc     : "  << __GNUC__ << '.'
            << __GNUC_MINOR__ << '.'
            << __GNUC_PATCHLEVEL__  << '\n';
  
  std::cout << "standard: " <<  __cplusplus 
            << '\n';  
}
Listing 3

g++ currently implements modules by creating a gcm.cache directory and creates an ELF (Executable and Linker Format) file named after the module it contains – in this case std.gcm. To get extra information about the ELF file, you can use the command:

  $ readelf -a std.gcm | less

Getting PPP3 examples to build

This article only covers the building of text mode modules. Those PPP3 examples that use graphics with Qt will have to wait. I went to https://stroustrup.com/programming.html and downloaded PPP.ixx. PPP_support.h, and PPP.h – this gives you the means to build the PPP module. However, I got a compilation failure for PPP_support as size_t was not declared. To get this to work, I edited PPP.ixx to read as follows:

  export module PPP;
  
  export import std;
  
  using std::size_t; // added by me to get things 
                     // to build
  #define PPP_EXPORT export
  #include "PPP_support.h"
  using namespace PPP;

To see if I could access the PPP module, I then created a new file, hello-ppp3.cpp (Listing 4).

/* hello-ppp3.cpp
  Programme to use some of PPP3's code - in this 
  case, a checked string which will complain at 
  runtime when abused.
  compile with:
  make hello-ppp3
  
  Bjarne Stroustrup likes to use this in PPP.h:
   using namespace PPP;
   using namespace std;
  This makes code easier for a novice reader.
  I prefer not to do so. This is because in 
  medium-sized programmes and larger, this can 
  cause name collisions and headaches.
  However, PPP.h is used by this program which 
  means I can write cout instead of std::cout.
*/

#include "PPP.h" // Use Bjarne's PPP3 tutorial 
                 // module

int main()
{
  cout << "Hello from : "  __FILE__ "\n";
  // this line use's Bjarne's PPP::Checked_string 
  // because PPP.h does this preprocessor 
  // trickery:
  // #define string Checked_string

  string astring="Hello\n";

  cout << astring;
  cout << "About to get a deliberate runtime "
          "error\n";
  // get a runtime error, to show that 
  // PPP::Checked_string is working.
  astring[100]='!'; // bang! deliberately exceed 
                    // the string's text
}
Listing 4

A more modern Hello World

As recommended by Lieven de Cock on the accu-members email mailing list, Listing 5 is a more modern take on “Hello, World”, using std::println and std::source_location.

/* greetings.cpp
   
   compile with:
   make greetings
Sources:
https://en.cppreference.com/w/cpp/utility/source_location.html
https://en.cppreference.com/w/cpp/io/println.html
Whilst Bjarne Stroustrup likes to use this in his examples:
   using namespace std;
   
I prefer not to do so. This is because in medium-sized programmes and larger, this can cause name collisions and headaches so I have to  prefix names from the standard library with std::
*/

import std;

int main()
{
  std::source_location here 
    = std::source_location::current();
  std::println("Greetings from {}, 
       function {} @ {}:{}",
       here.file_name(),
       here.function_name(),
       here.line(),
       here.column()
       );  
}
Listing 5

Compiling your own code

As you write your C++ code, you could modify the makefile to build your code OR, if you are dealing with individual source files (e.g. I wrote a small programme for the exercise on page 50 of PPP3, called: 50-ex-11-how-many-coins.cpp. To get it to compile and link, all I had to do was:

  $ make std.io PPP.o 50-ex-11-how-many-coins

and make used its knowledge to execute this command line:

/opt/gcc-latest/bin/g++ -g -Wall -Wshadow -Wconversion -fmodules -std=c++23 -c /opt/gcc-latest/include/c++/16.0.0/bits/std.cc
/opt/gcc-latest/bin/g++ -g -Wall -Wshadow -Wconversion -fmodules -std=c++23 -c PPP.ixx
/opt/gcc-latest/bin/g++ -g -Wall -Wshadow -Wconversion -fmodules -std=c++23  -Wl,-rpath,/opt/gcc-latest/lib64  50-ex-11-how-many-coins.cpp   -o 50-ex-11-how-many-coins

If you have already built std.o or PPP.o, make will refrain from re-building those files as they are up to date.

Updating your compiler

When your compiler gets updated, I’d advise you to delete your object files and executables and then rebuild the executables, typically done via a ‘make clean all’ command. At the moment, this requires looking at Jonathan Wakely’s webpage, waiting for a new release, and then downloading and installing as previously discussed.

GNU Software manuals

More resources

A fair amount of articles have been written and presentations given on modules; here are a couple.

References

[Bruntlett] Files associated with this article: https://github.com/ian-bruntlett/studies/tree/main/cpp/PPP3/gcc-latest

[Stroustrup24] Bjarne Stroustrup (2024) Programming: Principles and Practice Using C++ (3rd edition), Addison-Wesley Professional.

[Wakely] Jonathan Wakely, ‘Binary packages for GCC snapshots’, at https://jwakely.github.io/pkg-gcc-latest/

Ian Bruntlett Since getting to grips with Git, Ian has been re-learning C++ using Programming: Principles and Practice Using C++ and also runs sessions of the sci-fi TTRPG (Mongoose) Traveller.






Your Privacy

By clicking "Accept Non-Essential Cookies" you agree ACCU can store non-essential cookies on your device and disclose information in accordance with our Privacy Policy and Cookie Policy.

Current Setting: Non-Essential Cookies REJECTED


By clicking "Include Third Party Content" you agree ACCU can forward your IP address to third-party sites (such as YouTube) to enhance the information presented on this site, and that third-party sites may store cookies on your device.

Current Setting: Third Party Content EXCLUDED



Settings can be changed at any time from the Cookie Policy page.