[WIP RFC] libstdc++: add module std
Jonathan Wakely
jwakely@redhat.com
Fri Nov 15 11:04:24 GMT 2024
On 14/11/24 23:09 -0500, Jason Merrill wrote:
>On 10/18/24 9:38 AM, Jason Merrill wrote:
>>This patch is not ready for integration, but I'd like to get feedback on the
>>approach (and various specific questions below).
>
>An updated version:
>From 533c496ae39ba2cf1783136e1da5ae9f0f61d4f7 Mon Sep 17 00:00:00 2001
>From: Jason Merrill <jason@redhat.com>
>Date: Thu, 10 Oct 2024 17:27:50 -0400
>Subject: [PATCH] libstdc++: add module std [PR106852]
>To: gcc-patches@gcc.gnu.org
>
>This patch introduces an installed source form of module std and std.compat.
>To find them, we install a libstdc++.modules.json file alongside
>libstdc++.so, which tells the build system where the files are and any
>special flags it should use when compiling them (none, in our case). The
>format is from a proposal in SG15.
>
>The build system can find this file with
>gcc -print-file-name=libstdc++.modules.json
>
>It seems preferable to use a relative path from this file to the sources so
>that moving the installation doesn't break the reference, but I didn't see
>any obvious way to compute that without relying on coreutils, perl, or
>python, so I wrote a POSIX shell script for it.
>
>Currently this installs the sources under $(gxx_include_dir)/bits/,
>i.e. /usr/include/c++/15/bits. So with my -fsearch-include-path change,
>std.cc can be compiled with g++ -fsearch-include-path bits/std.cc.
Would there be a way to give a diagnostic if a translation unit does
#include <bits/std.cc> ?
If we install it there, somebody will try to include it like a header.
I'm not terribly concerned about that, but it would be nice to warn or
error if we can.
Maybe:
#if __INCLUDE_LEVEL__ != 0
# warning "stop it"
#endif
Or even:
#ifndef _GLIBCXX_ALLOW_WEIRD_INCLUDE_WHAT_ARE_YOU_EVEN_DOING
static_assert(std::string_view(__BASE_FILE__).ends_with("std.cc"));
#endif
>The sources currently have the extension .cc, like other source files.
>
>std.cc started with m.cencora's implementation in PR114600. I've made some
>adjustments, but more is probably desirable, e.g. of the <algorithm>
>handling of namespace ranges, and to remove exports of templates that are
>only specialized in a particular header.
>
>I've filled in a bunch of missing exports, and added some FIXMEs where I
>noticed bits that are not implemented yet.
>
>Since bits/stdc++.h also intends to include the whole standard library, I
>include it rather than duplicate it. But stdc++.h comments out <execution>,
>so I include it separately. Alternatively, we could uncomment it in
>stdc++.h.
It's not included by default because it pulls in a dependency on
libtbb.so even if you don't use the parallel algos:
$ g++ -include algorithm -include execution -x c++ - <<< 'int main() { }'
/usr/bin/ld: /tmp/ccA76qrz.o: in function `tbb::detail::d1::execution_slot(tbb::detail::d1::execution_data const&)':
<stdin>:(.text._ZN3tbb6detail2d114execution_slotERKNS1_14execution_dataE[_ZN3tbb6detail2d114execution_slotERKNS1_14execution_dataE]+0x14): undefined reference to `tbb::detail::r1::execution_slot(tbb::detail::d1::execution_data const*)'
/usr/bin/ld: /tmp/ccA76qrz.o: in function `tbb::detail::d1::current_thread_index()':
<stdin>:(.text._ZN3tbb6detail2d120current_thread_indexEv[_ZN3tbb6detail2d120current_thread_indexEv]+0xe): undefined reference to `tbb::detail::r1::execution_slot(tbb::detail::d1::execution_data const*)'
collect2: error: ld returned 1 exit status
The way we arranged the PSTL inclusion is that you only get a
dependeny on TBB if you include a header containing a parallel algo
(<algorithm>, <numeric>) *and* include <execution>. Since including
<execution> is formally required by the standard in order to pass one
of std::execution::par, std::execution::seq etc. to a parallel algo,
we switch on whether <execution> has been included or not to detect
whether the user actually wants to use parallel algos.
Is this not a problem for 'import std;'?
Maybe we should figure out how to fix it for #include <execution>
anyway. When we eventually support senders/receivers in <execution>
for C++26, users are going to want to include that for reasons other
than using the parallel algos and their execution policies.
>It seemed most convenient for the two files to be monolithic so we don't
>need to worry about include paths. So the C library names that module
>std.compat exports in both namespace std and :: in module are a block of
>code that is identical in both files, adjusted based on whether the macro
>STD_COMPAT is defined before the block.
We could split std.cc and std.compat.cc into several *.in files and
build them on the fly during installation, so that the verbatim part
is not duplicated. Something like:
cat std.head.in std.clib.in std.tail.in > std.cc
cat std.compat.head.in std.clib.in > std.compat.cc
>In this implementation std.compat imports std; it would also be valid for it
>to duplicate everything in std. I see the libc++ std.compat also imports
>std.
That seems fine.
>As discussed in the PR, module std is supported in C++20 mode even though it
>was added in C++23.
Great.
>Changes to test module std will follow in a separate patch. In my testing
>I've noticed a few compiler bugs that break various testcases, so I don't
>expect to enable module std testing by default at first.
>
> PR libstdc++/106852
>
>libstdc++-v3/ChangeLog:
>
> * include/bits/version.def: Add __cpp_lib_modules.
> * include/bits/version.h: Regenerate.
> * src/c++23/Makefile.am: Add module std/std.compat.
> * src/c++23/Makefile.in: Regenerate.
> * src/c++23/std.cc: New file.
> * src/c++23/std.compat.cc: New file.
> * src/c++23/libstdc++.modules.json.in: New file.
>
>contrib/ChangeLog:
>
> * relpath.sh: New file.
>---
> libstdc++-v3/include/bits/version.h | 10 +
> libstdc++-v3/src/c++23/std.cc | 3925 +++++++++++++++++
> libstdc++-v3/src/c++23/std.compat.cc | 705 +++
> contrib/relpath.sh | 83 +
> libstdc++-v3/include/bits/version.def | 9 +
> libstdc++-v3/src/c++23/Makefile.am | 27 +
> libstdc++-v3/src/c++23/Makefile.in | 137 +-
> .../src/c++23/libstdc++.modules.json.in | 17 +
> 8 files changed, 4897 insertions(+), 16 deletions(-)
> create mode 100644 libstdc++-v3/src/c++23/std.cc
> create mode 100644 libstdc++-v3/src/c++23/std.compat.cc
> create mode 100755 contrib/relpath.sh
> create mode 100644 libstdc++-v3/src/c++23/libstdc++.modules.json.in
>
>diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h
>index a0e3b36864b..c556aca38fa 100644
>--- a/libstdc++-v3/include/bits/version.h
>+++ b/libstdc++-v3/include/bits/version.h
>@@ -2075,4 +2075,14 @@
> #endif /* !defined(__cpp_lib_to_string) && defined(__glibcxx_want_to_string) */
> #undef __glibcxx_want_to_string
>
>+#if !defined(__cpp_lib_modules)
>+# if (__cplusplus >= 202002L) && (__cpp_modules)
>+# define __glibcxx_modules 202207L
>+# if defined(__glibcxx_want_all) || defined(__glibcxx_want_modules)
>+# define __cpp_lib_modules 202207L
>+# endif
>+# endif
>+#endif /* !defined(__cpp_lib_modules) && defined(__glibcxx_want_modules) */
>+#undef __glibcxx_want_modules
>+
> #undef __glibcxx_want_all
>diff --git a/libstdc++-v3/src/c++23/std.cc b/libstdc++-v3/src/c++23/std.cc
>new file mode 100644
>index 00000000000..4311c8dc5cb
>--- /dev/null
>+++ b/libstdc++-v3/src/c++23/std.cc
>@@ -0,0 +1,3925 @@
>+// -*- C++ -*- [std.modules] module std
>+
>+// Copyright The GNU Toolchain Authors.
>+//
>+// This file is part of the GNU ISO C++ Library. This library is free
>+// software; you can redistribute it and/or modify it under the
>+// terms of the GNU General Public License as published by the
>+// Free Software Foundation; either version 3.
>+
>+// This library is distributed in the hope that it will be useful,
>+// but WITHOUT ANY WARRANTY; without even the implied warranty of
>+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>+// GNU General Public License for more details.
>+
>+// Under Section 7 of GPL version 3, you are granted additional
>+// permissions described in the GCC Runtime Library Exception, version
>+// 3.1, as published by the Free Software Foundation.
>+
>+// You should have received a copy of the GNU General Public License and
>+// a copy of the GCC Runtime Library Exception along with this program;
>+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
>+// <http://www.gnu.org/licenses/>.
>+
>+module;
>+
>+#include <bits/stdc++.h>
>+
>+// ??? Commented out in stdc++.h
>+#include <execution>
>+
>+#undef __DEPRECATED
Could this be done with:
#pragma GCC diagnostic ignored "-Wdeprecated"
instead?
>+#include <strstream>
>+
>+export module std;
>+
>+// **** Any changes to the C library section below must also be made to the
>+// **** verbatim copy in std.compat.cc.
>+
>+// C standard library headers [tab:headers.cpp.c]
>+
[...]
>diff --git a/contrib/relpath.sh b/contrib/relpath.sh
>new file mode 100755
>index 00000000000..94301d2778c
>--- /dev/null
>+++ b/contrib/relpath.sh
>@@ -0,0 +1,83 @@
>+#!/bin/sh
>+
>+if [ "$1" == "--help" ]; then
Single = here.
>+ echo Usage: relpath.sh FROM TO
>+ echo Print the relative path from FROM to TO
>+ echo FROM must be a directory, but need not exist
>+ exit 0
>+fi
>+
>+if [ -f "$1" ]; then
Why not [ ! -d "$1" ] ?
>+ echo first argument must be a directory
Redirect >&2
>+ exit 1
>+fi
>+
>+from="${1%%/}"
>+to="${2%%/}"
>+
>+# The parent directory of a pathname, handling ..
>+parent() {
>+ name=$(basename "$1")
>+ path=$(dirname "$1")
>+ top=$(basename "$path")
>+ if [ "$top" = ".." ]; then
>+ path=$(parent "$path")
>+ fi
>+ if [ "$name" = ".." ]; then
>+ path=$(parent "$path")
>+ fi
>+ echo $path
>+}
>+
>+# Canonicalize a directory that contains '..'.
>+canonicalize() {
>+ path=$1
>+ suffix=
>+ while ! [ -d "$path" ]; do
>+ name=$(basename "$path")
>+ path=$(parent "$path")
>+ suffix="/$name$suffix"
>+ done
>+ if [ -d "$path" ]; then
>+ echo $(cd "$path"; pwd)$suffix
>+ else
>+ echo $1
>+ fi
>+}
>+
>+case "$to$from" in
>+ *..* )
>+ from=$(canonicalize "$from")
>+ to=$(canonicalize "$to")
>+ ;;
>+esac
>+case "$to$from" in
>+ *..* )
>+ echo unable to canonicalize ..
Redirect to >&2 ?
>+ exit 1
>+ ;;
>+esac
>+
>+back=
>+while [ "${to#$from}" = "$to" ]; do
>+ #echo $from too long
>+ from=$(dirname $from);
>+ back=../$back
>+
>+ if [ "$from" = "/" ]; then
>+ echo $to
>+ exit 0
>+ fi
>+done
>+
>+to=${to#$from}
>+to=${to##/}
>+back=${back%%/}
>+
>+if [ -n "$to" ] && [ -n "$back" ]; then
>+ echo $back/$to
>+elif [ -n "$back$to" ]; then
>+ echo $back$to
>+else
>+ echo .
>+fi
More information about the Libstdc++
mailing list