(address . guix-patches@gnu.org)(name . Leo Nikkilä)(address . hello@lnikki.la)
After the "hack" introduced for https://issues.guix.gnu.org/42392, all GCCs
are built with the current GCC's libstdc++ headers. This results in subtly
broken C++ headers in older versions, which aren't necessarily compatible with
libstdc++s from other versions.
For example, this test case works with GCC 11:
$ guix shell --container --emulate-fhs --pure -e '(@ (gnu packages gcc) gcc)' binutils -- sh -c 'echo -e "#include <cmath>\nint main() { return std::isnan(0); }" | g++ -x c++ -; echo $?'
0
but fails with GCC 9:
$ guix shell --container --emulate-fhs --pure -e '(@ (gnu packages gcc) gcc-9)' binutils -- sh -c 'echo -e "#include <cmath>\nint main() { return std::isnan(0); }" | g++ -x c++ -; echo $?'
In file included from /gnu/store/gkh2rljdrnj24q1q7baa6bhb119251w4-profile/include/c++/cmath:45,
from <stdin>:1:
<stdin>: In function 'int main()':
<stdin>:2:26: error: '__builtin_isnan' is not a member of 'std'; did you mean '__builtin_isnan'?
<built-in>: note: '__builtin_isnan' declared here
1
This specific error can be traced back to the GCC build, where GCC 10 and 11
are configured with:
checking for ISO C99 support in <math.h> for C++11... yes
but GCC 9 is configured with:
checking for ISO C99 support in <math.h> for C++11... no
The configure check fails due to errors like these due to the mismatched
libstdc++:
configure:17817: checking for ISO C99 support in <math.h> for C++11
configure:17886: /tmp/guix-build-gcc-9.5.0.drv-0/build/./gcc/xgcc -shared-libgcc -B/tmp/guix-build-gcc-9.5.0.drv-0/build/./gcc -nostdinc++ -L/tmp/guix-build-gcc-9.5.0.drv-0/build/aarch64-unknown-linux-gnu/libstdc++-v3/src -L/tmp/guix-build-gcc-9.5.0.drv-0/build/aarch64-unknown-linux-gnu/libstdc++-v3/src/.libs -L/tmp/guix-build-gcc-9.5.0.drv-0/build/aarch64-unknown-linux-gnu/libstdc++-v3/libsupc++/.libs -B/gnu/store/l9a96zpznir4bm02lsycj35q0pakln32-gcc-9.5.0/aarch64-unknown-linux-gnu/bin/ -B/gnu/store/l9a96zpznir4bm02lsycj35q0pakln32-gcc-9.5.0/aarch64-unknown-linux-gnu/lib/ -isystem /gnu/store/l9a96zpznir4bm02lsycj35q0pakln32-gcc-9.5.0/aarch64-unknown-linux-gnu/include -isystem /gnu/store/l9a96zpznir4bm02lsycj35q0pakln32-gcc-9.5.0/aarch64-unknown-linux-gnu/sys-include -fchecking=1 -o conftest -g -O2 -D_GNU_SOURCE -std=c++11 -fno-exceptions -B/gnu/store/3gvs8sw95ldfypr1n688svl5brwdmdi9-glibc-2.39/lib -Wl,-dynamic-linker -Wl,/gnu/store/3gvs8sw95ldfypr1n688svl5brwdmdi9-glibc-2.39/lib/ld-linux-aarch64.so.1 conftest.cpp -lm >&5
In file included from /gnu/store/y3kk0ybf7hqwndl8xpm61r4a5b3lhwix-libstdc++-11.4.0/include/cmath:41,
from /gnu/store/y3kk0ybf7hqwndl8xpm61r4a5b3lhwix-libstdc++-11.4.0/include/math.h:36,
from conftest.cpp:41:
/gnu/store/y3kk0ybf7hqwndl8xpm61r4a5b3lhwix-libstdc++-11.4.0/include/bits/c++config.h:491:18: error: missing binary operator before token "("
491 | #if __has_builtin(__builtin_is_constant_evaluated)
| ^
In file included from /gnu/store/y3kk0ybf7hqwndl8xpm61r4a5b3lhwix-libstdc++-11.4.0/include/cmath:41,
from /gnu/store/y3kk0ybf7hqwndl8xpm61r4a5b3lhwix-libstdc++-11.4.0/include/math.h:36,
from conftest.cpp:41:
/gnu/store/y3kk0ybf7hqwndl8xpm61r4a5b3lhwix-libstdc++-11.4.0/include/bits/c++config.h:732:25: error: missing binary operator before token "("
732 | #if _GLIBCXX_HAS_BUILTIN(__has_unique_object_representations)
| ^
/gnu/store/y3kk0ybf7hqwndl8xpm61r4a5b3lhwix-libstdc++-11.4.0/include/bits/c++config.h:736:25: error: missing binary operator before token "("
736 | #if _GLIBCXX_HAS_BUILTIN(__is_aggregate)
| ^
/gnu/store/y3kk0ybf7hqwndl8xpm61r4a5b3lhwix-libstdc++-11.4.0/include/bits/c++config.h:740:25: error: missing binary operator before token "("
740 | #if _GLIBCXX_HAS_BUILTIN(__builtin_is_constant_evaluated)
| ^
/gnu/store/y3kk0ybf7hqwndl8xpm61r4a5b3lhwix-libstdc++-11.4.0/include/bits/c++config.h:744:25: error: missing binary operator before token "("
744 | #if _GLIBCXX_HAS_BUILTIN(__is_same)
| ^
/gnu/store/y3kk0ybf7hqwndl8xpm61r4a5b3lhwix-libstdc++-11.4.0/include/bits/c++config.h:748:25: error: missing binary operator before token "("
748 | #if _GLIBCXX_HAS_BUILTIN(__builtin_launder)
| ^
configure:17886: $? = 1
Updating libstdc++ to reference each GCC works around this. I've tested this
with GCC 9, but I swapped the `libstdc++-headers' input directly as I didn't
have the time to do a `guix pull'. I wrote this little test however to check
that `this-package' should work here:
(use-modules (guix build-system trivial)
(guix gexp)
(guix packages))
(define (make-requirement pkg)
(define builder
#~(call-with-output-file #$output
(lambda (port)
(format port "~a~%" #$(package-name pkg)))))
(computed-file "requirement" builder))
(define package-1
(package
(name "package-1")
(version "1")
(source #f)
(build-system trivial-build-system)
(inputs
`(("requirement" ,(make-requirement this-package))))
(arguments
'(#:builder
(copy-file (assoc-ref %build-inputs "requirement")
%output)))
(synopsis #f)
(description #f)
(home-page #f)
(license #f)))
(define package-2
(package
(inherit package-1)
(name "package-2")
(version "2")))
(list package-1 package-2)
Building these packages results in the expected output, where each package
uses an input customised for it:
$ cat $(guix build -f this-package.scm)
package-2
package-1
* gnu/packages/gcc.scm (libstdc++, libstdc++-headers): Remove variables.
(make-libstdc++-headers): New procedure.
(gcc-6)[native-inputs]: Use it with `this-package'.
---
gnu/packages/gcc.scm | 38 ++++++++++++++++++--------------------
1 file changed, 18 insertions(+), 20 deletions(-)
Toggle diff (71 lines)
diff --git a/gnu/packages/gcc.scm b/gnu/packages/gcc.scm
index 6247919fec4..3735a9c9d94 100644
--- a/gnu/packages/gcc.scm
+++ b/gnu/packages/gcc.scm
@@ -17,6 +17,7 @@
;;; Copyright © 2023 Bruno Victal <mirai@makinata.eu>
;;; Copyright © 2023 Maxim Cournoyer <maxim.cournoyer@gmail.com>
;;; Copyright © 2024 Nguy?n Gia Phong <mcsinyx@disroot.org>
+;;; Copyright © 2025 Leo Nikkilä <hello@lnikki.la>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -549,7 +550,7 @@ (define-public gcc-6
;; XXX: This gross hack allows us to have libstdc++'s <bits/c++config.h>
;; in the search path, thereby avoiding misconfiguration of libstdc++:
;; <https://bugs.gnu.org/42392>.
- ("libstdc++" ,libstdc++-headers)
+ ("libstdc++" ,(make-libstdc++-headers this-package))
,@(package-inputs gcc-4.7)))))
@@ -1055,31 +1056,28 @@ (define-public (make-libstdc++ gcc)
(propagated-inputs '())
(synopsis "GNU C++ standard library")))
-(define libstdc++
- ;; Libstdc++ matching the default GCC.
- (make-libstdc++ gcc))
-
-(define libstdc++-headers
+(define (make-libstdc++-headers gcc)
;; XXX: This package is for internal use to work around
;; <https://bugs.gnu.org/42392> (see above). The main difference compared
;; to the libstdc++ headers that come with 'gcc' is that <bits/c++config.h>
;; is right under include/c++ and not under
;; include/c++/x86_64-unknown-linux-gnu (aka. GPLUSPLUS_TOOL_INCLUDE_DIR).
- (package
- (inherit libstdc++)
- (name "libstdc++-headers")
- (outputs '("out"))
- (build-system trivial-build-system)
- (arguments
- '(#:builder (let* ((out (assoc-ref %outputs "out"))
- (libstdc++ (assoc-ref %build-inputs "libstdc++")))
- (mkdir out)
- (mkdir (string-append out "/include"))
- (symlink (string-append libstdc++ "/include")
- (string-append out "/include/c++")))))
- (inputs `(("libstdc++" ,libstdc++)))
- (synopsis "Headers of GNU libstdc++")))
+ (let ((libstdc++ (make-libstdc++ gcc)))
+ (package
+ (inherit libstdc++)
+ (name "libstdc++-headers")
+ (outputs '("out"))
+ (build-system trivial-build-system)
+ (arguments
+ '(#:builder (let* ((out (assoc-ref %outputs "out"))
+ (libstdc++ (assoc-ref %build-inputs "libstdc++")))
+ (mkdir out)
+ (mkdir (string-append out "/include"))
+ (symlink (string-append libstdc++ "/include")
+ (string-append out "/include/c++")))))
+ (inputs `(("libstdc++" ,libstdc++)))
+ (synopsis "Headers of GNU libstdc++"))))
(define-public libstdc++-4.9
(make-libstdc++ gcc-4.9))
--
2.47.1