Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
f235e78
Adds libcxx/modules subdirectory
Diyou Jun 7, 2026
922e9aa
Add c++23 stl module support to the Emscripten toolchain
Diyou Jun 7, 2026
fc98e2b
Prevent overwriting CMAKE_CXX_STDLIB_MODULES_JSON
Diyou Jun 7, 2026
0518db0
Use libcxx/modules from the `emscripten-libs-21` branch
Diyou Jun 8, 2026
8bc7bd8
Fix indentation in Emscripten.cmake
Diyou Jun 8, 2026
1125e15
Include modules in update_libcxx.py
Diyou Jun 8, 2026
2a95f40
Revert "Include modules in update_libcxx.py"
Diyou Jun 8, 2026
79d3d70
Remove CMakeLists.txt from the excludes
Diyou Jun 8, 2026
135e83f
Add back modules in update_libcxx.py
Diyou Jun 8, 2026
8b5827f
Allow passing a search path with -print-file-name
Diyou Jun 8, 2026
d881828
Flip LIBCXX_* definitions so LIBCXX_INSTALL_* paths can be relative t…
Diyou Jun 8, 2026
29d7923
Make 'excludes' into a set
Diyou Jun 8, 2026
d9c2803
Revert "Allow passing a search path with -print-file-name"
Diyou Jun 9, 2026
53c6e9c
Specifcy binary_dir for the modules subdirectory
Diyou Jun 9, 2026
fa09f3e
Generate/Install modules alongside system headers
Diyou Jun 11, 2026
85ebfb3
Add import std test
Diyou Jun 11, 2026
8b97952
Add missing import in system_libs
Diyou Jun 11, 2026
8575e83
CS fixes
Diyou Jun 11, 2026
443dd60
Pass a blank object to install_modules
Diyou Jun 11, 2026
2a591ab
Use a standalone python script to build the module interfaces
Diyou Jun 11, 2026
39fba31
Checkin the generated files
Diyou Jun 11, 2026
29ebc50
Remove unused import
Diyou Jun 11, 2026
9ca4f51
Move module generation script into update_libcxx.py
Diyou Jun 11, 2026
724ae06
Rename module/prefix to module/prebuilt
Diyou Jun 12, 2026
e190b7a
Skip test on EMTEST_SKIP_NEW_CMAKE
Diyou Jun 12, 2026
3c73acd
Exit update_libcxx.py early if CMake is not found
Diyou Jun 12, 2026
c5a5ee0
Lower requirement to CMake 3.30 by utilizing Clang-CXX-CXXImportStd
Diyou Jun 12, 2026
490f66d
Avoid using if( ... IN_LIST) and use CMAKE_CXX_COMPILER_LOADED instead
Diyou Jun 12, 2026
578f8e3
Skip test_cmake_cxx_import_std specifically on version check
Diyou Jun 12, 2026
c6b1eda
Add a CMake-less test
Diyou Jun 13, 2026
f552d85
Some reformatting
Diyou Jun 13, 2026
f0784c1
Simplified test
Diyou Jun 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions cmake/Modules/Platform/Emscripten.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ if (EMSCRIPTEN_FORCE_COMPILERS)
set(CMAKE_CXX_COMPILER_ID Clang)
set(CMAKE_CXX_COMPILER_FRONTEND_VARIANT GNU)
set(CMAKE_CXX_STANDARD_COMPUTED_DEFAULT 98)
set(CMAKE_CXX_STANDARD_LIBRARY libc++)

set(CMAKE_C_PLATFORM_ID "emscripten")
set(CMAKE_CXX_PLATFORM_ID "emscripten")
Expand Down Expand Up @@ -380,3 +381,45 @@ endif()
# complain about unused CMake variable.
if (CMAKE_CROSSCOMPILING_EMULATOR)
endif()

# C++23 stl modules (Ref: https://cmake.org/cmake/help/latest/manual/cmake-cxxmodules.7.html#import-std-support)
# Opt-in via CMAKE_CXX_MODULE_STD (Ref: https://cmake.org/cmake/help/latest/variable/CMAKE_CXX_MODULE_STD.html)
if(CMAKE_CXX_MODULE_STD AND CMAKE_CXX_COMPILER_LOADED AND CMAKE_VERSION VERSION_GREATER_EQUAL 3.30 AND NOT CMAKE_CXX_STDLIB_MODULES_JSON)
# include guard and auxiliary for _cmake_cxx_import_std
set(CMAKE_CXX_STDLIB_MODULES_JSON "${EMSCRIPTEN_SYSROOT}/lib/${CMAKE_LIBRARY_ARCHITECTURE}/${CMAKE_CXX_STANDARD_LIBRARY}.modules.json")

# Ref: https://cmake.org/cmake/help/latest/variable/CMAKE_CXX_COMPILER_IMPORT_STD.html
unset(CMAKE_CXX_COMPILER_IMPORT_STD)
foreach(COMPILE_FEATURE IN LISTS CMAKE_CXX_COMPILE_FEATURES)
if(COMPILE_FEATURE MATCHES [[cxx_std_([0-9]+)]] AND CMAKE_MATCH_1 GREATER_EQUAL 23 AND CMAKE_MATCH_1 LESS 98)
list(APPEND CMAKE_CXX_COMPILER_IMPORT_STD ${CMAKE_MATCH_1})
endif()
endforeach()

include(Compiler/Clang-CXX-CXXImportStd)
if(COMMAND _cmake_cxx_find_modules_json)
# CMake >= 4.3
_cmake_cxx_find_modules_json()
if(CMAKE_CXX_COMPILER_IMPORT_STD_ERROR_MESSAGE)
message(WARNING "${CMAKE_CXX_COMPILER_IMPORT_STD_ERROR_MESSAGE}")
unset(CMAKE_CXX_COMPILER_IMPORT_STD)
endif()
elseif(COMMAND _cmake_cxx_import_std)
# CMake 3.30 ... 4.3
foreach(STD_VERSION IN LISTS CMAKE_CXX_COMPILER_IMPORT_STD)
_cmake_cxx_import_std(${STD_VERSION} eval_code)
cmake_language(EVAL CODE "${eval_code}")
if(CMAKE_CXX${STD_VERSION}_COMPILER_IMPORT_STD_NOT_FOUND_MESSAGE)
message(WARNING "${CMAKE_CXX${STD_VERSION}_COMPILER_IMPORT_STD_NOT_FOUND_MESSAGE}")
list(REMOVE_ITEM CMAKE_CXX_COMPILER_IMPORT_STD ${STD_VERSION})
endif()
endforeach()
endif()
endif()

set_property(SOURCE
"${EMSCRIPTEN_SYSROOT}/share/libc++/v1/std.cppm"
"${EMSCRIPTEN_SYSROOT}/share/libc++/v1/std.compat.cppm"
PROPERTY
COMPILE_FLAGS -Wno-reserved-module-identifier
)
3 changes: 3 additions & 0 deletions system/lib/libcxx/modules/.clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
BasedOnStyle: InheritParentConfig

NamespaceIndentation: All
269 changes: 269 additions & 0 deletions system/lib/libcxx/modules/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,269 @@
# The headers of Table 24: C++ library headers [tab:headers.cpp]
# and the headers of Table 25: C++ headers for C library facilities [tab:headers.cpp.c]
set(LIBCXX_MODULE_STD_SOURCES
std/algorithm.inc
std/any.inc
std/array.inc
std/atomic.inc
std/barrier.inc
std/bit.inc
std/bitset.inc
std/cassert.inc
std/cctype.inc
std/cerrno.inc
std/cfenv.inc
std/cfloat.inc
std/charconv.inc
std/chrono.inc
std/cinttypes.inc
std/climits.inc
std/clocale.inc
std/cmath.inc
std/codecvt.inc
std/compare.inc
std/complex.inc
std/concepts.inc
std/condition_variable.inc
std/coroutine.inc
std/csetjmp.inc
std/csignal.inc
std/cstdarg.inc
std/cstddef.inc
std/cstdint.inc
std/cstdio.inc
std/cstdlib.inc
std/cstring.inc
std/ctime.inc
std/cuchar.inc
std/cwchar.inc
std/cwctype.inc
std/deque.inc
std/exception.inc
std/execution.inc
std/expected.inc
std/filesystem.inc
std/flat_map.inc
std/flat_set.inc
std/format.inc
std/forward_list.inc
std/fstream.inc
std/functional.inc
std/future.inc
std/generator.inc
std/hazard_pointer.inc
std/initializer_list.inc
std/iomanip.inc
std/ios.inc
std/iosfwd.inc
std/iostream.inc
std/istream.inc
std/iterator.inc
std/latch.inc
std/limits.inc
std/list.inc
std/locale.inc
std/map.inc
std/mdspan.inc
std/memory.inc
std/memory_resource.inc
std/mutex.inc
std/new.inc
std/numbers.inc
std/numeric.inc
std/optional.inc
std/ostream.inc
std/print.inc
std/queue.inc
std/random.inc
std/ranges.inc
std/ratio.inc
std/rcu.inc
std/regex.inc
std/scoped_allocator.inc
std/semaphore.inc
std/set.inc
std/shared_mutex.inc
std/source_location.inc
std/span.inc
std/spanstream.inc
std/sstream.inc
std/stack.inc
std/stacktrace.inc
std/stdexcept.inc
std/stdfloat.inc
std/stop_token.inc
std/streambuf.inc
std/string.inc
std/string_view.inc
std/strstream.inc
std/syncstream.inc
std/system_error.inc
std/text_encoding.inc
std/thread.inc
std/tuple.inc
std/type_traits.inc
std/typeindex.inc
std/typeinfo.inc
std/unordered_map.inc
std/unordered_set.inc
std/utility.inc
std/valarray.inc
std/variant.inc
std/vector.inc
std/version.inc
)

set(LIBCXX_MODULE_STD_COMPAT_SOURCES
std.compat/cassert.inc
std.compat/cctype.inc
std.compat/cerrno.inc
std.compat/cfenv.inc
std.compat/cfloat.inc
std.compat/cinttypes.inc
std.compat/climits.inc
std.compat/clocale.inc
std.compat/cmath.inc
std.compat/csetjmp.inc
std.compat/csignal.inc
std.compat/cstdarg.inc
std.compat/cstddef.inc
std.compat/cstdint.inc
std.compat/cstdio.inc
std.compat/cstdlib.inc
std.compat/cstring.inc
std.compat/ctime.inc
std.compat/cuchar.inc
std.compat/cwchar.inc
std.compat/cwctype.inc
)

# TODO MODULES the CMakeLists.txt in the build directory is only temporary.
# This allows using as available in the build directory. Once build systems
# have proper support for the installed files this will be removed.
if ("${LIBCXX_GENERATED_INCLUDE_DIR}" STREQUAL "${LIBCXX_GENERATED_INCLUDE_TARGET_DIR}")
# This typically happens when the target is not installed.
set(LIBCXX_CONFIGURED_INCLUDE_DIRS "${LIBCXX_GENERATED_INCLUDE_DIR}")
else()
# It's important that the arch directory be included first so that its header files
# which interpose on the default include dir be included instead of the default ones.
set(LIBCXX_CONFIGURED_INCLUDE_DIRS
"${LIBCXX_GENERATED_INCLUDE_TARGET_DIR};${LIBCXX_GENERATED_INCLUDE_DIR}"
)
endif()
configure_file(
"CMakeLists.txt.in"
"${LIBCXX_GENERATED_MODULE_DIR}/CMakeLists.txt"
@ONLY
)

set(LIBCXX_MODULE_STD_INCLUDE_SOURCES)
foreach(file ${LIBCXX_MODULE_STD_SOURCES})
set(
LIBCXX_MODULE_STD_INCLUDE_SOURCES
"${LIBCXX_MODULE_STD_INCLUDE_SOURCES}#include \"${file}\"\n"
)
endforeach()

configure_file(
"std.cppm.in"
"${LIBCXX_GENERATED_MODULE_DIR}/std.cppm"
@ONLY
)

set(LIBCXX_MODULE_STD_COMPAT_INCLUDE_SOURCES)
foreach(file ${LIBCXX_MODULE_STD_COMPAT_SOURCES})
set(
LIBCXX_MODULE_STD_COMPAT_INCLUDE_SOURCES
"${LIBCXX_MODULE_STD_COMPAT_INCLUDE_SOURCES}#include \"${file}\"\n"
)
endforeach()

configure_file(
"std.compat.cppm.in"
"${LIBCXX_GENERATED_MODULE_DIR}/std.compat.cppm"
@ONLY
)

set(_all_modules)
list(APPEND _all_modules "${LIBCXX_GENERATED_MODULE_DIR}/CMakeLists.txt")
list(APPEND _all_modules "${LIBCXX_GENERATED_MODULE_DIR}/std.cppm")
list(APPEND _all_modules "${LIBCXX_GENERATED_MODULE_DIR}/std.compat.cppm")
foreach(file ${LIBCXX_MODULE_STD_SOURCES} ${LIBCXX_MODULE_STD_COMPAT_SOURCES})
set(src "${CMAKE_CURRENT_SOURCE_DIR}/${file}")
set(dst "${LIBCXX_GENERATED_MODULE_DIR}/${file}")
add_custom_command(OUTPUT ${dst}
DEPENDS ${src}
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${src} ${dst}
COMMENT "Copying CXX module ${file}")
list(APPEND _all_modules "${dst}")
endforeach()

add_custom_target(generate-cxx-modules
ALL DEPENDS
${_all_modules}
)

# Configure the modules manifest.
# Use the relative path between the installation and the module in the json
# file. This allows moving the entire installation to a different location.
if("${CMAKE_INSTALL_PREFIX}" STREQUAL "")
set(BASE_DIRECTORY "/")
else()
set(BASE_DIRECTORY ${CMAKE_INSTALL_PREFIX})
endif()
cmake_path(ABSOLUTE_PATH LIBCXX_INSTALL_LIBRARY_DIR
BASE_DIRECTORY ${BASE_DIRECTORY}
OUTPUT_VARIABLE ABS_LIBRARY_DIR)
cmake_path(ABSOLUTE_PATH LIBCXX_INSTALL_MODULES_DIR
BASE_DIRECTORY ${BASE_DIRECTORY}
OUTPUT_VARIABLE ABS_MODULES_DIR)
file(RELATIVE_PATH LIBCXX_MODULE_RELATIVE_PATH
${ABS_LIBRARY_DIR}
${ABS_MODULES_DIR})
configure_file(
"modules.json.in"
"${LIBCXX_LIBRARY_DIR}/libc++.modules.json"
@ONLY
)

# Dummy library to make modules an installation component.
add_library(cxx-modules INTERFACE)
add_dependencies(cxx-modules generate-cxx-modules)

if (LIBCXX_INSTALL_MODULES)
foreach(file ${LIBCXX_MODULE_STD_SOURCES} ${LIBCXX_MODULE_STD_COMPAT_SOURCES})
get_filename_component(dir ${file} DIRECTORY)
install(FILES ${file}
DESTINATION "${LIBCXX_INSTALL_MODULES_DIR}/${dir}"
COMPONENT cxx-modules
PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ
)
endforeach()

# Install the generated module files.
install(FILES
"${LIBCXX_GENERATED_MODULE_DIR}/std.cppm"
"${LIBCXX_GENERATED_MODULE_DIR}/std.compat.cppm"
DESTINATION "${LIBCXX_INSTALL_MODULES_DIR}"
COMPONENT cxx-modules
PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ
)

# Install the module manifest.
install(FILES
"${LIBCXX_LIBRARY_DIR}/libc++.modules.json"
DESTINATION "${LIBCXX_INSTALL_LIBRARY_DIR}"
COMPONENT cxx-modules
PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ
)

if (NOT CMAKE_CONFIGURATION_TYPES)
add_custom_target(install-cxx-modules
DEPENDS cxx-modules
COMMAND "${CMAKE_COMMAND}"
-DCMAKE_INSTALL_COMPONENT=cxx-modules
-P "${CMAKE_BINARY_DIR}/cmake_install.cmake")
# Stripping is a no-op for modules
add_custom_target(install-cxx-modules-stripped DEPENDS install-cxx-modules)
endif()
endif()
Loading
Loading