diff --git a/minimal.toml b/minimal.toml index e2fb88cd..3f2225ac 100644 --- a/minimal.toml +++ b/minimal.toml @@ -15,3 +15,9 @@ exec = "claude --dangerously-skip-permissions" interactive = true packages = ["base", "bash", "opencode", "curl"] exec = "opencode" + +# UNCOMMITTED test rig for the libarchive PR — discard before push. +[tasks.diffcheck] +description = "Prove diffoscope actually runs with the new libarchive dep" +packages = ["base", "coreutils", "diffoscope"] +bash = "diffoscope --version && echo 'diffcheck: ok'" diff --git a/packages/diffoscope/build.ncl b/packages/diffoscope/build.ncl index 8249240e..67b50491 100644 --- a/packages/diffoscope/build.ncl +++ b/packages/diffoscope/build.ncl @@ -3,6 +3,7 @@ let base = import "../base/build.ncl" in let toolchain = import "../toolchain/build.ncl" in let uv = import "../uv/build.ncl" in let python = import "../python/build.ncl" in +let libarchive = import "../libarchive/build.ncl" in let version = "325" in { name = "diffoscope", @@ -18,11 +19,16 @@ let version = "325" in ], runtime_deps = [ python, + # diffoscope imports python's libarchive-c at STARTUP, which dlopens the + # native libarchive.so — without it every invocation dies with + # "undefined symbol: archive_version_number" (found by repro-lab's + # rc-tools, which invokes every tool instead of trusting `command -v`). + libarchive, ], cmd = "./build.sh", outputs = { - diffoscope = { glob = "usr/bin/diffoscope" } | OutputBin, + diffoscope = { glob = "usr/bin/diffoscope*" } | OutputBin, site_packages = { glob = "usr/lib/python*/site-packages/**/*" } | OutputData, }, attrs = { diff --git a/packages/diffoscope/build.sh b/packages/diffoscope/build.sh index 1bb28985..e29ee641 100755 --- a/packages/diffoscope/build.sh +++ b/packages/diffoscope/build.sh @@ -5,5 +5,18 @@ tar -xof diffoscope-325.tar.gz cd diffoscope-325 pip3 install --root $OUTPUT_DIR . + +# ctypes' find_library() has neither ldconfig nor gcc inside a composed +# root, so libarchive-c cannot locate libarchive.so on its own — but it +# honors $LIBARCHIVE. Ship the console script behind a wrapper that points +# it at the library (overridable, harmless when unset elsewhere). +mv "$OUTPUT_DIR/usr/bin/diffoscope" "$OUTPUT_DIR/usr/bin/diffoscope-real" +cat > "$OUTPUT_DIR/usr/bin/diffoscope" <<'WRAP' +#!/bin/sh +export LIBARCHIVE="${LIBARCHIVE:-/usr/lib/libarchive.so.13}" +exec /usr/bin/diffoscope-real "$@" +WRAP +chmod 755 "$OUTPUT_DIR/usr/bin/diffoscope" + # TODO does not produce /usr/bin/diffoscope # uv pip install --system --prefix $OUTPUT_DIR/usr -r pyproject.toml --extra cmdline diff --git a/packages/libarchive/build.ncl b/packages/libarchive/build.ncl new file mode 100644 index 00000000..f3e99f86 --- /dev/null +++ b/packages/libarchive/build.ncl @@ -0,0 +1,62 @@ +let { Attrs, BuildSpec, Local, OutputData, OutputLib, Source, .. } = import "minimal.ncl" in +let bash-bootstrap = import "../bash-bootstrap/build.ncl" in +let make = import "../make/build.ncl" in +let sed = import "../sed/build.ncl" in +let grep = import "../grep/build.ncl" in +let gawk-bootstrap = import "../gawk-bootstrap/build.ncl" in +let tar = import "../tar/build.ncl" in +let coreutils = import "../coreutils/build.ncl" in +let toolchain = import "../toolchain/build.ncl" in +let glibc = import "../glibc/build.ncl" in +let zlib = import "../zlib/build.ncl" in +let bzip2 = import "../bzip2/build.ncl" in +let zstd = import "../zstd/build.ncl" in + +let version = "3.8.1" in +{ + name = "libarchive", + build_deps = [ + { file = "build.sh" } | Local, + { + # Upstream: https://github.com/libarchive/libarchive/releases/download/v3.8.1/libarchive-3.8.1.tar.gz + # STAGING: gcloud storage cp libarchive-3.8.1.tar.gz gs://minimal-staging-archives/ + url = "gs://minimal-staging-archives/libarchive-%{version}.tar.gz", + sha256 = "bde832a5e3344dc723cfe9cc37f8e54bde04565bfe6f136bc1bd31ab352e9fab" + } | Source, + bash-bootstrap, + make, + sed, + grep, + gawk-bootstrap, + tar, + coreutils, + toolchain, + zlib, + bzip2, + zstd, + ], + runtime_deps = [ + glibc, + zlib, + bzip2, + zstd, + ], + + cmd = "./build.sh", + outputs = { + # Exists for diffoscope: python's libarchive-c dlopens libarchive.so. + libarchive = { glob = "usr/lib/libarchive.so*" } | OutputLib, + headers = { glob = "usr/include/archive*.h" } | OutputData, + pkgconfig = { glob = "usr/lib/pkgconfig/libarchive.pc" } | OutputData, + }, + attrs = + { + upstream_version = version, + license_spdx = "BSD-2-Clause", + source_provenance = { + category = 'GithubRepo, + owner = "libarchive", + repo = "libarchive", + }, + } | Attrs, +} | BuildSpec diff --git a/packages/libarchive/build.sh b/packages/libarchive/build.sh new file mode 100755 index 00000000..05c524c2 --- /dev/null +++ b/packages/libarchive/build.sh @@ -0,0 +1,30 @@ +#!/bin/sh +set -ex + +tar -xof libarchive-3.8.1.tar.gz +cd libarchive-3.8.1 + +case $(uname -m) in + x86_64) MARCH="-march=x86-64-v3" ;; + aarch64) MARCH="-march=armv8-a" ;; + *) MARCH="" ;; +esac +export CFLAGS="$MARCH -O2 -pipe -gno-record-gcc-switches -ffile-prefix-map=$(pwd)=/builddir" +export LDFLAGS="-Wl,--build-id=none" +export CXXFLAGS="${CFLAGS}" + +# Library only — the bsd* tools aren't the point (diffoscope needs +# libarchive.so via python's libarchive-c) and every compressor we skip is a +# runtime dep we don't drag in. zlib/bzip2/zstd are the pkgs we already have. +./configure --prefix=/usr \ + --disable-bsdtar --disable-bsdcat --disable-bsdcpio --disable-bsdunzip \ + --with-zlib --with-bz2lib --with-zstd \ + --without-lz4 --without-lzo2 --without-lzma \ + --without-xml2 --without-expat \ + --without-openssl --without-nettle \ + --disable-acl --disable-xattr + +make -j"$(nproc)" +# NOTE: no `make check` — libarchive's suite wants ACL/xattr/locale support +# we deliberately configured out; failures there wouldn't indict the library. +make DESTDIR="$OUTPUT_DIR" install