[llvm] [libcxx] [libc++][modules] Adds module testing. (PR #76246)

Mark de Wever via llvm-commits llvm-commits at lists.llvm.org
Fri Dec 22 10:52:17 PST 2023


https://github.com/mordante updated https://github.com/llvm/llvm-project/pull/76246

>From 5c5c96851933bac0e362fc805454b2ec24fb1395 Mon Sep 17 00:00:00 2001
From: Mark de Wever <koraq at xs4all.nl>
Date: Wed, 20 Dec 2023 18:32:39 +0100
Subject: [PATCH 1/2] [libc++][modules] Removes module testing.

This removes the entire modules testing infrastructure.

The current infrastructure uses CMake to generate the std and std.compat
module. This requires quite a bit of plumbing and uses CMake. Since
CMake introduced module support in CMake 3.26, modules have a higher
CMake requirement than the rest of the LLVM project. (The LLVM project
requires 3.20.) The main motivation for this approach was how libc++
generated its modules. Every header had its own module partition. This
was changed to improve performance and now only two modules remain.
The code to build these can be manually crafted.

A followup patch will reenable testing modules, using a different
approach.
---
 .github/workflows/libcxx-build-and-test.yaml  |  8 --
 libcxx/CMakeLists.txt                         | 15 +---
 libcxx/cmake/caches/Generic-cxx26.cmake       |  1 -
 .../Generic-hardening-mode-extensive.cmake    |  1 -
 .../cmake/caches/Generic-no-exceptions.cmake  |  1 -
 .../caches/Generic-no-experimental.cmake      |  1 -
 .../cmake/caches/Generic-no-filesystem.cmake  |  1 -
 .../caches/Generic-no-localization.cmake      |  1 -
 .../caches/Generic-no-random_device.cmake     |  1 -
 libcxx/cmake/caches/Generic-no-threads.cmake  |  1 -
 libcxx/cmake/caches/Generic-no-tzdb.cmake     |  1 -
 libcxx/cmake/caches/Generic-no-unicode.cmake  |  1 -
 .../caches/Generic-no-wide-characters.cmake   |  1 -
 libcxx/docs/Modules.rst                       |  2 +-
 libcxx/docs/ReleaseNotes/18.rst               |  4 +
 libcxx/modules/CMakeLists.txt                 | 28 ------
 libcxx/modules/CMakeLists.txt.in              | 86 -------------------
 libcxx/test/CMakeLists.txt                    | 25 ------
 libcxx/test/configs/cmake-bridge.cfg.in       |  7 --
 libcxx/test/lit.local.cfg                     | 83 ------------------
 libcxx/test/std/modules/std.compat.pass.cpp   |  4 +-
 libcxx/test/std/modules/std.pass.cpp          |  4 +-
 libcxx/utils/ci/Dockerfile                    | 11 ---
 libcxx/utils/ci/buildkite-pipeline.yml        |  2 -
 libcxx/utils/ci/run-buildbot                  | 10 ---
 libcxx/utils/libcxx/test/features.py          |  1 -
 libcxx/utils/libcxx/test/modules.py           |  3 +-
 27 files changed, 13 insertions(+), 291 deletions(-)
 delete mode 100644 libcxx/modules/CMakeLists.txt.in
 delete mode 100644 libcxx/test/lit.local.cfg

diff --git a/.github/workflows/libcxx-build-and-test.yaml b/.github/workflows/libcxx-build-and-test.yaml
index 370cf830a60cf8..a7aeeb1b0d59d2 100644
--- a/.github/workflows/libcxx-build-and-test.yaml
+++ b/.github/workflows/libcxx-build-and-test.yaml
@@ -35,7 +35,6 @@ concurrency:
 
 
 env:
-  CMAKE: "/opt/bin/cmake"
   # LLVM POST-BRANCH bump version
   # LLVM POST-BRANCH add compiler test for ToT - 1, e.g. "Clang 17"
   # LLVM RELEASE bump remove compiler ToT - 3, e.g. "Clang 15"
@@ -169,24 +168,18 @@ jobs:
           'bootstrapping-build'
         ]
         machine: [ 'libcxx-runners-8-set' ]
-        std_modules: [ 'OFF' ]
         include:
         - config: 'generic-cxx26'
           machine: libcxx-runners-8-set
-          std_modules: 'ON'
         - config: 'generic-asan'
           machine: libcxx-runners-8-set
-          std_modules: 'OFF'
         - config: 'generic-tsan'
           machine: libcxx-runners-8-set
-          std_modules: 'OFF'
         - config: 'generic-ubsan'
           machine: libcxx-runners-8-set
-          std_modules: 'OFF'
         # Use a larger machine for MSAN to avoid timeout and memory allocation issues.
         - config: 'generic-msan'
           machine: libcxx-runners-32-set
-          std_modules: 'OFF'
     runs-on: ${{ matrix.machine }}
     steps:
       - uses: actions/checkout at v4
@@ -196,7 +189,6 @@ jobs:
           CC: clang-18
           CXX: clang++-18
           ENABLE_CLANG_TIDY: "OFF"
-          ENABLE_STD_MODULES: ${{ matrix.std_modules }}
       - uses: actions/upload-artifact at v3
         if: always()
         with:
diff --git a/libcxx/CMakeLists.txt b/libcxx/CMakeLists.txt
index 75cb63222da35c..0ab900e7df3c51 100644
--- a/libcxx/CMakeLists.txt
+++ b/libcxx/CMakeLists.txt
@@ -117,12 +117,6 @@ option(LIBCXX_ENABLE_VENDOR_AVAILABILITY_ANNOTATIONS
    the shared library they shipped should turn this on and see `include/__availability`
    for more details." OFF)
 option(LIBCXX_ENABLE_CLANG_TIDY "Whether to compile and run clang-tidy checks" OFF)
-# TODO MODULES Remove this option and test for the requirements (CMake/Clang) instead.
-option(LIBCXX_ENABLE_STD_MODULES
-   "Whether to enable the building the C++23 `std` module. This feature is
-    experimental and has additional dependencies. Only enable this when
-    interested in testing or developing this module. See
-    https://libcxx.llvm.org/Modules.html for more information." OFF)
 
 if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
   set(LIBCXX_DEFAULT_TEST_CONFIG "llvm-libc++-shared-gcc.cfg.in")
@@ -772,7 +766,6 @@ config_define_if_not(LIBCXX_ENABLE_RANDOM_DEVICE _LIBCPP_HAS_NO_RANDOM_DEVICE)
 config_define_if_not(LIBCXX_ENABLE_LOCALIZATION _LIBCPP_HAS_NO_LOCALIZATION)
 config_define_if_not(LIBCXX_ENABLE_UNICODE _LIBCPP_HAS_NO_UNICODE)
 config_define_if_not(LIBCXX_ENABLE_WIDE_CHARACTERS _LIBCPP_HAS_NO_WIDE_CHARACTERS)
-config_define_if_not(LIBCXX_ENABLE_STD_MODULES _LIBCPP_HAS_NO_STD_MODULES)
 config_define_if_not(LIBCXX_ENABLE_TIME_ZONE_DATABASE _LIBCPP_HAS_NO_TIME_ZONE_DATABASE)
 config_define_if_not(LIBCXX_ENABLE_VENDOR_AVAILABILITY_ANNOTATIONS _LIBCPP_HAS_NO_VENDOR_AVAILABILITY_ANNOTATIONS)
 
@@ -856,9 +849,7 @@ endfunction()
 add_subdirectory(include)
 add_subdirectory(src)
 add_subdirectory(utils)
-if (LIBCXX_ENABLE_STD_MODULES)
-  add_subdirectory(modules)
-endif()
+add_subdirectory(modules)
 
 set(LIBCXX_TEST_DEPS "cxx_experimental")
 
@@ -866,9 +857,7 @@ if (LIBCXX_ENABLE_CLANG_TIDY)
   list(APPEND LIBCXX_TEST_DEPS cxx-tidy)
 endif()
 
-if (LIBCXX_ENABLE_STD_MODULES)
-  list(APPEND LIBCXX_TEST_DEPS generate-cxx-modules generate-test-module-std)
-endif()
+list(APPEND LIBCXX_TEST_DEPS generate-cxx-modules)
 
 if (LIBCXX_INCLUDE_BENCHMARKS)
   add_subdirectory(benchmarks)
diff --git a/libcxx/cmake/caches/Generic-cxx26.cmake b/libcxx/cmake/caches/Generic-cxx26.cmake
index f48d72d493c2f5..6ba9482af57851 100644
--- a/libcxx/cmake/caches/Generic-cxx26.cmake
+++ b/libcxx/cmake/caches/Generic-cxx26.cmake
@@ -1,3 +1,2 @@
-set(LIBCXX_ENABLE_STD_MODULES ON CACHE BOOL "") # TODO MODULES Remove when enabled automatically.
 set(LIBCXX_TEST_PARAMS "std=c++26" CACHE STRING "")
 set(LIBCXXABI_TEST_PARAMS "${LIBCXX_TEST_PARAMS}" CACHE STRING "")
diff --git a/libcxx/cmake/caches/Generic-hardening-mode-extensive.cmake b/libcxx/cmake/caches/Generic-hardening-mode-extensive.cmake
index 0487377d4e9ba2..72263dfd84635b 100644
--- a/libcxx/cmake/caches/Generic-hardening-mode-extensive.cmake
+++ b/libcxx/cmake/caches/Generic-hardening-mode-extensive.cmake
@@ -1,2 +1 @@
-set(LIBCXX_ENABLE_STD_MODULES ON CACHE BOOL "") # TODO MODULES Remove when enabled automatically.
 set(LIBCXX_HARDENING_MODE "extensive" CACHE STRING "")
diff --git a/libcxx/cmake/caches/Generic-no-exceptions.cmake b/libcxx/cmake/caches/Generic-no-exceptions.cmake
index f405f7fe993752..f0dffef60dba08 100644
--- a/libcxx/cmake/caches/Generic-no-exceptions.cmake
+++ b/libcxx/cmake/caches/Generic-no-exceptions.cmake
@@ -1,3 +1,2 @@
-set(LIBCXX_ENABLE_STD_MODULES ON CACHE BOOL "") # TODO MODULES Remove when enabled automatically.
 set(LIBCXX_ENABLE_EXCEPTIONS OFF CACHE BOOL "")
 set(LIBCXXABI_ENABLE_EXCEPTIONS OFF CACHE BOOL "")
diff --git a/libcxx/cmake/caches/Generic-no-experimental.cmake b/libcxx/cmake/caches/Generic-no-experimental.cmake
index fe14e7afed7b96..f33ed01418990b 100644
--- a/libcxx/cmake/caches/Generic-no-experimental.cmake
+++ b/libcxx/cmake/caches/Generic-no-experimental.cmake
@@ -1,3 +1,2 @@
-set(LIBCXX_ENABLE_STD_MODULES ON CACHE BOOL "") # TODO MODULES Remove when enabled automatically.
 set(LIBCXX_TEST_PARAMS "enable_experimental=False" CACHE STRING "")
 set(LIBCXXABI_TEST_PARAMS "${LIBCXX_TEST_PARAMS}" CACHE STRING "")
diff --git a/libcxx/cmake/caches/Generic-no-filesystem.cmake b/libcxx/cmake/caches/Generic-no-filesystem.cmake
index db62f86854d941..4000f3a3e8ef23 100644
--- a/libcxx/cmake/caches/Generic-no-filesystem.cmake
+++ b/libcxx/cmake/caches/Generic-no-filesystem.cmake
@@ -1,2 +1 @@
-set(LIBCXX_ENABLE_STD_MODULES ON CACHE BOOL "") # TODO MODULES Remove when enabled automatically.
 set(LIBCXX_ENABLE_FILESYSTEM OFF CACHE BOOL "")
diff --git a/libcxx/cmake/caches/Generic-no-localization.cmake b/libcxx/cmake/caches/Generic-no-localization.cmake
index 54a7ec3f1f5b36..79d6b44c7139aa 100644
--- a/libcxx/cmake/caches/Generic-no-localization.cmake
+++ b/libcxx/cmake/caches/Generic-no-localization.cmake
@@ -1,2 +1 @@
-set(LIBCXX_ENABLE_STD_MODULES ON CACHE BOOL "") # TODO MODULES Remove when enabled automatically.
 set(LIBCXX_ENABLE_LOCALIZATION OFF CACHE BOOL "")
diff --git a/libcxx/cmake/caches/Generic-no-random_device.cmake b/libcxx/cmake/caches/Generic-no-random_device.cmake
index adfa2458a8edf6..e9b4cc60cc80ea 100644
--- a/libcxx/cmake/caches/Generic-no-random_device.cmake
+++ b/libcxx/cmake/caches/Generic-no-random_device.cmake
@@ -1,2 +1 @@
-set(LIBCXX_ENABLE_STD_MODULES ON CACHE BOOL "") # TODO MODULES Remove when enabled automatically.
 set(LIBCXX_ENABLE_RANDOM_DEVICE OFF CACHE BOOL "")
diff --git a/libcxx/cmake/caches/Generic-no-threads.cmake b/libcxx/cmake/caches/Generic-no-threads.cmake
index 2aeab22915e00c..616baef1be7bef 100644
--- a/libcxx/cmake/caches/Generic-no-threads.cmake
+++ b/libcxx/cmake/caches/Generic-no-threads.cmake
@@ -1,4 +1,3 @@
-set(LIBCXX_ENABLE_STD_MODULES ON CACHE BOOL "") # TODO MODULES Remove when enabled automatically.
 set(LIBCXX_ENABLE_THREADS OFF CACHE BOOL "")
 set(LIBCXXABI_ENABLE_THREADS OFF CACHE BOOL "")
 set(LIBCXX_ENABLE_MONOTONIC_CLOCK OFF CACHE BOOL "")
diff --git a/libcxx/cmake/caches/Generic-no-tzdb.cmake b/libcxx/cmake/caches/Generic-no-tzdb.cmake
index c5dc882e584428..27c826edfecffb 100644
--- a/libcxx/cmake/caches/Generic-no-tzdb.cmake
+++ b/libcxx/cmake/caches/Generic-no-tzdb.cmake
@@ -1,2 +1 @@
-set(LIBCXX_ENABLE_STD_MODULES ON CACHE BOOL "") # TODO MODULES Remove when enabled automatically.
 set(LIBCXX_ENABLE_TIME_ZONE_DATABASE OFF CACHE BOOL "")
diff --git a/libcxx/cmake/caches/Generic-no-unicode.cmake b/libcxx/cmake/caches/Generic-no-unicode.cmake
index 880e2d502ad91b..01160bf218981a 100644
--- a/libcxx/cmake/caches/Generic-no-unicode.cmake
+++ b/libcxx/cmake/caches/Generic-no-unicode.cmake
@@ -1,2 +1 @@
-set(LIBCXX_ENABLE_STD_MODULES ON CACHE BOOL "") # TODO MODULES Remove when enabled automatically.
 set(LIBCXX_ENABLE_UNICODE OFF CACHE BOOL "")
diff --git a/libcxx/cmake/caches/Generic-no-wide-characters.cmake b/libcxx/cmake/caches/Generic-no-wide-characters.cmake
index 5036f6abd52e83..728d41086a3867 100644
--- a/libcxx/cmake/caches/Generic-no-wide-characters.cmake
+++ b/libcxx/cmake/caches/Generic-no-wide-characters.cmake
@@ -1,2 +1 @@
-set(LIBCXX_ENABLE_STD_MODULES ON CACHE BOOL "") # TODO MODULES Remove when enabled automatically.
 set(LIBCXX_ENABLE_WIDE_CHARACTERS OFF CACHE BOOL "")
diff --git a/libcxx/docs/Modules.rst b/libcxx/docs/Modules.rst
index 5099e6095582cf..1998cd9d1d267e 100644
--- a/libcxx/docs/Modules.rst
+++ b/libcxx/docs/Modules.rst
@@ -115,7 +115,7 @@ directory. First libc++ needs to be build with module support enabled.
   $ git clone https://github.com/llvm/llvm-project.git
   $ cd llvm-project
   $ mkdir build
-  $ cmake -G Ninja -S runtimes -B build -DLIBCXX_ENABLE_STD_MODULES=ON -DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi;libunwind"
+  $ cmake -G Ninja -S runtimes -B build -DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi;libunwind"
   $ ninja -C build
 
 The above ``build`` directory will be referred to as ``<build>`` in the
diff --git a/libcxx/docs/ReleaseNotes/18.rst b/libcxx/docs/ReleaseNotes/18.rst
index 79608c631f1e62..45e12cec44e510 100644
--- a/libcxx/docs/ReleaseNotes/18.rst
+++ b/libcxx/docs/ReleaseNotes/18.rst
@@ -83,6 +83,10 @@ Improvements and New Features
 - The ``_LIBCPP_ENABLE_CXX26_REMOVED_STRING_RESERVE`` macro has been added to make
   the function ``std::basic_string<...>::reserve()`` available.
 
+- The cmake option ``LIBCXX_ENABLE_STD_MODULES`` has been removed. The test
+  infrastructure no longer depends on a modern CMake, it works with the minimal
+  required LLVM version (3.20.0).
+
 
 Deprecations and Removals
 -------------------------
diff --git a/libcxx/modules/CMakeLists.txt b/libcxx/modules/CMakeLists.txt
index fae6448a7eec84..31fbadf449f773 100644
--- a/libcxx/modules/CMakeLists.txt
+++ b/libcxx/modules/CMakeLists.txt
@@ -1,8 +1,3 @@
-if (CMAKE_VERSION VERSION_LESS 3.26)
-  message(WARNING "The libc++ modules won't be available because the CMake version is too old. Update to CMake 3.26 or later.")
-  return()
-endif()
-
 # 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
@@ -142,28 +137,6 @@ set(LIBCXX_MODULE_STD_COMPAT_SOURCES
   std.compat/cwctype.inc
 )
 
-# TODO MODULES the CMakeLists.txt in the install directory is only temporary
-# When that is removed the configured file can use the substitution
-# LIBCXX_GENERATED_INCLUDE_TARGET_DIR avoiding this set.
-# Also clean up the parts needed to generate the install version.
-# - LIBCXX_GENERATED_INCLUDE_DIR contains the libc++ headers
-# - LIBCXX_GENERATED_INCLUDE_TARGET_DIR contains the libc++ site config
-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(
@@ -193,7 +166,6 @@ configure_file(
 )
 
 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})
diff --git a/libcxx/modules/CMakeLists.txt.in b/libcxx/modules/CMakeLists.txt.in
deleted file mode 100644
index 98168673ebfe9c..00000000000000
--- a/libcxx/modules/CMakeLists.txt.in
+++ /dev/null
@@ -1,86 +0,0 @@
-cmake_minimum_required(VERSION 3.26)
-
-project(libc++-modules LANGUAGES CXX)
-
-# Enable CMake's module support
-if(CMAKE_VERSION VERSION_LESS "3.28.0")
-  if(CMAKE_VERSION VERSION_LESS "3.27.0")
-    set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "2182bf5c-ef0d-489a-91da-49dbc3090d2a")
-  else()
-    set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "aa1f7df0-828a-4fcd-9afc-2dc80491aca7")
-  endif()
-  set(CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP 1)
-else()
-  cmake_policy(VERSION 3.28)
-endif()
-
-# Default to C++ extensions being off. Libc++'s modules support have trouble
-# with extensions right now.
-set(CMAKE_CXX_EXTENSIONS OFF)
-
-# Propagates the CMake options to the modules.
-#
-# This uses the std module hard-coded since the std.compat module does not
-# depend on these flags.
-macro(compile_define_if_not condition def)
-  if (NOT ${condition})
-    target_compile_definitions(std PRIVATE ${def})
-  endif()
-endmacro()
-macro(compile_define_if condition def)
-  if (${condition})
-    target_compile_definitions(std PRIVATE ${def})
-  endif()
-endmacro()
-
-### STD
-
-add_library(std)
-target_sources(std
-  PUBLIC FILE_SET cxx_modules TYPE CXX_MODULES FILES
-    std.cppm
-)
-
-target_include_directories(std SYSTEM PRIVATE @LIBCXX_CONFIGURED_INCLUDE_DIRS@)
-
-if (NOT @LIBCXX_ENABLE_EXCEPTIONS@)
-  target_compile_options(std PUBLIC -fno-exceptions)
-endif()
-
-target_compile_options(std
-  PUBLIC
-    -nostdinc++
-    -Wno-reserved-module-identifier
-    -Wno-reserved-user-defined-literal
-    @LIBCXX_COMPILE_FLAGS@
-)
-set_target_properties(std
-  PROPERTIES
-    OUTPUT_NAME   "c++std"
-)
-
-### STD.COMPAT
-
-add_library(std.compat)
-target_sources(std.compat
-  PUBLIC FILE_SET cxx_modules TYPE CXX_MODULES FILES
-    std.compat.cppm
-)
-
-target_include_directories(std.compat SYSTEM PRIVATE @LIBCXX_CONFIGURED_INCLUDE_DIRS@)
-
-if (NOT @LIBCXX_ENABLE_EXCEPTIONS@)
-  target_compile_options(std.compat PUBLIC -fno-exceptions)
-endif()
-
-target_compile_options(std.compat
-  PUBLIC
-    -nostdinc++
-    -Wno-reserved-module-identifier
-    -Wno-reserved-user-defined-literal
-    @LIBCXX_COMPILE_FLAGS@
-)
-set_target_properties(std.compat
-  PROPERTIES
-    OUTPUT_NAME   "c++std.compat"
-)
diff --git a/libcxx/test/CMakeLists.txt b/libcxx/test/CMakeLists.txt
index 48dd233462ab3b..52620fc55feeb7 100644
--- a/libcxx/test/CMakeLists.txt
+++ b/libcxx/test/CMakeLists.txt
@@ -87,31 +87,6 @@ if (LIBCXX_INCLUDE_TESTS)
     ${CMAKE_CURRENT_BINARY_DIR}
     DEPENDS cxx-test-depends)
 
-  if(LIBCXX_ENABLE_STD_MODULES)
-    # Generates the modules used in the test.
-    # Note the test will regenerate this with the proper setting
-    # - the right DCMAKE_CXX_STANDARD
-    # - the right test compilation flags
-    # Since modules depend on these flags there currently is no way to
-    # avoid generating these for the tests. The advantage of the
-    # pre generation is that less build information needs to be shared
-    # in the bridge.
-    add_custom_command(
-        OUTPUT "${CMAKE_BINARY_DIR}/test/__config_module__/CMakeCache.txt"
-        COMMAND
-        ${CMAKE_COMMAND}
-            "-G${CMAKE_GENERATOR}"
-            "-DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM}"
-            "-B${CMAKE_BINARY_DIR}/test/__config_module__"
-            "-H${LIBCXX_GENERATED_MODULE_DIR}"
-            "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}"
-            "-DCMAKE_CXX_STANDARD=23"
-            "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON"
-            )
-  add_custom_target(generate-test-module-std
-      DEPENDS "${CMAKE_BINARY_DIR}/test/__config_module__/CMakeCache.txt"
-      COMMENT "Builds generic module std.")
-  endif()
 endif()
 
 if (LIBCXX_GENERATE_COVERAGE)
diff --git a/libcxx/test/configs/cmake-bridge.cfg.in b/libcxx/test/configs/cmake-bridge.cfg.in
index 0e3c3040c96446..72b2ddf378bb64 100644
--- a/libcxx/test/configs/cmake-bridge.cfg.in
+++ b/libcxx/test/configs/cmake-bridge.cfg.in
@@ -31,10 +31,3 @@ config.substitutions.append(('%{target-include}', '@LIBCXX_GENERATED_INCLUDE_TAR
 config.substitutions.append(('%{lib}', '@LIBCXX_LIBRARY_DIR@'))
 config.substitutions.append(('%{module}', '@LIBCXX_GENERATED_MODULE_DIR@'))
 config.substitutions.append(('%{test-tools}', '@LIBCXX_TEST_TOOLS_PATH@'))
-
-# The test needs to manually rebuild the module. The compiler flags used in the
-# test need to be the same as the compiler flags used to generate the module.
-# In the future, when CMake can generated modules this may no longer be
-# necessary.
-# TODO MODULES whether it's possible to remove this substitution.
-config.substitutions.append(('%{cmake}', '@CMAKE_COMMAND@'))
diff --git a/libcxx/test/lit.local.cfg b/libcxx/test/lit.local.cfg
deleted file mode 100644
index 1ee9086ee22e3c..00000000000000
--- a/libcxx/test/lit.local.cfg
+++ /dev/null
@@ -1,83 +0,0 @@
-# ===----------------------------------------------------------------------===##
-#
-# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-# See https://llvm.org/LICENSE.txt for license information.
-# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-#
-# ===----------------------------------------------------------------------===##
-
-# This configuration builds the C++23 std module.
-# It is build when the current lit configuration supports modules.
-#
-# TODO MODULES Evaluate whether this file can be removed when CMake supports
-# modules in libc++.
-
-import os
-import site
-import subprocess
-import libcxx.test.params, libcxx.test.config, libcxx.test.dsl
-
-
-def getSubstitution(substitution, config):
-    for orig, replacement in config.substitutions:
-        if orig == substitution:
-            return replacement
-    raise ValueError("Substitution {} is not in the config.".format(substitution))
-
-
-def appendToSubstitution(substitutions, key, value):
-    return [(k, v + " " + value) if k == key else (k, v) for (k, v) in substitutions]
-
-
-std = getSubstitution("%{cxx_std}", config)
-if std == "cxx26":
-    std = "26"
-elif std == "cxx23":
-    std = "23"
-elif std == "cxx20":
-    std = "20"
-else:
-    std = ""
-
-if (
-    std
-    and not "libcpp-has-no-std-modules" in config.available_features
-    and not "clang-modules-build" in config.available_features
-):
-    build = os.path.join(config.test_exec_root, "__config_module__")
-    config.substitutions = appendToSubstitution(
-        config.substitutions,
-        "%{compile_flags}",
-        "-fprebuilt-module-path="
-        + os.path.join(config.test_exec_root, "__config_module__/CMakeFiles/std.dir"),
-    )
-
-    cmake = getSubstitution("%{cmake}", config)
-    flags = getSubstitution("%{flags}", config)
-    if "c++experimental" in config.available_features:
-        flags = f"{flags} -D_LIBCPP_ENABLE_EXPERIMENTAL"
-
-    subprocess.check_call(
-        [cmake, f"-DCMAKE_CXX_STANDARD={std}", f"-DCMAKE_CXX_FLAGS={flags}", build],
-        env={},
-    )
-    subprocess.check_call([cmake, "--build", build, "--", "-v"], env={})
-    config.substitutions = appendToSubstitution(
-        config.substitutions,
-        "%{link_flags}",
-        os.path.join(build, "libc++std.a"),
-    )
-
-    config.substitutions = appendToSubstitution(
-        config.substitutions,
-        "%{compile_flags}",
-        "-fprebuilt-module-path="
-        + os.path.join(
-            config.test_exec_root, "__config_module__/CMakeFiles/std.compat.dir"
-        ),
-    )
-    config.substitutions = appendToSubstitution(
-        config.substitutions,
-        "%{link_flags}",
-        os.path.join(build, "libc++std.compat.a"),
-    )
diff --git a/libcxx/test/std/modules/std.compat.pass.cpp b/libcxx/test/std/modules/std.compat.pass.cpp
index a33ed3b6b64533..ba75f8e4010027 100644
--- a/libcxx/test/std/modules/std.compat.pass.cpp
+++ b/libcxx/test/std/modules/std.compat.pass.cpp
@@ -7,10 +7,10 @@
 //===----------------------------------------------------------------------===//
 
 // UNSUPPORTED: c++03, c++11, c++14, c++17
-
-// UNSUPPORTED: libcpp-has-no-std-modules
 // UNSUPPORTED: clang-modules-build
 
+// XFAIL: *
+
 // A minimal test to validate import works.
 
 import std.compat;
diff --git a/libcxx/test/std/modules/std.pass.cpp b/libcxx/test/std/modules/std.pass.cpp
index 8ec3ce27322b74..a018e42a265891 100644
--- a/libcxx/test/std/modules/std.pass.cpp
+++ b/libcxx/test/std/modules/std.pass.cpp
@@ -7,10 +7,10 @@
 //===----------------------------------------------------------------------===//
 
 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
-
-// UNSUPPORTED: libcpp-has-no-std-modules
 // UNSUPPORTED: clang-modules-build
 
+// XFAIL: *
+
 // A minimal test to validate import works.
 
 import std;
diff --git a/libcxx/utils/ci/Dockerfile b/libcxx/utils/ci/Dockerfile
index e4bda4f06742c1..225de937cc869a 100644
--- a/libcxx/utils/ci/Dockerfile
+++ b/libcxx/utils/ci/Dockerfile
@@ -152,17 +152,6 @@ RUN <<EOF
     wget https://github.com/Kitware/CMake/releases/download/v3.21.1/cmake-3.21.1-linux-x86_64.sh -O /tmp/install-cmake.sh
     sudo bash /tmp/install-cmake.sh --prefix=/usr --exclude-subdir --skip-license
     rm /tmp/install-cmake.sh
-
-    # Install a newer CMake for modules
-    # TODO Remove the duplicated installation when all runtimes can be build with CMake 3.28.
-    wget https://github.com/Kitware/CMake/releases/download/v3.27.1/cmake-3.27.1-linux-x86_64.sh -O /tmp/install-cmake.sh
-    sudo bash /tmp/install-cmake.sh --prefix=/opt --exclude-subdir --skip-license
-    rm /tmp/install-cmake.sh
-
-    wget https://github.com/Kitware/CMake/releases/download/v3.28.0-rc4/cmake-3.28.0-rc4-linux-x86_64.sh -O /tmp/install-cmake.sh
-    sudo mkdir /opt/cmake-3.28
-    sudo bash /tmp/install-cmake.sh --prefix=/opt/cmake-3.28 --exclude-subdir --skip-license
-    rm /tmp/install-cmake.sh
 EOF
 
 # ===----------------------------------------------------------------------===##
diff --git a/libcxx/utils/ci/buildkite-pipeline.yml b/libcxx/utils/ci/buildkite-pipeline.yml
index a48f8524ef63c4..a7c44dab709391 100644
--- a/libcxx/utils/ci/buildkite-pipeline.yml
+++ b/libcxx/utils/ci/buildkite-pipeline.yml
@@ -48,7 +48,6 @@ environment_definitions:
       CLANG_CRASH_DIAGNOSTICS_DIR: "crash_diagnostics"
       CC: clang-${LLVM_HEAD_VERSION}
       CXX: clang++-${LLVM_HEAD_VERSION}
-      CMAKE: /opt/bin/cmake
 
   _absolute_path_clang: &absolute_path_clang
     # Note modules require and absolute path for clang-scan-deps
@@ -262,7 +261,6 @@ steps:
     env:
       CC: clang16
       CXX: clang++16
-      ENABLE_STD_MODULES: 'Off'
     agents:
       queue: libcxx-builders
       os: freebsd
diff --git a/libcxx/utils/ci/run-buildbot b/libcxx/utils/ci/run-buildbot
index 672d5cb70ae816..2e91f036811a43 100755
--- a/libcxx/utils/ci/run-buildbot
+++ b/libcxx/utils/ci/run-buildbot
@@ -47,11 +47,6 @@ CLANG_FORMAT        The clang-format binary to use when generating the format
 ENABLE_CLANG_TIDY   Whether to compile and run clang-tidy checks. This variable
                     is optional.
 
-ENABLE_STD_MODULES  Whether to enable or disable building the C++23 std
-                    modules. This variable is optional.
-                    TODO MODULES remove when all supported compilers support
-                    modules.
-
 EOF
 }
 
@@ -120,10 +115,6 @@ if [ -z "${ENABLE_CLANG_TIDY}" ]; then
     ENABLE_CLANG_TIDY=Off
 fi
 
-if [ -n "${ENABLE_STD_MODULES}" ]; then
-    ENABLE_STD_MODULES="-DLIBCXX_ENABLE_STD_MODULES=${ENABLE_STD_MODULES}"
-fi
-
 function generate-cmake-base() {
     echo "--- Generating CMake"
     ${CMAKE} \
@@ -136,7 +127,6 @@ function generate-cmake-base() {
           -DLIBCXXABI_ENABLE_WERROR=YES \
           -DLIBUNWIND_ENABLE_WERROR=YES \
           -DLIBCXX_ENABLE_CLANG_TIDY=${ENABLE_CLANG_TIDY} \
-          ${ENABLE_STD_MODULES} \
           -DLLVM_LIT_ARGS="-sv --xunit-xml-output test-results.xml --timeout=1500 --time-tests" \
           "${@}"
 }
diff --git a/libcxx/utils/libcxx/test/features.py b/libcxx/utils/libcxx/test/features.py
index 77efbdf1310349..332def02980ca6 100644
--- a/libcxx/utils/libcxx/test/features.py
+++ b/libcxx/utils/libcxx/test/features.py
@@ -343,7 +343,6 @@ def _getAndroidDeviceApi(cfg):
     "_LIBCPP_HAS_NO_WIDE_CHARACTERS": "no-wide-characters",
     "_LIBCPP_HAS_NO_TIME_ZONE_DATABASE": "no-tzdb",
     "_LIBCPP_HAS_NO_UNICODE": "libcpp-has-no-unicode",
-    "_LIBCPP_HAS_NO_STD_MODULES":  "libcpp-has-no-std-modules",
     "_LIBCPP_PSTL_CPU_BACKEND_LIBDISPATCH": "libcpp-pstl-cpu-backend-libdispatch",
 }
 for macro, feature in macros.items():
diff --git a/libcxx/utils/libcxx/test/modules.py b/libcxx/utils/libcxx/test/modules.py
index bd19fac314dd9b..9362d52cb72d2c 100644
--- a/libcxx/utils/libcxx/test/modules.py
+++ b/libcxx/utils/libcxx/test/modules.py
@@ -118,9 +118,10 @@ def write_lit_configuration(self):
         print(
             f"""\
 // UNSUPPORTED: c++03, c++11, c++14, c++17
-// UNSUPPORTED: libcpp-has-no-std-modules
 // UNSUPPORTED: clang-modules-build
 
+// XFAIL: *
+
 // REQUIRES: has-clang-tidy
 
 // The GCC compiler flags are not always compatible with clang-tidy.

>From 10c2d9a35aafe8e21835a6274eddb780baaa6f2c Mon Sep 17 00:00:00 2001
From: Mark de Wever <koraq at xs4all.nl>
Date: Wed, 20 Dec 2023 20:43:38 +0100
Subject: [PATCH 2/2] [libc++][modules] Adds module testing.

This adds a new module test infrastructure. This requires tagging tests
using modules. The test runner uses this information to determine the
compiler flags needed to build and use the module.

Currently modules are build per test, which allows testing them for
tests with ADDITIONAL_COMPILE_FLAGS. At the moment only 4 tests use
modules. Therefore the performance penalty is not measurable. If in the
future more tests use modules it would be good to measure the overhead
and determine whether it's acceptable.
---
 libcxx/test/libcxx/module_std.gen.py          |  3 +-
 libcxx/test/libcxx/module_std_compat.gen.py   |  3 +-
 .../libcxx/selftest/modules/no-modules.sh.cpp | 12 +++
 .../modules/std-and-std.compat-module.sh.cpp  | 19 +++++
 .../libcxx/selftest/modules/std-module.sh.cpp | 21 ++++++
 .../selftest/modules/std.compat-module.sh.cpp | 21 ++++++
 .../modules/unknown-module.compile.pass.cpp   | 13 ++++
 libcxx/test/std/modules/std.compat.pass.cpp   |  4 +-
 libcxx/test/std/modules/std.pass.cpp          |  4 +-
 libcxx/utils/libcxx/test/features.py          | 13 ++++
 libcxx/utils/libcxx/test/format.py            | 73 +++++++++++++++++--
 libcxx/utils/libcxx/test/modules.py           |  5 +-
 12 files changed, 180 insertions(+), 11 deletions(-)
 create mode 100644 libcxx/test/libcxx/selftest/modules/no-modules.sh.cpp
 create mode 100644 libcxx/test/libcxx/selftest/modules/std-and-std.compat-module.sh.cpp
 create mode 100644 libcxx/test/libcxx/selftest/modules/std-module.sh.cpp
 create mode 100644 libcxx/test/libcxx/selftest/modules/std.compat-module.sh.cpp
 create mode 100644 libcxx/test/libcxx/selftest/modules/unknown-module.compile.pass.cpp

diff --git a/libcxx/test/libcxx/module_std.gen.py b/libcxx/test/libcxx/module_std.gen.py
index 8e03d6e5b5b523..3ad2aff9d085f4 100644
--- a/libcxx/test/libcxx/module_std.gen.py
+++ b/libcxx/test/libcxx/module_std.gen.py
@@ -29,7 +29,8 @@
     "%{clang-tidy}",
     "%{test-tools}/clang_tidy_checks/libcxx-tidy.plugin",
     "%{cxx}",
-    "%{flags} %{compile_flags}",
+    "%{flags} %{compile_flags} %{module_flags}",
+    "std",
 )
 
 
diff --git a/libcxx/test/libcxx/module_std_compat.gen.py b/libcxx/test/libcxx/module_std_compat.gen.py
index c4792db3d71e62..63fdd8188937e1 100644
--- a/libcxx/test/libcxx/module_std_compat.gen.py
+++ b/libcxx/test/libcxx/module_std_compat.gen.py
@@ -29,7 +29,8 @@
     "%{clang-tidy}",
     "%{test-tools}/clang_tidy_checks/libcxx-tidy.plugin",
     "%{cxx}",
-    "%{flags} %{compile_flags}",
+    "%{flags} %{compile_flags} %{module_flags}",
+    "std.compat",
 )
 
 
diff --git a/libcxx/test/libcxx/selftest/modules/no-modules.sh.cpp b/libcxx/test/libcxx/selftest/modules/no-modules.sh.cpp
new file mode 100644
index 00000000000000..86d0afc13e3c40
--- /dev/null
+++ b/libcxx/test/libcxx/selftest/modules/no-modules.sh.cpp
@@ -0,0 +1,12 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// Make sure that the module flags are empty when no module is supplied.
+
+// MODULES:
+// RUN: echo "%{module_flags}"  | grep "^$"
diff --git a/libcxx/test/libcxx/selftest/modules/std-and-std.compat-module.sh.cpp b/libcxx/test/libcxx/selftest/modules/std-and-std.compat-module.sh.cpp
new file mode 100644
index 00000000000000..75f107c70d9429
--- /dev/null
+++ b/libcxx/test/libcxx/selftest/modules/std-and-std.compat-module.sh.cpp
@@ -0,0 +1,19 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// XFAIL: has-no-module-support
+
+// Make sure that the module flags contain the expected elements.
+// The tests only look for the expected components and not the exact flags.
+// Otherwise changing the location of the module breaks this test.
+
+// MODULES: std std.compat
+//
+// RUN: echo "%{module_flags}" | grep -- "-fprebuilt-module-path="
+// RUN: echo "%{module_flags}" | grep "std.pcm"
+// RUN: echo "%{module_flags}" | grep "std.compat.pcm"
diff --git a/libcxx/test/libcxx/selftest/modules/std-module.sh.cpp b/libcxx/test/libcxx/selftest/modules/std-module.sh.cpp
new file mode 100644
index 00000000000000..3572607baa4e3e
--- /dev/null
+++ b/libcxx/test/libcxx/selftest/modules/std-module.sh.cpp
@@ -0,0 +1,21 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// XFAIL: has-no-module-support
+
+// Make sure that the module flags contain the expected elements.
+// The tests only look for the expected components and not the exact flags.
+// Otherwise changing the location of the module breaks this test.
+
+// MODULES: std
+//
+// RUN: echo "%{module_flags}" | grep -- "-fprebuilt-module-path="
+// RUN: echo "%{module_flags}" | grep "std.pcm"
+
+// The std module should not provide the std.compat module
+// RUN: echo "%{module_flags}" | grep -v "std.compat.pcm"
diff --git a/libcxx/test/libcxx/selftest/modules/std.compat-module.sh.cpp b/libcxx/test/libcxx/selftest/modules/std.compat-module.sh.cpp
new file mode 100644
index 00000000000000..a1e738153baa15
--- /dev/null
+++ b/libcxx/test/libcxx/selftest/modules/std.compat-module.sh.cpp
@@ -0,0 +1,21 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// XFAIL: has-no-module-support
+
+// Make sure that the module flags contain the expected elements.
+// The tests only look for the expected components and not the exact flags.
+// Otherwise changing the location of the module breaks this test.
+
+// MODULES: std.compat
+//
+// RUN: echo "%{module_flags}" | grep -- "-fprebuilt-module-path="
+// RUN: echo "%{module_flags}" | grep "std.compat.pcm"
+
+// It's unspecified whether std.compat is built on the std module.
+// Therefore don't test its presence
diff --git a/libcxx/test/libcxx/selftest/modules/unknown-module.compile.pass.cpp b/libcxx/test/libcxx/selftest/modules/unknown-module.compile.pass.cpp
new file mode 100644
index 00000000000000..7c10f0db1e3401
--- /dev/null
+++ b/libcxx/test/libcxx/selftest/modules/unknown-module.compile.pass.cpp
@@ -0,0 +1,13 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// Make sure that modules that are unknown fail.
+
+// MODULES: this_module_is_not_a_standard_library_module
+
+// XFAIL: *
diff --git a/libcxx/test/std/modules/std.compat.pass.cpp b/libcxx/test/std/modules/std.compat.pass.cpp
index ba75f8e4010027..25cb4cac12f875 100644
--- a/libcxx/test/std/modules/std.compat.pass.cpp
+++ b/libcxx/test/std/modules/std.compat.pass.cpp
@@ -9,10 +9,12 @@
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 // UNSUPPORTED: clang-modules-build
 
-// XFAIL: *
+// XFAIL: has-no-module-support
 
 // A minimal test to validate import works.
 
+// MODULES: std.compat
+
 import std.compat;
 
 int main(int, char**) { return !(::strlen("Hello modular world") == 19); }
diff --git a/libcxx/test/std/modules/std.pass.cpp b/libcxx/test/std/modules/std.pass.cpp
index a018e42a265891..ed10a8228e07ae 100644
--- a/libcxx/test/std/modules/std.pass.cpp
+++ b/libcxx/test/std/modules/std.pass.cpp
@@ -9,10 +9,12 @@
 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
 // UNSUPPORTED: clang-modules-build
 
-// XFAIL: *
+// XFAIL: has-no-module-support
 
 // A minimal test to validate import works.
 
+// MODULES: std
+
 import std;
 
 int main(int, char**) {
diff --git a/libcxx/utils/libcxx/test/features.py b/libcxx/utils/libcxx/test/features.py
index 332def02980ca6..58c33e5bb37475 100644
--- a/libcxx/utils/libcxx/test/features.py
+++ b/libcxx/utils/libcxx/test/features.py
@@ -317,6 +317,19 @@ def _getAndroidDeviceApi(cfg):
             AddSubstitution("%{clang-tidy}", lambda cfg: _getSuitableClangTidy(cfg))
         ],
     ),
+    # Whether module support for the platform is available.
+    Feature(
+        name="has-no-module-support",
+        # The libc of these platforms have functions with internal linkages.
+        # This is not allowed per C11 7.1.2 Standard headers/6
+        #  Any declaration of a library function shall have external linkage.
+        when=lambda cfg: "__ANDROID__" in compilerMacros(cfg)
+        or "__PICOLIBC__" in compilerMacros(cfg)
+        or platform.system().lower().startswith("aix")
+        # Avoid building on platforms that don't support modules properly.
+        or not hasCompileFlag(cfg, "-Wno-reserved-module-identifier"),
+    ),
+
 ]
 
 # Deduce and add the test features that that are implied by the #defines in
diff --git a/libcxx/utils/libcxx/test/format.py b/libcxx/utils/libcxx/test/format.py
index e58e404bfcd2a5..058d4b2155c69d 100644
--- a/libcxx/utils/libcxx/test/format.py
+++ b/libcxx/utils/libcxx/test/format.py
@@ -91,6 +91,8 @@ def parseScript(test, preamble):
     # Parse the test file, including custom directives
     additionalCompileFlags = []
     fileDependencies = []
+    modules = []  # The enabled modules
+    moduleCompileFlags = []  # The compilation flags to use modules
     parsers = [
         lit.TestRunner.IntegratedTestKeywordParser(
             "FILE_DEPENDENCIES:",
@@ -102,6 +104,11 @@ def parseScript(test, preamble):
             lit.TestRunner.ParserKind.SPACE_LIST,
             initial_value=additionalCompileFlags,
         ),
+        lit.TestRunner.IntegratedTestKeywordParser(
+            "MODULES:",
+            lit.TestRunner.ParserKind.SPACE_LIST,
+            initial_value=modules,
+        ),
     ]
 
     # Add conditional parsers for ADDITIONAL_COMPILE_FLAGS. This should be replaced by first
@@ -131,6 +138,48 @@ def parseScript(test, preamble):
     script += preamble
     script += scriptInTest
 
+    has_std_module = False
+    has_std_compat_module = False
+    for module in modules:
+        if module == "std":
+            has_std_module = True
+        elif module == "std.compat":
+            has_std_compat_module = True
+        else:
+             script.insert(0, f"echo \"The module '{module}' is not valid, use 'std' or 'std.compat'\"")
+             script.insert(1, "false");
+             return script
+
+    if modules:
+        # This flag is needed for both modules.
+        moduleCompileFlags.append("-fprebuilt-module-path=%T")
+
+        # Building the modules needs to happen before the other script commands
+        # are executed. Therefore the commands are added to the front of the
+        # list.
+        if has_std_compat_module:
+            script.insert(
+                0,
+                "%dbg(MODULE std.compat) %{cxx} %{flags} %{compile_flags} "
+                "-Wno-reserved-module-identifier -Wno-reserved-user-defined-literal "
+                "--precompile -o %T/std.compat.pcm -c %{module}/std.compat.cppm",
+            )
+            moduleCompileFlags.append("%T/std.compat.pcm")
+
+        # Make sure the std module is added before std.compat.
+        # Libc++'s std.compat module will depend on its std module.
+        # It is not known whether the compiler expects the modules in the order
+        # of their dependencies. However it's trivial to provide them in that
+        # order.
+        if has_std_module:
+            script.insert(
+                0,
+                "%dbg(MODULE std) %{cxx} %{flags} %{compile_flags} "
+                "-Wno-reserved-module-identifier -Wno-reserved-user-defined-literal "
+                "--precompile -o %T/std.pcm -c %{module}/std.cppm",
+            )
+            moduleCompileFlags.append("%T/std.pcm")
+
     # Add compile flags specified with ADDITIONAL_COMPILE_FLAGS.
     substitutions = [
         (s, x + " " + " ".join(additionalCompileFlags))
@@ -138,6 +187,13 @@ def parseScript(test, preamble):
         else (s, x)
         for (s, x) in substitutions
     ]
+    # In order to use modules additional compilation flags are required.
+    # Adding these to the %{compile_flags} gives a chicken and egg issue:
+    # - the modules need to be build with the same compilation flags as the
+    #   tests,
+    # - except for the module dependency, which does not exist.
+    # The issue is resolved by adding a private substitution.
+    substitutions.append(("%{module_flags}", " ".join(moduleCompileFlags)))
 
     # Perform substitutions in the script itself.
     script = lit.TestRunner.applySubstitutions(
@@ -191,6 +247,7 @@ class CxxStandardLibraryTest(lit.formats.FileBasedTest):
     constructs:
         %{cxx}           - A command that can be used to invoke the compiler
         %{compile_flags} - Flags to use when compiling a test case
+        %{module_flags}  - Flags to use when compiling a test case that imports modules
         %{link_flags}    - Flags to use when linking a test case
         %{flags}         - Flags to use either when compiling or linking a test case
         %{exec}          - A command to prefix the execution of executables
@@ -223,6 +280,12 @@ class CxxStandardLibraryTest(lit.formats.FileBasedTest):
             allows adding special compilation flags without having to use a
             .sh.cpp test, which would be more powerful but perhaps overkill.
 
+        // MODULE: std std.compat
+
+           This directive will build the required C++23 standard library
+           modules and add the provide the additional compiler flags in
+           %{module_flags}. (Libc++ offers these modules in C++20 as an
+           extenstion.)
 
     Additional provided substitutions and features
     ==============================================
@@ -288,22 +351,22 @@ def execute(self, test, litConfig):
             ".compile.pass.mm"
         ):
             steps = [
-                "%dbg(COMPILED WITH) %{cxx} %s %{flags} %{compile_flags} -fsyntax-only"
+                "%dbg(COMPILED WITH) %{cxx} %s %{flags} %{compile_flags} %{module_flags} -fsyntax-only"
             ]
             return self._executeShTest(test, litConfig, steps)
         elif filename.endswith(".compile.fail.cpp"):
             steps = [
-                "%dbg(COMPILED WITH) ! %{cxx} %s %{flags} %{compile_flags} -fsyntax-only"
+                "%dbg(COMPILED WITH) ! %{cxx} %s %{flags} %{compile_flags} %{module_flags} -fsyntax-only"
             ]
             return self._executeShTest(test, litConfig, steps)
         elif filename.endswith(".link.pass.cpp") or filename.endswith(".link.pass.mm"):
             steps = [
-                "%dbg(COMPILED WITH) %{cxx} %s %{flags} %{compile_flags} %{link_flags} -o %t.exe"
+                "%dbg(COMPILED WITH) %{cxx} %s %{flags} %{compile_flags} %{module_flags} %{link_flags} -o %t.exe"
             ]
             return self._executeShTest(test, litConfig, steps)
         elif filename.endswith(".link.fail.cpp"):
             steps = [
-                "%dbg(COMPILED WITH) %{cxx} %s %{flags} %{compile_flags} -c -o %t.o",
+                "%dbg(COMPILED WITH) %{cxx} %s %{flags} %{compile_flags} %{module_flags} -c -o %t.o",
                 "%dbg(LINKED WITH) ! %{cxx} %t.o %{flags} %{link_flags} -o %t.exe",
             ]
             return self._executeShTest(test, litConfig, steps)
@@ -321,7 +384,7 @@ def execute(self, test, litConfig):
         # suffixes above too.
         elif filename.endswith(".pass.cpp") or filename.endswith(".pass.mm"):
             steps = [
-                "%dbg(COMPILED WITH) %{cxx} %s %{flags} %{compile_flags} %{link_flags} -o %t.exe",
+                "%dbg(COMPILED WITH) %{cxx} %s %{flags} %{compile_flags} %{module_flags} %{link_flags} -o %t.exe",
                 "%dbg(EXECUTED AS) %{exec} %t.exe",
             ]
             return self._executeShTest(test, litConfig, steps)
diff --git a/libcxx/utils/libcxx/test/modules.py b/libcxx/utils/libcxx/test/modules.py
index 9362d52cb72d2c..e2e94c239f21c7 100644
--- a/libcxx/utils/libcxx/test/modules.py
+++ b/libcxx/utils/libcxx/test/modules.py
@@ -113,6 +113,7 @@ class module_test_generator:
     clang_tidy_plugin: str
     compiler: str
     compiler_flags: str
+    module: str
 
     def write_lit_configuration(self):
         print(
@@ -120,13 +121,13 @@ def write_lit_configuration(self):
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 // UNSUPPORTED: clang-modules-build
 
-// XFAIL: *
-
 // REQUIRES: has-clang-tidy
 
 // The GCC compiler flags are not always compatible with clang-tidy.
 // UNSUPPORTED: gcc
 
+// MODULES: {self.module}
+
 // RUN: echo -n > {self.tmp_prefix}.all_partitions
 """
         )



More information about the llvm-commits mailing list