Re-exporting Modules (Turkish Van)

A Partitioned Module (Javanese) used export import :Balinese; to re-export a partition of the same module. The export import syntax isn’t limited to partitions, though — a module can just as well re-export an entirely separate, unrelated top-level module. This chapter builds a small umbrella module that does exactly that, composing two independent modules into a single consumer-facing import.

Module TurkishAngora

A small, self-contained module, unaware it will later be re-exported.

1 module;
2 
3 #include <print>
4 
5 export module TurkishAngora;
6 
7 export auto angora_meow() -> void {
8    std::println("Ankara kedisi «Miyav» der.");
9 }

Module TurkishVan

 1 module;
 2 
 3 #include <print>
 4 
 5 export module TurkishVan;
 6 
 7 export import TurkishAngora; // umbrella re-export: importing TurkishVan
 8                               // transitively brings in TurkishAngora's
 9                               // exports too, composing two independent
10                               // top-level modules into one consumer import.
11                               // Contrast with Javanese's `export import
12                               // :Balinese;`, which re-exports a partition
13                               // of itself rather than a separate module.
14 
15 export auto van_meow() -> void {
16    std::println("Van kedisi «Miyav» der.");
17 }

The only new syntax here is on line 7: export import TurkishAngora; names a complete, independent module rather than a :partition. Everything TurkishAngora exports becomes visible to anyone who imports TurkishVan, without them ever writing import TurkishAngora; themselves.

User Code: main.cpp

1 import TurkishVan; // the only import needed -- angora_meow() comes along
2                     // via TurkishVan's umbrella re-export
3 
4 auto main() -> int {
5    van_meow();
6    angora_meow();
7 
8    return 0;
9 }

main.cpp imports only TurkishVan (line 1) and calls both van_meow(), native to TurkishVan, and angora_meow(), which arrived transitively. There is no import TurkishAngora; anywhere in this file.

An icon indicating this blurb contains a warning

Re-exporting two modules that happen to export the same name is a compile error, not a silent shadowing — an umbrella module can’t resolve which one you meant. This is worth checking for before composing modules you didn’t write yourself.

Building With CMake

TurkishAngora and TurkishVan are separate library targets; TurkishVan links TurkishAngora PUBLIC so both its own compilation and any importer’s compilation can see it.

 1 cmake_minimum_required(VERSION 3.30.5)
 2 
 3 project(TurkishVan LANGUAGES CXX)
 4 
 5 add_library(turkish_angora)
 6 target_compile_features(turkish_angora PUBLIC cxx_std_23)
 7 target_sources(turkish_angora
 8                PUBLIC
 9                FILE_SET cxx_modules TYPE CXX_MODULES
10                FILES TurkishAngora.cppm
11 )
12 
13 add_library(turkish_van)
14 target_compile_features(turkish_van PUBLIC cxx_std_23)
15 target_sources(turkish_van
16                PUBLIC
17                FILE_SET cxx_modules TYPE CXX_MODULES
18                FILES TurkishVan.cppm
19 )
20 # turkish_van's own scan needs to see TurkishAngora's BMI, and importers of
21 # turkish_van need to transitively link turkish_angora too -- PUBLIC covers
22 # both.
23 target_link_libraries(turkish_van PUBLIC turkish_angora)
24 
25 add_executable(${PROJECT_NAME} main.cpp)
26 target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_23)
27 
28 target_link_libraries(${PROJECT_NAME} turkish_van)

The PUBLIC on line 22’s target_link_libraries() is the important detail — a PRIVATE link would let turkish_van’s own sources see turkish_angora, but the executable target that only links turkish_van (line 27) wouldn’t transitively pick it up, and the final link would fail to find angora_meow()’s definition.