mirror of
https://github.com/Klipper4FlashForge/firmware.git
synced 2026-10-22 05:12:16 -05:00
That is why bin/patch.sh section 5c was 825 lines and why a Pillow bump
rebuilt CPython. Cross-building an extension module needs the untrimmed
staging tree (INCLUDEPY points into it), the private sysroot of static C
libraries (pillow links zlib, cffi links libffi) and an x86-64 build-python
of the same version -- and all three existed only mid-section, so the wheels
had to be built there too, on a cache with two stamps that invalidated each
other.
Each of those three is now a durable thing: anvil-python-dev carries the
headers, pkg_deps fills each recipe's own sysroot from the feed, and
pkg_buildpython caches one build-python for all nineteen recipes. So the
coupling goes away with them -- `make packages PKG=python-pillow` builds
Pillow.
pkg/python -> anvil-python + anvil-python-dev
pkg/python-<name> x18 -> anvil-python-distro, anvil-python-pillow, ...
Three verbs in pkg/lib.sh, shared by all nineteen rather than one per awkward
project: pkg_buildpython provides the build-python, pkg_pytarget points its
sysconfig at the target headers in the sysroot, pkg_pywheel builds one wheel
and unpacks it into the staging site-packages. greenlet's gcc 7.2 designated
initializers, lmdb's LMDB_FORCE_CPYTHON and pillow's build_ext options are
recipe lines and a PKG_PY_SETUP_ARGS knob, not three more verbs.
Eighteen versions that were invisible are now in the feed index, anvil-moonraker
declares the thirteen packages it imports, and a printer that does not want
gcode thumbnails can leave Pillow uninstalled.
PY_STAMP, PYPKG_STAMP and PY_BUILD are gone: pkg_stamp derives the key from
PKG_BUILD_DEPENDS, and bin/fetch-assets.sh asks pkg_needs instead of
re-deriving a stamp bin/patch.sh also derived. Two of its four toolchain
conditions were that second spelling.
Measured:
* 40 packages; 959 site-packages files, none owned by two packages
* 12 mipsel extension modules -- the count the old gate demanded
* every Depends resolves inside the feed (24 declare one, 0 unsatisfiable)
* two cold builds byte-identical, with work/pkg, work/.py-host and the
unpacked toolchain deleted in between
* 233 static tests, 4 new: the PYPKG_LIST/recipe agreement both ways, no
version pinned twice, patch.sh builds every package, and no Depends
naming a package no recipe produces
Not verified here: the replica suite. It needs the stock FlashForge package,
which the packaging lane deliberately does without.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
398 lines
18 KiB
Bash
Executable File
398 lines
18 KiB
Bash
Executable File
#!/bin/bash
|
|
# ---------------------------------------------------------------------------
|
|
# Cross-build CPython 3.13 for the FlashForge Creator 5 Pro (Ingenic mipsel).
|
|
#
|
|
# THIS IS THE MEASUREMENT HARNESS, NOT THE BUILD. pkg/python is what produces
|
|
# the interpreter a package ships: it compiles inside the repo's own build
|
|
# image, from the tarballs pinned in versions.env, and caches the result in
|
|
# work/pkg/python. The two are the same build -- same flags,
|
|
# same wrappers, same gates -- but this one re-execs itself inside a
|
|
# throwaway debian:bookworm, which is how every number in README.md beside it
|
|
# was measured, and which is the fastest way to try a change to the recipe
|
|
# without touching the build lane. Exactly the relationship
|
|
# tools/supervisor/build.sh has to section 5b.
|
|
#
|
|
# Target ABI, measured, non-negotiable:
|
|
# e_flags = 0x70001405 = ELF32 / little-endian / NAN2008 / O32 /
|
|
# hard-float / mips32r2
|
|
# loader = /lib/ld-linux-mipsn8.so.1 , rootfs glibc 2.33
|
|
#
|
|
# Toolchain: the repo's Ingenic gcc 7.2 / glibc 2.29 cross compiler -- the SAME
|
|
# one bin/patch.sh uses for klippy's c_helper.so. musl is forbidden: a
|
|
# musl-linked interpreter cannot dlopen a glibc c_helper.so, which is exactly
|
|
# how klippy loads it. glibc 2.29 -> 2.33 is forward compatible.
|
|
#
|
|
# `-EL -mnan=2008` must reach BOTH the compile and the link of every object.
|
|
# Rather than trust each project's build system to forward CFLAGS to its link
|
|
# line (several do not), we install PATH wrappers that bake the two flags into
|
|
# the driver itself. That is the single most important trick in this file.
|
|
#
|
|
# Usage:
|
|
# ./tools/python/build.sh # the whole thing, in docker
|
|
# ./tools/python/build.sh --in-container # the actual build
|
|
#
|
|
# Artifacts land in tools/python/out/ (gitignored, like everything else this
|
|
# repo builds): py313.tgz is the trimmed tree the payload would carry,
|
|
# py313-full.tgz is everything `make install` produced.
|
|
# ---------------------------------------------------------------------------
|
|
set -euo pipefail
|
|
|
|
HERE="$(cd "$(dirname "$0")" && pwd)"
|
|
REPO="${REPO:-$(cd "$HERE/../.." && pwd)}"
|
|
TOOLCHAIN_HOST="$REPO/work/.mips-toolchain/mips-gcc720-glibc229"
|
|
|
|
# --------------------------------------------------------------- versions ---
|
|
# Kept in step with versions.env by hand. They are duplicated rather than
|
|
# sourced because this script has to run against a source tree it is
|
|
# experimenting on -- bumping a version HERE first, seeing what breaks, and
|
|
# only then editing the pin -- which is the whole reason it still exists.
|
|
PY_VER="${PY_VER:-3.13.7}"
|
|
ZLIB_VER=1.3.1
|
|
OSSL_VER=3.0.15
|
|
FFI_VER=3.4.6
|
|
SQLITE_TAR=sqlite-autoconf-3460100 # 3.46.1
|
|
XZ_VER=5.4.7
|
|
BZIP2_VER=1.0.8
|
|
EXPAT_VER=2.6.4
|
|
EXPAT_TAG=R_2_6_4
|
|
# The mod's prefix root on the printer, and the same --prefix bin/patch.sh
|
|
# builds with: bin/python3.13 beside bin/s6-svscan, stdlib in
|
|
# lib/python3.13/. The one difference is that patch.sh deletes the `python3`
|
|
# symlink (and idle3/pydoc3/*-config) out of bin/ before staging, so that
|
|
# putting $MODDIR/bin on PATH cannot quietly change what `python3` means --
|
|
# see tools/python/README.md. This harness leaves the tree as `make install`
|
|
# produced it, because the sizes reported below are of that tree.
|
|
PREFIX=/usr/data/anvil
|
|
|
|
# ------------------------------------------------------- docker wrapper -----
|
|
if [ "${1:-}" != "--in-container" ]; then
|
|
[ -x "$TOOLCHAIN_HOST/bin/mips-linux-gnu-gcc" ] || {
|
|
echo "!! no toolchain at $TOOLCHAIN_HOST" >&2
|
|
echo " run ./bin/fetch-assets.sh, then any build (bin/patch.sh unpacks it)" >&2
|
|
exit 1; }
|
|
exec docker run --rm \
|
|
-v "$TOOLCHAIN_HOST":/toolchain:ro \
|
|
-v "$HERE":/work \
|
|
-e PY_VER="$PY_VER" -e PY_EXTRA_CONFIGURE="${PY_EXTRA_CONFIGURE:-}" \
|
|
-e HOST_UID="$(id -u)" -e HOST_GID="$(id -g)" \
|
|
-w /work debian:bookworm \
|
|
bash /work/build.sh --in-container
|
|
fi
|
|
|
|
# =========================== everything below runs inside the container ======
|
|
START=$(date +%s)
|
|
export DEBIAN_FRONTEND=noninteractive
|
|
TC=/toolchain
|
|
W=/work
|
|
SRC=$W/src # tarball cache (survives between runs)
|
|
B=$W/build # scratch: unpacked trees
|
|
HOSTPY=$W/hostpy # the x86-64 build-Python 3.13 (--with-build-python)
|
|
DEP=$W/deproot # cross-built C libraries, STATIC. Not shipped.
|
|
STAGE=$W/stage # DESTDIR: what actually goes on the printer
|
|
OUT=$W/out
|
|
mkdir -p "$SRC" "$B" "$HOSTPY" "$DEP" "$OUT"
|
|
|
|
log() { echo; echo "===== $* ====="; }
|
|
|
|
log "apt: build dependencies"
|
|
apt-get update -qq
|
|
apt-get install -y -qq --no-install-recommends \
|
|
build-essential curl ca-certificates pkg-config perl file xz-utils \
|
|
zlib1g-dev libssl-dev libffi-dev >/dev/null
|
|
|
|
# ------------------------------------------------------- the wrappers -------
|
|
# -EL -mnan=2008 on every invocation, compile or link. Without -mnan=2008 the
|
|
# objects are legacy-NaN and the kernel refuses to load the result.
|
|
log "toolchain wrappers (-EL -mnan=2008 baked in)"
|
|
mkdir -p /opt/xw/bin
|
|
for t in gcc g++ cpp; do
|
|
cat > /opt/xw/bin/mips-linux-gnu-$t <<EOF
|
|
#!/bin/sh
|
|
exec $TC/bin/mips-linux-gnu-$t -EL -mnan=2008 "\$@"
|
|
EOF
|
|
chmod +x /opt/xw/bin/mips-linux-gnu-$t
|
|
done
|
|
for t in ar as ld nm objcopy objdump ranlib readelf strip strings size; do
|
|
ln -sf $TC/bin/mips-linux-gnu-$t /opt/xw/bin/mips-linux-gnu-$t
|
|
done
|
|
export PATH=/opt/xw/bin:$PATH
|
|
mips-linux-gnu-gcc --version | head -1
|
|
|
|
# gate the wrapper itself before building 300MB on top of it
|
|
echo 'int main(void){return 0;}' > /tmp/abi.c
|
|
mips-linux-gnu-gcc /tmp/abi.c -o /tmp/abi.out
|
|
FLAGS=$(mips-linux-gnu-readelf -h /tmp/abi.out | awk '/Flags:/{print $2}' | tr -d ,)
|
|
echo "wrapper produces e_flags=$FLAGS"
|
|
[ "$FLAGS" = "0x70001405" ] || { echo "!! wrong ABI from the wrapper"; exit 1; }
|
|
|
|
# ------------------------------------------------------------ fetch ---------
|
|
# No sha256 here on purpose: versions.env holds the pins and
|
|
# bin/fetch-assets.sh is what enforces them for anything that ships. This
|
|
# harness downloads whatever version you point it at, which is what makes it
|
|
# useful for deciding whether a bump is safe BEFORE it becomes a pin.
|
|
fetch() { # fetch <url> -> $SRC/<basename>, cached
|
|
local url=$1 f="$SRC/$(basename "$1")"
|
|
[ -s "$f" ] || { echo ">> $url"; curl -sSLf -o "$f.part" "$url" && mv "$f.part" "$f"; }
|
|
}
|
|
log "fetch sources"
|
|
fetch https://www.python.org/ftp/python/$PY_VER/Python-$PY_VER.tgz
|
|
fetch https://zlib.net/fossils/zlib-$ZLIB_VER.tar.gz
|
|
fetch https://github.com/openssl/openssl/releases/download/openssl-$OSSL_VER/openssl-$OSSL_VER.tar.gz
|
|
fetch https://github.com/libffi/libffi/releases/download/v$FFI_VER/libffi-$FFI_VER.tar.gz
|
|
fetch https://www.sqlite.org/2024/$SQLITE_TAR.tar.gz
|
|
fetch https://github.com/tukaani-project/xz/releases/download/v$XZ_VER/xz-$XZ_VER.tar.gz
|
|
fetch https://sourceware.org/pub/bzip2/bzip2-$BZIP2_VER.tar.gz
|
|
fetch https://github.com/libexpat/libexpat/releases/download/$EXPAT_TAG/expat-$EXPAT_VER.tar.gz
|
|
|
|
unpack() { rm -rf "$B/${2}"; tar -xf "$SRC/$1" -C "$B"; }
|
|
|
|
# ============================================ 1. host CPython 3.13 ==========
|
|
# Cross-building CPython needs a build-Python of the *same* version: the
|
|
# Makefile runs it to freeze modules, generate deepfreeze sources and byte
|
|
# compile the stdlib. A distro python3.11 will not do.
|
|
if [ ! -x "$HOSTPY/bin/python3.13" ]; then
|
|
log "host CPython $PY_VER (x86-64, for --with-build-python)"
|
|
unpack Python-$PY_VER.tgz Python-$PY_VER
|
|
cd "$B/Python-$PY_VER"
|
|
./configure --prefix="$HOSTPY" --without-ensurepip >/dev/null
|
|
make -j"$(nproc)" >/dev/null
|
|
make install >/dev/null
|
|
cd /
|
|
else
|
|
log "host CPython already built -- reusing $HOSTPY"
|
|
fi
|
|
"$HOSTPY/bin/python3.13" -VV
|
|
|
|
# ============================================ 2. cross C libraries ==========
|
|
# All STATIC (-fPIC) into $DEP. Rationale: linking them into the interpreter
|
|
# and its extension modules means the shipped tree has no .so of ours to find
|
|
# at runtime, so there is no LD_LIBRARY_PATH for dependencies, no chance of
|
|
# picking up FlashForge's /usr/prog copies, and nothing to version-skew. The
|
|
# only cost is a few MB of duplicated libcrypto between _ssl.so and _hashlib.so.
|
|
export CC=mips-linux-gnu-gcc
|
|
export CXX=mips-linux-gnu-g++
|
|
export AR=mips-linux-gnu-ar
|
|
export RANLIB=mips-linux-gnu-ranlib
|
|
export STRIP=mips-linux-gnu-strip
|
|
export CFLAGS="-O2 -fPIC -D_FILE_OFFSET_BITS=64"
|
|
export CPPFLAGS="-I$DEP/include"
|
|
export LDFLAGS="-L$DEP/lib"
|
|
# pkg-config must see ONLY our sysroot, never the container's /usr/lib.
|
|
export PKG_CONFIG_LIBDIR="$DEP/lib/pkgconfig"
|
|
export PKG_CONFIG_PATH="$DEP/lib/pkgconfig"
|
|
HOSTTRIPLE=mips-linux-gnu
|
|
BUILDTRIPLE=x86_64-linux-gnu
|
|
|
|
log "zlib $ZLIB_VER"
|
|
unpack zlib-$ZLIB_VER.tar.gz zlib-$ZLIB_VER
|
|
cd "$B/zlib-$ZLIB_VER"
|
|
CHOST=$HOSTTRIPLE ./configure --prefix="$DEP" --static >/dev/null
|
|
make -j"$(nproc)" >/dev/null && make install >/dev/null
|
|
|
|
log "openssl $OSSL_VER"
|
|
unpack openssl-$OSSL_VER.tar.gz openssl-$OSSL_VER
|
|
cd "$B/openssl-$OSSL_VER"
|
|
# linux-mips32 is the O32 target. openssldir points at where the interpreter
|
|
# will look for certs ON THE PRINTER, not at a build path.
|
|
#
|
|
# Two traps, both hit for real:
|
|
# * `no-docs` only exists from OpenSSL 3.1. On 3.0.15 it is an "Unsupported
|
|
# options" hard error, not a warning.
|
|
# * the linux-mips32 target hardcodes `-mips2` into its cflags. This
|
|
# toolchain defaults to -mfp64 (hard-float, fp64 registers), and gcc
|
|
# rejects `-mgp32 -mfp64` on anything below mips32r2:
|
|
# error: '-mgp32' and '-mfp64' can only be combined if the target
|
|
# supports the mfhc1 and mthc1 instructions
|
|
# User cflags land AFTER the target's on the command line, so appending
|
|
# -mips32r2 puts the ISA back where the printer actually is. If a future
|
|
# OpenSSL orders them the other way, linux-generic32 (portable C, no mips
|
|
# assembly) is the fallback and is exercised below.
|
|
OSSL_TARGET=linux-mips32
|
|
OSSL_ISA=-mips32r2
|
|
./Configure $OSSL_TARGET \
|
|
--prefix="$DEP" --libdir=lib --openssldir=$PREFIX/ssl \
|
|
no-shared no-tests \
|
|
-fPIC -O2 $OSSL_ISA -D_FILE_OFFSET_BITS=64 >/dev/null
|
|
if ! make -j"$(nproc)" >"$OUT/openssl.log" 2>&1; then
|
|
echo "!! $OSSL_TARGET failed; falling back to linux-generic32 (no mips asm)"
|
|
tail -20 "$OUT/openssl.log"
|
|
make distclean >/dev/null 2>&1 || true
|
|
./Configure linux-generic32 \
|
|
--prefix="$DEP" --libdir=lib --openssldir=$PREFIX/ssl \
|
|
no-shared no-tests no-asm \
|
|
-fPIC -O2 -D_FILE_OFFSET_BITS=64 >/dev/null
|
|
make -j"$(nproc)" >"$OUT/openssl.log" 2>&1
|
|
fi
|
|
make install_sw >/dev/null
|
|
|
|
log "libffi $FFI_VER"
|
|
unpack libffi-$FFI_VER.tar.gz libffi-$FFI_VER
|
|
cd "$B/libffi-$FFI_VER"
|
|
./configure --host=$HOSTTRIPLE --build=$BUILDTRIPLE --prefix="$DEP" \
|
|
--disable-shared --enable-static --with-pic --disable-docs >/dev/null
|
|
make -j"$(nproc)" >/dev/null && make install >/dev/null
|
|
|
|
log "sqlite ($SQLITE_TAR) -- THE reason this whole exercise exists"
|
|
unpack $SQLITE_TAR.tar.gz $SQLITE_TAR
|
|
cd "$B/$SQLITE_TAR"
|
|
./configure --host=$HOSTTRIPLE --build=$BUILDTRIPLE --prefix="$DEP" \
|
|
--disable-shared --enable-static --with-pic \
|
|
--disable-readline --disable-editline >/dev/null
|
|
make -j"$(nproc)" >/dev/null && make install >/dev/null
|
|
|
|
log "xz (liblzma) $XZ_VER"
|
|
unpack xz-$XZ_VER.tar.gz xz-$XZ_VER
|
|
cd "$B/xz-$XZ_VER"
|
|
./configure --host=$HOSTTRIPLE --build=$BUILDTRIPLE --prefix="$DEP" \
|
|
--disable-shared --enable-static --with-pic \
|
|
--disable-xz --disable-xzdec --disable-lzmadec --disable-lzmainfo \
|
|
--disable-scripts --disable-doc --disable-nls >/dev/null
|
|
make -j"$(nproc)" >/dev/null && make install >/dev/null
|
|
|
|
log "bzip2 $BZIP2_VER"
|
|
unpack bzip2-$BZIP2_VER.tar.gz bzip2-$BZIP2_VER
|
|
cd "$B/bzip2-$BZIP2_VER"
|
|
# bzip2 has no configure; drive its Makefile directly.
|
|
make -j"$(nproc)" libbz2.a CC="$CC" AR="$AR" RANLIB="$RANLIB" \
|
|
CFLAGS="-O2 -fPIC -D_FILE_OFFSET_BITS=64 -Wall -Winline" >/dev/null
|
|
install -m644 libbz2.a "$DEP/lib/"
|
|
install -m644 bzlib.h "$DEP/include/"
|
|
|
|
log "expat $EXPAT_VER"
|
|
unpack expat-$EXPAT_VER.tar.gz expat-$EXPAT_VER
|
|
cd "$B/expat-$EXPAT_VER"
|
|
./configure --host=$HOSTTRIPLE --build=$BUILDTRIPLE --prefix="$DEP" \
|
|
--disable-shared --enable-static --with-pic \
|
|
--without-docbook --without-examples --without-tests >/dev/null
|
|
make -j"$(nproc)" >/dev/null && make install >/dev/null
|
|
|
|
echo "-- $DEP/lib --"; ls "$DEP/lib"
|
|
|
|
# ============================================ 3. CPython, cross =============
|
|
log "CPython $PY_VER cross for $HOSTTRIPLE"
|
|
unpack Python-$PY_VER.tgz Python-$PY_VER
|
|
cd "$B/Python-$PY_VER"
|
|
|
|
# Answers configure cannot probe because it may not run target binaries.
|
|
cat > "$B/config.site" <<'EOF'
|
|
ac_cv_file__dev_ptmx=yes
|
|
ac_cv_file__dev_ptc=no
|
|
ac_cv_buggy_getaddrinfo=no
|
|
ac_cv_little_endian_double=yes
|
|
ac_cv_big_endian_double=no
|
|
ac_cv_mixed_endian_double=no
|
|
ac_cv_working_tzset=yes
|
|
ac_cv_have_long_long_format=yes
|
|
ac_cv_no_strict_aliasing=no
|
|
ac_cv_pthread_system_supported=yes
|
|
EOF
|
|
|
|
export CONFIG_SITE="$B/config.site"
|
|
export CPPFLAGS="-I$DEP/include"
|
|
export LDFLAGS="-L$DEP/lib"
|
|
# -latomic: 64-bit atomics on mips32 are out-of-line calls into libatomic, and
|
|
# CPython 3.13's _Py_atomic_* on 64-bit types needs them.
|
|
# -lm: because the sqlite/lzma/expat libraries here are STATIC. A shared
|
|
# libsqlite3.so carries its own DT_NEEDED on libm; a libsqlite3.a does not,
|
|
# so configure's `checking for sqlite3_bind_double in -lsqlite3` link probe
|
|
# fails with a wall of `undefined reference to floor/log/pow/...` and 3.13
|
|
# silently records _sqlite3 as "missing" -- which is the one module this
|
|
# whole build exists for. It is a probe failure, not a compile failure, so
|
|
# nothing in the build output says why.
|
|
export LIBS="-latomic -lm"
|
|
export CFLAGS="-O2 -D_FILE_OFFSET_BITS=64"
|
|
# Bypass pkg-config for sqlite and state the static link line outright, so the
|
|
# -lm above cannot be reordered out from under the probe.
|
|
export LIBSQLITE3_CFLAGS="-I$DEP/include"
|
|
export LIBSQLITE3_LIBS="-L$DEP/lib -lsqlite3 -lm"
|
|
|
|
./configure \
|
|
--host=$HOSTTRIPLE --build=$BUILDTRIPLE \
|
|
--with-build-python="$HOSTPY/bin/python3.13" \
|
|
--prefix=$PREFIX \
|
|
--disable-shared \
|
|
--without-ensurepip \
|
|
--disable-test-modules \
|
|
--with-openssl="$DEP" \
|
|
--with-system-expat \
|
|
${PY_EXTRA_CONFIGURE:-} 2>&1 | tee "$OUT/configure.log" | tail -60
|
|
|
|
echo "-- configure: modules it decided it could not build --"
|
|
grep -iE 'could not be built|missing|failed to build' -A6 "$OUT/configure.log" | tail -40 || true
|
|
|
|
make -j"$(nproc)" 2>&1 | tee "$OUT/make.log" | tail -40
|
|
echo "-- build: modules that failed --"
|
|
grep -iE 'necessary bits|could not be found|failed to build these' -A10 "$OUT/make.log" | tail -40 || true
|
|
|
|
rm -rf "$STAGE"
|
|
make install DESTDIR="$STAGE" 2>&1 | tail -20
|
|
|
|
# ============================================ 4. gates + package ============
|
|
log "ABI gate on every ELF in the stage"
|
|
# The measured target word is 0x70001405 for an EXECUTABLE. Shared objects
|
|
# additionally carry EF_MIPS_PIC (0x2) and so read 0x70001407 -- that is
|
|
# correct and unavoidable for a DYN, and klippy's own c_helper.so has it too.
|
|
# So gate on the ABI ATTRIBUTES, which is also what bin/patch.sh does
|
|
# (`readelf -h | grep -q nan2008`), and pin the whole word per ELF type.
|
|
BAD=0; N=0
|
|
while IFS= read -r f; do
|
|
case "$(file -b "$f")" in *ELF*) ;; *) continue;; esac
|
|
hdr=$(mips-linux-gnu-readelf -h "$f" 2>/dev/null)
|
|
fl=$(echo "$hdr" | awk '/Flags:/{print $2}' | tr -d ,)
|
|
typ=$(echo "$hdr" | awk '/^ Type:/{print $2}')
|
|
want=0x70001405; [ "$typ" = "DYN" ] && want=0x70001407
|
|
case "$hdr" in
|
|
*nan2008*o32*mips32r2*) ;;
|
|
*) echo "!! $f not nan2008/o32/mips32r2"; BAD=1; continue;;
|
|
esac
|
|
if [ "$fl" != "$want" ]; then
|
|
echo "!! $f type=$typ flags=$fl want=$want"; BAD=1
|
|
fi
|
|
N=$((N+1))
|
|
done < <(find "$STAGE" -type f)
|
|
[ $BAD -eq 0 ] && echo "$N ELF objects, all nan2008/o32/mips32r2 (EXEC 0x70001405, DYN 0x70001407)" || exit 1
|
|
|
|
# _sqlite3 is the reason this build exists. Its absence must be a hard error,
|
|
# not a line in a 400-line make log that nobody reads.
|
|
if ! ls "$STAGE$PREFIX/lib/python3.13/lib-dynload/"_sqlite3*.so >/dev/null 2>&1; then
|
|
echo "!! NO _sqlite3 MODULE WAS BUILT -- see $OUT/configure.log and config.log"
|
|
exit 1
|
|
fi
|
|
echo "_sqlite3 present: $(basename "$(ls "$STAGE$PREFIX/lib/python3.13/lib-dynload/"_sqlite3*.so)")"
|
|
|
|
echo "-- NEEDED of the interpreter --"
|
|
mips-linux-gnu-readelf -d "$STAGE$PREFIX/bin/python3.13" | grep -E 'NEEDED|RPATH|RUNPATH' || true
|
|
echo "-- lib-dynload --"
|
|
ls "$STAGE$PREFIX/lib/python3.13/lib-dynload/" | sed 's/\.cpython.*//' | sort | tr '\n' ' '; echo
|
|
|
|
log "sizes"
|
|
FULL=$(du -sm "$STAGE" | cut -f1)
|
|
# trimmed: what would actually ship
|
|
rm -rf "$W/stage-trim"
|
|
cp -a "$STAGE" "$W/stage-trim"
|
|
rm -rf "$W/stage-trim$PREFIX/lib/python3.13/test" \
|
|
"$W/stage-trim$PREFIX/lib/python3.13/idlelib" \
|
|
"$W/stage-trim$PREFIX/lib/python3.13/tkinter" \
|
|
"$W/stage-trim$PREFIX/lib/python3.13/turtledemo" \
|
|
"$W/stage-trim$PREFIX/lib/python3.13/config-"* \
|
|
"$W/stage-trim$PREFIX/include" \
|
|
"$W/stage-trim$PREFIX/share"
|
|
find "$W/stage-trim" -name '__pycache__' -prune -exec rm -rf {} + 2>/dev/null || true
|
|
find "$W/stage-trim" -name '*.a' -delete
|
|
mips-linux-gnu-strip "$W/stage-trim$PREFIX/bin/python3.13" 2>/dev/null || true
|
|
find "$W/stage-trim$PREFIX/lib/python3.13/lib-dynload" -name '*.so' \
|
|
-exec mips-linux-gnu-strip {} + 2>/dev/null || true
|
|
TRIM=$(du -sm "$W/stage-trim" | cut -f1)
|
|
echo "staged : ${FULL} MB, $(find "$STAGE" -type f | wc -l) files"
|
|
echo "trimmed : ${TRIM} MB, $(find "$W/stage-trim" -type f | wc -l) files"
|
|
|
|
log "tarballs"
|
|
# The tarball's root is 'usr/data/anvil/...' relative -- unpack with -C /
|
|
( cd "$STAGE" && tar -czf "$OUT/py313-full.tgz" usr )
|
|
( cd "$W/stage-trim" && tar -czf "$OUT/py313.tgz" usr )
|
|
ls -l "$OUT"/*.tgz
|
|
chown -R "${HOST_UID:-0}:${HOST_GID:-0}" "$W" 2>/dev/null || true
|
|
|
|
END=$(date +%s)
|
|
log "done in $(( (END-START)/60 ))m $(( (END-START)%60 ))s"
|