diff --git a/libcxx/modules/std.cppm.in b/libcxx/modules/std.cppm.in --- a/libcxx/modules/std.cppm.in +++ b/libcxx/modules/std.cppm.in @@ -7,19 +7,25 @@ // //===----------------------------------------------------------------------===// +// WARNING, this entire header is generated by +// utils/generate_std_cppm_in.py +// DO NOT MODIFY! + module; #include <__config> -// TODO MODULES This could be generated - // 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] #include #include #include -#include -#include +#if !defined(_LIBCPP_HAS_NO_ATOMIC_HEADER) +# include +#endif +#if !defined(_LIBCPP_HAS_NO_THREADS) +# include +#endif #include #include #include @@ -31,7 +37,13 @@ #include #include #include +#if !defined(_LIBCPP_HAS_NO_LOCALIZATION) +# include +#endif #include +#if !defined(_LIBCPP_HAS_NO_LOCALIZATION) +# include +#endif #include #include #include @@ -47,6 +59,12 @@ #include #include #include +#if !defined(_LIBCPP_HAS_NO_WIDE_CHARACTERS) +# include +#endif +#if !defined(_LIBCPP_HAS_NO_WIDE_CHARACTERS) +# include +#endif #include #include #include @@ -54,14 +72,36 @@ #include #include #include +#if !defined(_LIBCPP_HAS_NO_LOCALIZATION) +# include +#endif #include -#include +#if !defined(_LIBCPP_HAS_NO_THREADS) +# include +#endif #include +#if !defined(_LIBCPP_HAS_NO_LOCALIZATION) +# include +#endif +#if !defined(_LIBCPP_HAS_NO_LOCALIZATION) +# include +#endif #include +#if !defined(_LIBCPP_HAS_NO_LOCALIZATION) +# include +#endif +#if !defined(_LIBCPP_HAS_NO_LOCALIZATION) +# include +#endif #include -#include +#if !defined(_LIBCPP_HAS_NO_THREADS) +# include +#endif #include #include +#if !defined(_LIBCPP_HAS_NO_LOCALIZATION) +# include +#endif #include #include #include @@ -71,24 +111,47 @@ #include #include #include +#if !defined(_LIBCPP_HAS_NO_LOCALIZATION) +# include +#endif #include #include #include #include #include +#if !defined(_LIBCPP_HAS_NO_LOCALIZATION) +# include +#endif #include -#include +#if !defined(_LIBCPP_HAS_NO_THREADS) +# include +#endif #include -#include +#if !defined(_LIBCPP_HAS_NO_THREADS) +# include +#endif #include #include +#if !defined(_LIBCPP_HAS_NO_LOCALIZATION) +# include +#endif #include #include -#include +#if !defined(_LIBCPP_HAS_NO_THREADS) +# include +#endif +#if !defined(_LIBCPP_HAS_NO_LOCALIZATION) +# include +#endif #include #include +#if !defined(_LIBCPP_HAS_NO_LOCALIZATION) +# include +#endif #include -#include +#if !defined(_LIBCPP_HAS_NO_THREADS) +# include +#endif #include #include #include @@ -101,68 +164,36 @@ #include #include -// *** Headers disabled by a feature *** - -#ifndef _LIBCPP_HAS_NO_LOCALIZATION -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -#endif // _LIBCPP_HAS_NO_LOCALIZATION -#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS -# include -# include -#endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS - // *** Headers not yet available *** +#if __has_include() +# error "update the header information for in libcxx/utils/generate_std_cppm_in.py" +#endif // __has_include() +#if __has_include() +# error "update the header information for in libcxx/utils/generate_std_cppm_in.py" +#endif // __has_include() #if __has_include() -# error "include unconditionally" -# include +# error "update the header information for in libcxx/utils/generate_std_cppm_in.py" #endif // __has_include() #if __has_include() -# error "include unconditionally" -# include +# error "update the header information for in libcxx/utils/generate_std_cppm_in.py" #endif // __has_include() -#if __has_include() -# error "include unconditionally" -# include -#endif // __has_include() -#if __has_include() -# error "include unconditionally" -# include -#endif // __has_include() #if __has_include() -# error "include unconditionally" -# include +# error "update the header information for in libcxx/utils/generate_std_cppm_in.py" #endif // __has_include() #if __has_include() -# error "include unconditionally" -# include +# error "update the header information for in libcxx/utils/generate_std_cppm_in.py" #endif // __has_include() #if __has_include() -# error "include unconditionally" -# include +# error "update the header information for in libcxx/utils/generate_std_cppm_in.py" #endif // __has_include() #if __has_include() -# error "include unconditionally" -# include +# error "update the header information for in libcxx/utils/generate_std_cppm_in.py" #endif // __has_include() #if __has_include() -# error "include unconditionally" -# include +# error "update the header information for in libcxx/utils/generate_std_cppm_in.py" #endif // __has_include() #if __has_include() -# error "include unconditionally" -# include +# error "update the header information for in libcxx/utils/generate_std_cppm_in.py" #endif // __has_include() export module std; diff --git a/libcxx/test/libcxx/module_std.gen.py b/libcxx/test/libcxx/module_std.gen.py --- a/libcxx/test/libcxx/module_std.gen.py +++ b/libcxx/test/libcxx/module_std.gen.py @@ -21,22 +21,12 @@ import sys sys.path.append(sys.argv[1]) -from libcxx.header_information import toplevel_headers +from libcxx.header_information import module_headers BLOCKLIT = ( "" # block Lit from interpreting a RUN/XFAIL/etc inside the generation script ) -### Remove the headers that have no module associated with them - -# Note all C-headers using .h are filtered in the loop. - -# These headers are not available in C++23, but in older language Standards. -toplevel_headers.remove("ccomplex") -toplevel_headers.remove("ciso646") -toplevel_headers.remove("cstdbool") -toplevel_headers.remove("ctgmath") - # Ignore several declarations found in the includes. # # Part of these items are bugs other are not yet implemented features. @@ -140,10 +130,7 @@ ) # Validate all module parts. -for header in toplevel_headers: - if header.endswith(".h"): # Skip C compatibility headers - continue - +for header in module_headers: # Generate a module partition for the header module includes. This # makes it possible to verify that all headers export all their # named declarations. diff --git a/libcxx/utils/CMakeLists.txt b/libcxx/utils/CMakeLists.txt --- a/libcxx/utils/CMakeLists.txt +++ b/libcxx/utils/CMakeLists.txt @@ -6,6 +6,10 @@ COMMAND "${Python3_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/generate_std_clang_module_header.py" COMMENT "Generate the <__std_clang_module> header") +add_custom_target(libcxx-generate-std-cppm-in-file + COMMAND "${Python3_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/generate_std_cppm_in.py" + COMMENT "Generate the std.cppm.in file") + add_custom_target(libcxx-generate-extended-grapheme-cluster-tables COMMAND "${Python3_EXECUTABLE}" @@ -43,6 +47,7 @@ add_custom_target(libcxx-generate-files DEPENDS libcxx-generate-feature-test-macros libcxx-generate-std-clang-module-header + libcxx-generate-std-cppm-in-file libcxx-generate-extended-grapheme-cluster-tables libcxx-generate-extended-grapheme-cluster-tests libcxx-generate-escaped-output-table diff --git a/libcxx/utils/generate_std_cppm_in.py b/libcxx/utils/generate_std_cppm_in.py new file mode 100644 --- /dev/null +++ b/libcxx/utils/generate_std_cppm_in.py @@ -0,0 +1,74 @@ +# ===----------------------------------------------------------------------===## +# +# 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 +# +# ===----------------------------------------------------------------------===## + +import operator +import os.path + +from libcxx.header_information import module_headers +from libcxx.header_information import header_restrictions +from libcxx.header_information import headers_not_available + + +libcxx_module_directory = os.path.join( + os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "modules" +) +with open( + os.path.join(libcxx_module_directory, "std.cppm.in"), "w" +) as std_module_cpp_in: + std_module_cpp_in.write( + """\ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// WARNING, this entire header is generated by +// utils/generate_std_cppm_in.py +// DO NOT MODIFY! + +module; + +#include <__config> + +// 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] +""" + ) + for header in module_headers: + if header in header_restrictions: + std_module_cpp_in.write( + f"""\ +#if {header_restrictions[header]} +# include <{header}> +#endif +""" + ) + else: + std_module_cpp_in.write(f"#include <{header}>\n") + + std_module_cpp_in.write("\n// *** Headers not yet available ***\n") + for header in sorted(headers_not_available): + std_module_cpp_in.write( + f"""\ +#if __has_include(<{header}>) +# error "update the header information for <{header}> in libcxx/utils/generate_std_cppm_in.py" +#endif // __has_include(<{header}>) +""" + ) + + std_module_cpp_in.write( + """ +export module std; + +@LIBCXX_MODULE_STD_INCLUDE_SOURCES@ +""" + ) diff --git a/libcxx/utils/libcxx/header_information.py b/libcxx/utils/libcxx/header_information.py --- a/libcxx/utils/libcxx/header_information.py +++ b/libcxx/utils/libcxx/header_information.py @@ -141,6 +141,27 @@ "vector": ["compare", "initializer_list"], } + +# These headers are not yet implemented in libc++ +# +# These headers are required by the latest (draft) Standard but have not been +# implemented yet. They are used in the generated module input. When the header +# is added and this list is not updated the C++23 standard modules will fail to +# build. +headers_not_available = [ + "flat_map", + "flat_set", + "generator", + "hazard_pointer", + "rcu", + "spanstream", + "stacktrace", + "stdfloat", + "syncstream", + "text_encoding", +] + + def is_header(file): """Returns whether the given file is a header (i.e. not a directory or the modulemap file).""" return ( @@ -159,6 +180,17 @@ p.relative_to(include).as_posix() for p in include.glob("[a-z]*") if is_header(p) ) experimental_headers = sorted( - p.relative_to(include).as_posix() for p in include.glob("experimental/[a-z]*") if is_header(p) + p.relative_to(include).as_posix() + for p in include.glob("experimental/[a-z]*") + if is_header(p) ) public_headers = toplevel_headers + experimental_headers + +# The headers used in the std and std.compat modules. +module_headers = [ + header + for header in toplevel_headers + if not header.endswith(".h") + # These headers have been removed in C++20 so never are part of a module. + and not header in ["ccomplex", "ciso646", "cstdbool", "ctgmath"] +]