Skip to content

Fix gnutls cross build: drop man/devdoc outputs when disabling docs#2

Merged
lacraig2 merged 8 commits into
mainfrom
fix/gnutls-cross-doc-outputs
Jun 7, 2026
Merged

Fix gnutls cross build: drop man/devdoc outputs when disabling docs#2
lacraig2 merged 8 commits into
mainfrom
fix/gnutls-cross-doc-outputs

Conversation

@lacraig2

@lacraig2 lacraig2 commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

Why main is failing post-merge

After #1 (cpython-runtime + dist-root fixes), the build progressed further and hit a new failure in Flake check:

error: builder for '...gnutls-aarch64-linux-musl-3.8.12.drv' failed to produce output path for output 'devdoc'
  → libmicrohttpd → elfutils → gdb-host-cpu-only-aarch64 (gdbserver) → penguin-tools-aarch64 → dist-root → tarball

Root cause

The cross overlay in src/cross-overlays.nix forces --disable-doc on gnutls (its doc build runs generated target binaries, which fails under cross-compile) but left the man and devdoc outputs declared. With docs disabled, neither output is ever populated, so Nix fails.

Upstream nixpkgs couples these: it only passes --disable-doc for MinGW, and in that same case drops both man and devdoc from outputs. The overlay copied the flag but not the output removal.

Fix

Filter man and devdoc out of gnutls's outputs in the same overlay. Verified gnutls for aarch64-linux-musl now builds and produces bin/dev/out.

lacraig2 added 8 commits June 7, 2026 08:56
The cross overlay forces --disable-doc on gnutls (its doc build runs
generated target binaries, which fails under cross-compilation), but left
the "man" and "devdoc" outputs declared. With docs disabled neither output
is populated, so Nix fails: "failed to produce output path for output
'devdoc'" (and then 'man'). Upstream couples these — it only passes
--disable-doc for MinGW and drops both outputs in the same case. Mirror
that by filtering man/devdoc out of the outputs list.

This was the next failure after the cpython-runtime/dist-root fixes let the
build progress to the gdbserver (gdb -> elfutils -> libmicrohttpd -> gnutls)
dependency chain. Verified gnutls aarch64-linux-musl now builds.
elfutils pulls in argp-standalone on musl. Its meson build links testsuite
example binaries (ex3/ex4) with stack-protector on, but some 32-bit musl
toolchains (e.g. powerpc) don't provide __stack_chk_fail_local, so linking
fails: "undefined reference to __stack_chk_fail_local". Only the static lib
is consumed by elfutils, so disable the stackprotector hardening flag,
which removes the reference from both the lib and the examples.

Next failure after the gnutls output fix let the build reach the powerpc
gdbserver (gdb -> elfutils -> argp-standalone) chain.
Penguin only supports ppc64, so remove the 32-bit powerpc-linux-musl arch
from the build matrix instead of working around its broken toolchain. The
32-bit PowerPC musl toolchain lacks __stack_chk_fail_local, which broke any
stack-protector static link (argp-standalone, libipt, ...) in the gdbserver
dependency tree. ppc64/ppc64el are unaffected and stay.

This also reverts the argp-standalone hardeningDisable workaround added for
that arch, which is no longer needed.
Two gdb-17.1-on-musl compile failures, surfaced once the ppc32 drop let CI
reach the gdb builds:

- aarch64: gdb defines its own `struct user_gcs` unless GCS_MAGIC is defined,
  but kernel headers >=6.13 put user_gcs in <asm/ptrace.h> while GCS_MAGIC is
  in <asm/sigcontext.h> (not included by ptrace.h), so the struct is
  redefined. Guard on ptrace.h's own include guard (__ASM_PTRACE_H) instead:
  files that include ptrace.h use the kernel struct, aarch64-linux-tdep.c
  (which doesn't) keeps gdb's fallback.

- all musl arches: ser-unix.c's custom-baudrate path uses .c_ispeed/.c_ospeed,
  but musl names those fields __c_ispeed/__c_ospeed (the struct termios2 path
  needs TCGETS2, which musl never defines). Map the field accesses to the
  musl names.

Verified gdb-host-cpu-only-aarch64-linux-musl now builds to completion.
gdb 17.1 (from the nixpkgs pin) does not build against musl + modern kernel
headers across our arch set: aarch64 hit a struct user_gcs redefinition,
all arches hit ser-unix.c's custom-baudrate code using glibc-only termios
fields, and gdbserver's in-process agent configure errors out on targets
like armv7l. These are gdb-17-era additions.

Rather than forward-port an open-ended tail of musl fixes, pin gdb to 16.3 —
the version Alpine and Buildroot ship on musl across all these arches. 16.3
predates the GCS and custom-baudrate code, so those failures disappear
entirely. Keep the mips sgidefs fixup, and disable the in-process agent
(unsupported on some targets, and unused by us).
The PowerPC backend tripped three glibc-isms under musl:

- The injected error() macro (replacing <error.h>) called strerror/exit
  without their prototypes, so strerror was assumed to return int and
  -Werror=format killed regs.c. Include <stdio.h>/<stdlib.h>/<string.h>.
- program_invocation_name is a glibc-only global; hardcode the "ltrace"
  prefix instead.
- trace.c uses the kernel PT_R0/PT_NIP/PT_LNK ptrace offsets, which
  glibc's <sys/ptrace.h> pulls in transitively but musl's does not.
  Add <asm/ptrace.h> in the ppc ptrace.h shim.

Confirmed building locally for ppc64 and ppc64el.
The bundle's validate_tree step forbids any /nix/store reference, but
several tools embed build-time store paths that survive ELF normalization:

- CPython bakes its PREFIX (the build python3-minimal store path) into
  libpython's rodata via getpath; ltrace bakes its SYSCONFDIR into the
  binary. These are compile-time fallbacks, overridden at runtime, and
  point at paths that don't exist on the guest regardless.
- _sysconfigdata*.py records the cross toolchain used to build the
  interpreter (build python, coreutils), only relevant for building
  extensions on-target, which we never do.

Rewrite the literal "/nix/store" to "/igloo_nix" across the staged tree
right before validation. The replacement is the same length, so the
substitution is length-preserving and leaves ELF section offsets intact.

Also fix CPython's hardcoded default shell (subprocess.py / ctypes
fetch_macholib) to point at the guest's /bin/sh, and drop the unused
EXTERNALLY-MANAGED pip marker.

Confirmed: penguin-tools-armel now builds and passes validate_tree, with
no /nix/store references and valid ELF binaries.
openssl's checkPhase runs only on the "native" x86_64-musl build (the
cross builds skip tests). Its 04-test_bio_dgram datagram-socket test
fails in the sandboxed Nix builder, breaking the curl -> elfutils ->
gdb dependency chain. openssl is only a transitive dependency here, so
disable its checks, mirroring the existing p11-kit treatment.

Verified the openssl derivation now carries doCheck="" and configures
with disable-tests.
@lacraig2 lacraig2 merged commit b049a54 into main Jun 7, 2026
1 check passed
@lacraig2 lacraig2 deleted the fix/gnutls-cross-doc-outputs branch June 7, 2026 21:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant