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,19 @@ // //===----------------------------------------------------------------------===// +// 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 #include #include #include @@ -55,11 +55,9 @@ #include #include #include -#include #include #include #include -#include #include #include #include @@ -77,18 +75,14 @@ #include #include #include -#include #include -#include #include #include #include #include -#include #include #include #include -#include #include #include #include @@ -103,6 +97,10 @@ // *** Headers disabled by a feature *** +#ifndef _LIBCPP_HAS_NO_ATOMIC_HEADER +# include +#endif // _LIBCPP_HAS_NO_ATOMIC_HEADER + #ifndef _LIBCPP_HAS_NO_LOCALIZATION # include # include @@ -118,52 +116,53 @@ # include # include #endif // _LIBCPP_HAS_NO_LOCALIZATION + +#ifndef _LIBCPP_HAS_NO_THREADS +# include +# include +# include +# include +# include +# include +# include +#endif // _LIBCPP_HAS_NO_THREADS + #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS # include # include #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS // *** Headers not yet available *** -#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 -#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 -#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 -#endif // __has_include() -#if __has_include() -# error "include unconditionally" -# include -#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 "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 "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 "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 "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 "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. @@ -139,10 +129,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,100 @@ +# ===----------------------------------------------------------------------===## +# +# 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 + +import libcxx.header_information + + +header_include_requirements = libcxx.header_information.header_include_requirements + + +always_available_headers = frozenset( + libcxx.header_information.module_headers +).difference(*header_include_requirements.values()) + +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] +""" + ) + # Include the angle brackets in sorting so that sorts before + # like check-format wants. + for include in sorted([f"<{header}>" for header in always_available_headers]): + std_module_cpp_in.write(f"#include {include}\n") + + std_module_cpp_in.write("\n// *** Headers disabled by a feature ***\n") + for requirements, headers in sorted( + header_include_requirements.items(), key=operator.itemgetter(0) + ): + std_module_cpp_in.write("\n") + if len(requirements) == 1: + std_module_cpp_in.write(f"#ifndef {requirements[0]}") + else: + std_module_cpp_in.write("#if") + for index, requirement in enumerate(requirements): + if index > 0: + std_module_cpp_in.write(" &&") + std_module_cpp_in.write(f" !defined({requirement})") + std_module_cpp_in.write("\n") + + for include in sorted([f"<{header}>" for header in headers]): + if include.endswith(".h>"): # Skip C compatibility headers + continue + if ( + include == "" + ): # TODO MODULES remove when header this header is removed from libc++ + continue + std_module_cpp_in.write(f"# include {include}\n") + + std_module_cpp_in.write(f"#endif // {requirements[0]}\n") + + std_module_cpp_in.write("\n// *** Headers not yet available ***\n") + for include in sorted( + [f"<{header}>" for header in libcxx.header_information.headers_not_available] + ): + std_module_cpp_in.write( + f"""\ +# if __has_include({include}) +# error "update the header information for {include} in libcxx/utils/generate_std_cppm_in.py" +# endif // __has_include({include}) +""" + ) + + 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 @@ -147,6 +147,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 ( @@ -165,6 +186,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"] +]