Guix 1.5.0 builds glibc-cross with the build host's static bash as the shell for system(), popen() and the exec*() script fallback, so on the cross-built Pi system they all failed with "Exec format error". cross-libc-fix wraps cross-libc to use /bin/sh instead. Deployed and verified as generation 14. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
67 lines
3.1 KiB
Scheme
67 lines
3.1 KiB
Scheme
;;; Cross-built glibc with a usable shell for system()/popen().
|
|
;;;
|
|
;;; Guix 1.5.0's glibc recipe points system(), popen() and the exec*() script
|
|
;;; fallback (_PATH_BSHELL) at its "static-bash" input. For a cross libc
|
|
;;; that input is a *native* one (cross-base.scm: ";FIXME: static-bash"), so
|
|
;;; on an aarch64 system cross-built from x86_64 they exec an x86_64 bash:
|
|
;;; "Exec format error", every system()/popen() fails (PITFALLS #35). A
|
|
;;; target bash can't be used instead: building it needs this very libc.
|
|
;;;
|
|
;;; Fix for cross-built *Guix systems*, which always have /bin/sh: use
|
|
;;; glibc's stock /bin/sh. Loading this module wraps `cross-libc' in
|
|
;;; (gnu packages cross-base), which the build systems look up by name
|
|
;;; (standard-cross-packages), so every cross build in the process -- the
|
|
;;; cross toolchain itself included -- uses the fixed libc.
|
|
(define-module (cross-libc-fix)
|
|
#:use-module (guix packages)
|
|
#:use-module (guix memoization)
|
|
#:use-module (guix utils))
|
|
|
|
(define %original-cross-libc
|
|
(module-ref (resolve-module '(gnu packages cross-base)) 'cross-libc))
|
|
|
|
(define fix-libc
|
|
(mlambdaq (libc)
|
|
(package
|
|
(inherit libc)
|
|
(arguments
|
|
(substitute-keyword-arguments (package-arguments libc)
|
|
((#:phases phases)
|
|
`(modify-phases ,phases
|
|
(add-after 'pre-configure 'use-/bin/sh
|
|
;; Undo pre-configure's static-bash paths.
|
|
(lambda _
|
|
(substitute* "sysdeps/posix/system.c"
|
|
(("#define[[:blank:]]+SHELL_PATH.*$")
|
|
"#define SHELL_PATH \"/bin/sh\"\n"))
|
|
(substitute* "libio/iopopen.c"
|
|
(("\"/gnu/store/[^\"]*/bin/sh\"") "\"/bin/sh\""))
|
|
(substitute* (find-files "." "^paths\\.h$")
|
|
(("#define[[:blank:]]+_PATH_BSHELL[[:blank:]].*$")
|
|
"#define _PATH_BSHELL \"/bin/sh\"\n"))))
|
|
(add-after 'patch-shebangs 'bin-sh-shebangs
|
|
;; ldd, sotruss, tzselect, xtrace: bash scripts whose
|
|
;; shebang is the host's static bash too. After
|
|
;; patch-shebangs, which would put it back; /bin/sh is bash
|
|
;; on Guix System.
|
|
(lambda* (#:key outputs #:allow-other-keys)
|
|
(let ((bin (string-append (assoc-ref outputs "out") "/bin")))
|
|
(for-each (lambda (script)
|
|
(let ((file (string-append bin "/" script)))
|
|
(when (file-exists? file)
|
|
(substitute* file
|
|
(("^#! ?/gnu/store/[^ \n]*/bin/(ba)?sh")
|
|
"#!/bin/sh")))))
|
|
'("ldd" "sotruss" "tzselect" "xtrace"))))))))))))
|
|
|
|
(define (cross-libc/bin-sh . args)
|
|
(let ((libc (apply %original-cross-libc args)))
|
|
(if (and (package? libc)
|
|
(string-prefix? "glibc-cross-" (package-name libc)))
|
|
(fix-libc libc)
|
|
libc)))
|
|
|
|
(unless (eq? %original-cross-libc cross-libc/bin-sh)
|
|
(module-set! (resolve-module '(gnu packages cross-base))
|
|
'cross-libc cross-libc/bin-sh))
|