diff --git a/libcxx/docs/Contributing.rst b/libcxx/docs/Contributing.rst --- a/libcxx/docs/Contributing.rst +++ b/libcxx/docs/Contributing.rst @@ -49,7 +49,7 @@ - Did you add it to ``include/module.modulemap.in``? - Did you add it to ``include/CMakeLists.txt``? - - If it's a public header, did you update ``utils/libcxx/test/header_information.py``? + - If it's a public header, did you update ``utils/libcxx/header_information.py``? - Did you add the relevant feature test macro(s) for your feature? Did you update the ``generate_feature_test_macro_components.py`` script with it? - Did you run the ``libcxx-generate-files`` target and verify its output? diff --git a/libcxx/include/__std_clang_module b/libcxx/include/__std_clang_module --- a/libcxx/include/__std_clang_module +++ b/libcxx/include/__std_clang_module @@ -17,7 +17,6 @@ # error "Do not include this header directly, include individual headers instead" #endif -#include <__availability> #include <__config> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -27,52 +26,109 @@ #include <algorithm> #include <any> #include <array> -#include <atomic> #include <bit> #include <bitset> +#include <cassert> +#include <ccomplex> +#include <cctype> +#include <cerrno> +#include <cfenv> +#include <cfloat> #include <charconv> #include <chrono> +#include <cinttypes> +#include <ciso646> +#include <climits> +#include <cmath> #include <compare> #include <complex> +#include <complex.h> #include <concepts> #include <condition_variable> +#include <coroutine> +#include <csetjmp> +#include <csignal> +#include <cstdarg> +#include <cstdbool> +#include <cstddef> +#include <cstdint> +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include <ctgmath> +#include <ctime> +#include <ctype.h> +#include <cuchar> #include <deque> +#include <errno.h> #include <exception> #include <execution> #include <expected> +#include <experimental/deque> +#include <experimental/forward_list> +#include <experimental/iterator> +#include <experimental/list> +#include <experimental/map> +#include <experimental/memory_resource> +#include <experimental/propagate_const> +#include <experimental/set> +#include <experimental/simd> +#include <experimental/string> +#include <experimental/type_traits> +#include <experimental/unordered_map> +#include <experimental/unordered_set> +#include <experimental/utility> +#include <experimental/vector> +#include <fenv.h> +#include <filesystem> +#include <float.h> #include <format> #include <forward_list> #include <functional> #include <initializer_list> +#include <inttypes.h> #include <iosfwd> #include <iterator> #include <limits> +#include <limits.h> #include <list> #include <map> +#include <math.h> #include <mdspan> #include <memory> #include <memory_resource> +#include <mutex> #include <new> #include <numbers> #include <numeric> #include <optional> +#include <print> #include <queue> #include <random> #include <ranges> #include <ratio> #include <scoped_allocator> #include <set> +#include <setjmp.h> #include <source_location> #include <span> #include <stack> +#include <stdbool.h> +#include <stddef.h> #include <stdexcept> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> #include <string> +#include <string.h> #include <string_view> #include <system_error> +#include <tgmath.h> #include <tuple> #include <type_traits> #include <typeindex> #include <typeinfo> +#include <uchar.h> #include <unordered_map> #include <unordered_set> #include <utility> @@ -81,132 +137,43 @@ #include <vector> #include <version> -#include <cassert> -#include <ccomplex> -#include <cctype> -#include <cerrno> -#include <cfenv> -#include <cfloat> -#include <cinttypes> -#include <ciso646> -#include <climits> -#include <cmath> -#include <csetjmp> -#include <csignal> -#include <cstdarg> -#include <cstdbool> -#include <cstddef> -#include <cstdint> -#include <cstdio> -#include <cstdlib> -#include <cstring> -#include <ctgmath> -#include <ctime> -#include <cuchar> - -#include <complex.h> -#include <ctype.h> -#include <errno.h> -#include <fenv.h> -#include <float.h> -#include <inttypes.h> -#include <limits.h> -#include <math.h> -#include <setjmp.h> -#include <stdbool.h> -#include <stddef.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <tgmath.h> -#include <uchar.h> +#ifndef _LIBCPP_HAS_NO_ATOMIC_HEADER +# include <atomic> +# include <stdatomic.h> +#endif #ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include <clocale> # include <codecvt> -# ifndef _LIBCPP_HAS_NO_FILESYSTEM -# include <fstream> -# endif +# include <experimental/regex> +# include <fstream> # include <iomanip> # include <ios> # include <iostream> # include <istream> # include <locale> +# include <locale.h> # include <ostream> # include <regex> # include <sstream> # include <streambuf> # include <strstream> +#endif -# include <clocale> - -# include <locale.h> +#ifndef _LIBCPP_HAS_NO_THREADS +# include <barrier> +# include <future> +# include <latch> +# include <semaphore> +# include <shared_mutex> +# include <stop_token> +# include <thread> #endif #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS # include <cwchar> # include <cwctype> - # include <wchar.h> # include <wctype.h> #endif -#ifdef _LIBCPP_AVAILABILITY_TO_CHARS_FLOATING_POINT -# include <print> -#endif - -#ifndef _LIBCPP_CXX03_LANG -# ifndef _LIBCPP_HAS_NO_THREADS -# include <future> -# include <mutex> -# include <thread> -# endif - -# include <experimental/deque> -# include <experimental/forward_list> -# include <experimental/iterator> -# include <experimental/list> -# include <experimental/map> -# include <experimental/memory_resource> -# include <experimental/propagate_const> -# ifndef _LIBCPP_HAS_NO_LOCALIZATION -# include <experimental/regex> -# endif -# include <experimental/set> -# include <experimental/simd> -# include <experimental/string> -# include <experimental/type_traits> -# include <experimental/unordered_map> -# include <experimental/unordered_set> -# include <experimental/utility> -# include <experimental/vector> -#endif - -#if _LIBCPP_STD_VER >= 14 -# ifndef _LIBCPP_HAS_NO_THREADS -# include <shared_mutex> -# endif -#endif - -#if _LIBCPP_STD_VER >= 17 -# ifndef _LIBCPP_HAS_NO_FILESYSTEM -# include <filesystem> -# endif -#endif - -#if _LIBCPP_STD_VER >= 20 -# include <coroutine> - -# ifndef _LIBCPP_HAS_NO_THREADS -# include <barrier> -# include <latch> -# include <semaphore> -# include <stop_token> -# endif -#endif - -#if _LIBCPP_STD_VER >= 23 -# ifndef _LIBCPP_HAS_NO_THREADS -# include <stdatomic.h> -# endif -#endif diff --git a/libcxx/test/libcxx/assertions/headers_declare_verbose_abort.gen.py b/libcxx/test/libcxx/assertions/headers_declare_verbose_abort.gen.py --- a/libcxx/test/libcxx/assertions/headers_declare_verbose_abort.gen.py +++ b/libcxx/test/libcxx/assertions/headers_declare_verbose_abort.gen.py @@ -14,7 +14,7 @@ import sys sys.path.append(sys.argv[1]) -from libcxx.test.header_information import lit_header_restrictions, public_headers +from libcxx.header_information import lit_header_restrictions, public_headers for header in public_headers: # Skip C compatibility headers. diff --git a/libcxx/test/libcxx/clang_tidy.gen.py b/libcxx/test/libcxx/clang_tidy.gen.py --- a/libcxx/test/libcxx/clang_tidy.gen.py +++ b/libcxx/test/libcxx/clang_tidy.gen.py @@ -12,7 +12,7 @@ import sys sys.path.append(sys.argv[1]) -from libcxx.test.header_information import lit_header_restrictions, public_headers +from libcxx.header_information import lit_header_restrictions, public_headers for header in public_headers: BLOCKLIT = '' # block Lit from interpreting a RUN/XFAIL/etc inside the generation script diff --git a/libcxx/test/libcxx/double_include.gen.py b/libcxx/test/libcxx/double_include.gen.py --- a/libcxx/test/libcxx/double_include.gen.py +++ b/libcxx/test/libcxx/double_include.gen.py @@ -12,7 +12,7 @@ import sys sys.path.append(sys.argv[1]) -from libcxx.test.header_information import lit_header_restrictions, public_headers +from libcxx.header_information import lit_header_restrictions, public_headers for header in public_headers: BLOCKLIT = '' # block Lit from interpreting a RUN/XFAIL/etc inside the generation script diff --git a/libcxx/test/libcxx/header_inclusions.gen.py b/libcxx/test/libcxx/header_inclusions.gen.py --- a/libcxx/test/libcxx/header_inclusions.gen.py +++ b/libcxx/test/libcxx/header_inclusions.gen.py @@ -13,7 +13,7 @@ import sys sys.path.append(sys.argv[1]) -from libcxx.test.header_information import lit_header_restrictions, public_headers, mandatory_inclusions +from libcxx.header_information import lit_header_restrictions, public_headers, mandatory_inclusions for header in public_headers: header_guard = lambda h: f"_LIBCPP_{h.upper().replace('.', '_').replace('/', '_')}" diff --git a/libcxx/test/libcxx/libcpp_version.gen.py b/libcxx/test/libcxx/libcpp_version.gen.py --- a/libcxx/test/libcxx/libcpp_version.gen.py +++ b/libcxx/test/libcxx/libcpp_version.gen.py @@ -12,7 +12,7 @@ import sys sys.path.append(sys.argv[1]) -from libcxx.test.header_information import lit_header_restrictions, public_headers +from libcxx.header_information import lit_header_restrictions, public_headers for header in public_headers: print(f"""\ 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,7 +21,7 @@ import sys sys.path.append(sys.argv[1]) -from libcxx.test.header_information import toplevel_headers +from libcxx.header_information import toplevel_headers BLOCKLIT = ( "" # block Lit from interpreting a RUN/XFAIL/etc inside the generation script diff --git a/libcxx/test/libcxx/modules_include.gen.py b/libcxx/test/libcxx/modules_include.gen.py --- a/libcxx/test/libcxx/modules_include.gen.py +++ b/libcxx/test/libcxx/modules_include.gen.py @@ -14,10 +14,11 @@ import sys sys.path.append(sys.argv[1]) -from libcxx.test.header_information import lit_header_restrictions, public_headers +from libcxx.header_information import lit_header_restrictions, public_headers + +BLOCKLIT = '' # block Lit from interpreting a RUN/XFAIL/etc inside the generation script for header in public_headers: - BLOCKLIT = '' # block Lit from interpreting a RUN/XFAIL/etc inside the generation script print(f"""\ //--- {header}.compile.pass.cpp // RUN{BLOCKLIT}: %{{cxx}} %s %{{flags}} %{{compile_flags}} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only @@ -45,7 +46,7 @@ #include <{header}> """) -print(f""" +print(f"""\ //--- __std_clang_module.compile.pass.mm // RUN{BLOCKLIT}: %{{cxx}} %s %{{flags}} %{{compile_flags}} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only @@ -68,10 +69,6 @@ // TODO: Investigate this failure // UNSUPPORTED{BLOCKLIT}: LIBCXX-FREEBSD-FIXME -// Lit seems to compile this twice: once with the default flags and once with with -// the flags specified in the RUN directive. Guard the first compile from failing. -#if __has_feature(modules) @import std; -#endif """) diff --git a/libcxx/test/libcxx/no_assert_include.gen.py b/libcxx/test/libcxx/no_assert_include.gen.py --- a/libcxx/test/libcxx/no_assert_include.gen.py +++ b/libcxx/test/libcxx/no_assert_include.gen.py @@ -13,7 +13,7 @@ import sys sys.path.append(sys.argv[1]) -from libcxx.test.header_information import lit_header_restrictions, public_headers +from libcxx.header_information import lit_header_restrictions, public_headers for header in public_headers: if header == 'cassert': diff --git a/libcxx/test/libcxx/system_reserved_names.gen.py b/libcxx/test/libcxx/system_reserved_names.gen.py --- a/libcxx/test/libcxx/system_reserved_names.gen.py +++ b/libcxx/test/libcxx/system_reserved_names.gen.py @@ -13,7 +13,7 @@ import sys sys.path.append(sys.argv[1]) -from libcxx.test.header_information import lit_header_restrictions, public_headers +from libcxx.header_information import lit_header_restrictions, public_headers for header in public_headers: print(f"""\ diff --git a/libcxx/test/libcxx/transitive_includes.gen.py b/libcxx/test/libcxx/transitive_includes.gen.py --- a/libcxx/test/libcxx/transitive_includes.gen.py +++ b/libcxx/test/libcxx/transitive_includes.gen.py @@ -20,7 +20,7 @@ import sys sys.path.append(sys.argv[1]) -from libcxx.test.header_information import lit_header_restrictions, public_headers +from libcxx.header_information import lit_header_restrictions, public_headers import re diff --git a/libcxx/utils/CMakeLists.txt b/libcxx/utils/CMakeLists.txt --- a/libcxx/utils/CMakeLists.txt +++ b/libcxx/utils/CMakeLists.txt @@ -2,6 +2,10 @@ COMMAND "${Python3_EXECUTABLE}" "${LIBCXX_SOURCE_DIR}/utils/generate_feature_test_macro_components.py" COMMENT "Generate the <version> header and tests for feature test macros.") +add_custom_target(libcxx-generate-std-clang-module-header + 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-extended-grapheme-cluster-tables COMMAND "${Python3_EXECUTABLE}" @@ -38,6 +42,7 @@ add_custom_target(libcxx-generate-files DEPENDS libcxx-generate-feature-test-macros + libcxx-generate-std-clang-module-header libcxx-generate-extended-grapheme-cluster-tables libcxx-generate-extended-grapheme-cluster-tests libcxx-generate-escaped-output-table diff --git a/libcxx/utils/generate_std_clang_module_header.py b/libcxx/utils/generate_std_clang_module_header.py new file mode 100644 --- /dev/null +++ b/libcxx/utils/generate_std_clang_module_header.py @@ -0,0 +1,74 @@ +import operator +import os.path + +import libcxx.header_information + +public_headers = libcxx.header_information.public_headers +header_include_requirements = libcxx.header_information.header_include_requirements +always_available_headers = frozenset(public_headers).difference( + *header_include_requirements.values() +) + +libcxx_include_directory = os.path.join( + os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "include" +) +with open( + os.path.join(libcxx_include_directory, "__std_clang_module"), "w" +) as std_clang_module_header: + std_clang_module_header.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 +// +//===----------------------------------------------------------------------===// + +// This header should not be directly included, it's exclusively to import all +// of the libc++ public clang modules for the `std` clang module to export. In +// other words, it's to facilitate `@import std;` in Objective-C++ and `import std` +// in Swift to expose all of the libc++ interfaces. This is generally not +// recommended, however there are some clients that need to import all of libc++ +// without knowing what "all" is. +#if !__building_module(std) +# error "Do not include this header directly, include individual headers instead" +#endif + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +""" + ) + for header in sorted(always_available_headers): + std_clang_module_header.write("#include <") + std_clang_module_header.write(header) + std_clang_module_header.write(">\n") + std_clang_module_header.write("\n") + + for requirements, headers in sorted( + header_include_requirements.items(), key=operator.itemgetter(0) + ): + if len(requirements) == 1: + std_clang_module_header.write("#ifndef ") + std_clang_module_header.write(requirements[0]) + else: + std_clang_module_header.write("#if") + for index, requirement in enumerate(requirements): + if index > 0: + std_clang_module_header.write(" &&") + std_clang_module_header.write(" !defined(") + std_clang_module_header.write(requirement) + std_clang_module_header.write(")") + std_clang_module_header.write("\n") + + for header in sorted(headers): + std_clang_module_header.write("# include <") + std_clang_module_header.write(header) + std_clang_module_header.write(">\n") + + std_clang_module_header.write("#endif\n\n") diff --git a/libcxx/utils/libcxx/test/header_information.py b/libcxx/utils/libcxx/header_information.py rename from libcxx/utils/libcxx/test/header_information.py rename to libcxx/utils/libcxx/header_information.py --- a/libcxx/utils/libcxx/test/header_information.py +++ b/libcxx/utils/libcxx/header_information.py @@ -15,10 +15,8 @@ "coroutine": "// UNSUPPORTED: c++03, c++11, c++14, c++17", "cwchar": "// UNSUPPORTED: no-wide-characters", "cwctype": "// UNSUPPORTED: no-wide-characters", - "experimental/algorithm": "// UNSUPPORTED: c++03", "experimental/deque": "// UNSUPPORTED: c++03", "experimental/forward_list": "// UNSUPPORTED: c++03", - "experimental/functional": "// UNSUPPORTED: c++03", "experimental/iterator": "// UNSUPPORTED: c++03", "experimental/list": "// UNSUPPORTED: c++03", "experimental/map": "// UNSUPPORTED: c++03", @@ -59,6 +57,24 @@ "wctype.h": "// UNSUPPORTED: no-wide-characters", } +header_include_requirements = { + # headers with #error directives + ("_LIBCPP_HAS_NO_ATOMIC_HEADER",): ("atomic", + # transitive includers of the above headers + "stdatomic.h"), + # headers with #error directives + ("_LIBCPP_HAS_NO_LOCALIZATION",): ("ios", "locale.h", + # transitive includers of the above headers + "clocale", "codecvt", "experimental/regex", "fstream", "iomanip", "iostream", "istream", + "locale", "ostream", "regex", "sstream", "streambuf", "strstream"), + # headers with #error directives + ("_LIBCPP_HAS_NO_THREADS",): ("barrier", "future", "latch", "semaphore", "shared_mutex", "stop_token", "thread"), + # headers with #error directives + ("_LIBCPP_HAS_NO_WIDE_CHARACTERS",): ("wchar.h", "wctype.h", + # transitive includers of the above headers + "cwchar", "cwctype") +} + # This table was produced manually, by grepping the TeX source of the Standard's # library clauses for the string "#include". Each header's synopsis contains # explicit "#include" directives for its mandatory inclusions. @@ -109,10 +125,11 @@ not file.is_dir() and not file.name == "module.modulemap.in" and not file.name == "CMakeLists.txt" + and not file.name == "generate_std_clang_module_header.py" and file.name != "libcxx.imp" ) -libcxx_root = pathlib.Path(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))) +libcxx_root = pathlib.Path(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))) include = pathlib.Path(os.path.join(libcxx_root, "include")) test = pathlib.Path(os.path.join(libcxx_root, "test")) assert libcxx_root.exists()