8000 jvm ladder on aarch64 by bryan-minimal · Pull Request #910 · gominimal/pkgs · GitHub
[go: up one dir, main page]

Skip to content
Draft
151 changes: 151 additions & 0 deletions packages/ant-bootstrap-1.8.4/build-aarch64.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
#!/bin/bash
# aarch64 recipe, derived from build.sh: toolchain gcc against the system glibc (SR=/usr).
# ant-bootstrap-1.8.4: one rung of the JVM ladder (jikes-1.22 -> classpath-0.93 -> jamvm-1.5.1 -> ant-bootstrap-1.8.4 -> ecj-bootstrap-3.2.2 -> classpath-0.99 -> classpath-devel -> jamvm-2.0.0 -> ecj4-bootstrap-4.2.1 -> icedtea-7 -> icedtea-8 -> openjdk-9 -> ... -> openjdk-25).
# Apache Ant 1.8.4 built by jikes and run on jamvm-1.5.1 (bootstrap.sh); its jars feed the ecj compiles.
set -eu
# config.sub/config.guess in these tarballs predate aarch64: take automake's
refresh_config() {
for f in $(find . -name config.sub -o -name config.guess); do
cp "$(ls /usr/share/automake-*/"${f##*/}" | head -1)" "$f"
done
}
trap 'echo "ant-bootstrap-1.8.4: failed at line $LINENO: $BASH_COMMAND" >&2' ERR

if [ -n "$OUTPUT_DIR" ] && [ -d "$OUTPUT_DIR" ]; then
for _e in "$OUTPUT_DIR"/* "$OUTPUT_DIR"/.[!.]* "$OUTPUT_DIR"/..?*; do [ -e "$_e" ] || [ -L "$_e" ] && rm -r "$_e"; done
fi
mkdir -p "$OUTPUT_DIR"
BUILDROOT="$(pwd)"
PREFIX="/usr/lib/ant-bootstrap-1.8.4"
DST="${OUTPUT_DIR}${PREFIX}"
GCC_VERSION=15.2.0
SR=/usr
LOADER=/usr/lib/ld-linux-aarch64.so.1
JOBS="$(nproc 2>/dev/null || echo 4)"
export HOME="${BUILDROOT}/home"; mkdir -p "$HOME"
export TMPDIR="${BUILDROOT}/tmp"; mkdir -p "$TMPDIR"
export TAR_OPTIONS=--no-same-owner # the sandbox cannot chown
JVMFLAGS="-Xnocompact -Xnoinlining" # jamvm: without these the class-library builds can hang

# --- P0 preconditions ---
[ "$(uname -m)" = aarch64 ] || { echo "ant-bootstrap-1.8.4: aarch64 recipe on $(uname -m)" >&2; exit 1; }
for t in gcc g++ ld ar ranlib make sed grep tar find xargs sha256sum python3 awk diff bzip2; do
command -v "$t" >/dev/null 2>&1 || { echo "ant-bootstrap-1.8.4: '$t' not on PATH" >&2; exit 1; }
done
BGCC="$(command -v gcc)"; BGXX="$(command -v g++)"
GCCVER="$("${BGCC}" -dumpversion 2>/dev/null || echo unknown)"
[ "${GCCVER}" = "${GCC_VERSION}" ] || { echo "ant-bootstrap-1.8.4: gcc -dumpversion='${GCCVER}', expected '${GCC_VERSION}'" >&2; exit 1; }
[ -e "${SR}/lib/libc.so" ] || { echo "ant-bootstrap-1.8.4: glibc sysroot missing at ${SR}" >&2; exit 1; }
[ -e "${LOADER}" ] || { echo "ant-bootstrap-1.8.4: glibc loader missing at ${LOADER}" >&2; exit 1; }
for x in /usr/lib/jikes-1.22/bin/jikes /usr/lib/jamvm-1.5.1/bin/jamvm /usr/lib/classpath-0.93/share/classpath/glibj.zip; do [ -e "$x" ] || { echo "ant-bootstrap-1.8.4: missing boot artifact $x" >&2; exit 1; }; done

# --- P1 sysroot C/C++ wrappers ---
# The sysroot's libc.so is a linker script with staging paths; regenerate it.
FIXLIB="${BUILDROOT}/glibc-fixlib"; mkdir -p "${FIXLIB}"
sed -E "s@[^ ()]*/(libc\.so\.6|libc_nonshared\.a|ld-linux-aarch64\.so\.1)@${SR}/lib/\1@g" "${SR}/lib/libc.so" > "${FIXLIB}/libc.so"
if grep -q '/build/output' "${FIXLIB}/libc.so"; then echo "ant-bootstrap-1.8.4: libc.so fixup failed" >&2; exit 1; fi
# LNK goes BEFORE the caller's arguments: a makefile's own -Wl,-rpath,/usr/lib must not precede the sysroot in RPATH,
# or the sysroot's ld.so loads the system libc.so.6 (GLIBC_PRIVATE symbol lookup error)
LNK="-L${FIXLIB} -B${SR}/lib -L${SR}/lib -L/usr/lib -Wl,--dynamic-linker=${LOADER} -Wl,-rpath,${SR}/lib:/usr/lib -Wl,--build-id=none"
INC="-isystem ${SR}/include -isystem /usr/include"
# C++: rebuild g++'s own include chain (libstdc++, gcc freestanding) ahead of the sysroot's glibc headers, and
# /usr/include last. Hoisting a glibc dir above libstdc++ shadows its <math.h> wrapper (no float overloads) and
# a hoisted /usr/include empties the tail #include_next needs.
CXXINC=""; CXXTAIL=""
for d in $("${BGXX}" -E -x c++ -v /dev/null 2>&1 | sed -n '/#include <...> search starts here:/,/End of search list./p' | sed '1d;$d'); do
case "$d" in */c++/*) CXXINC="${CXXINC} -isystem $d" ;; /usr/include|/usr/local/include) ;; /usr/include/*) CXXTAIL="${CXXTAIL} -idirafter $d" ;; *) CXXINC="${CXXINC} -isystem $d" ;; esac
done
CXXINC="${CXXINC# } -isystem ${SR}/include${CXXTAIL} -idirafter /usr/include"
[ -n "$(echo "${CXXINC}" | grep -o 'c++')" ] || { echo "ant-bootstrap-1.8.4: cannot find g++'s libstdc++ include dirs" >&2; exit 1; }
CCDIR="${BUILDROOT}/cc"; mkdir -p "${CCDIR}"
cat > "${CCDIR}/gcc" <<WRAP
#!/bin/sh
for a in "\$@"; do case "\$a" in -c|-S|-E|-M|-MM) exec "${BGCC}" ${INC} "\$@" ;; esac; done
exec "${BGCC}" ${INC} ${LNK} "\$@"
WRAP
cat > "${CCDIR}/g++" <<WRAP
#!/bin/sh
for a in "\$@"; do case "\$a" in -c|-S|-E|-M|-MM) exec "${BGXX}" -nostdinc -nostdinc++ ${CXXINC} "\$@" ;; esac; done
exec "${BGXX}" -nostdinc -nostdinc++ ${CXXINC} ${LNK} "\$@"
WRAP
chmod 0755 "${CCDIR}/gcc" "${CCDIR}/g++"
export CC="${CCDIR}/gcc" CXX="${CCDIR}/g++"

JIKES=/usr/lib/jikes-1.22/bin/jikes; JAMVM=/usr/lib/jamvm-1.5.1/bin/jamvm; GLIBJ=/usr/lib/classpath-0.93/share/classpath/glibj.zip
# --- P2 build ---
mkdir src && tar -xjf apache-ant-1.8.4-src.tar.bz2 -C src --strip-components=1
cd src
# bootstrap.sh resolves `jikes` through PATH (build.compiler=jikes); the tests need a JDK this stack lacks
mkdir -p "${BUILDROOT}/bin"; ln -sf "${JIKES}" "${BUILDROOT}/bin/jikes"
export PATH="${BUILDROOT}/bin:${PATH}" JAVA_HOME=/usr/lib/jamvm-1.5.1 JAVACMD="${JAMVM}" JAVAC="${JIKES}" CLASSPATH="${GLIBJ}"
export ANT_OPTS="-Dbuild.compiler=jikes" BOOTJAVAC_OPTS="-nowarn"
: > "${HOME}/.ant.properties"
sed -i "s|^\"\${JAVACMD}\" |\"\${JAVACMD}\" ${JVMFLAGS} |" bootstrap.sh
sed -i 's|depends="jars,test-jar"|depends="jars"|' build.xml
bash bootstrap.sh -Ddist.dir="${DST}" > ../bootstrap.log 2>&1 || {
tail -40 ../bootstrap.log >&2
# what the class library thinks of the build tree (a directory mistaken for a file points at its stat glue)
ls -la build build/lib >&2 2>&1 || true; stat build/lib >&2 2>&1 || true
printf 'public class D { public static void main(String[] a){ for (int i = 0; i < a.length; i++) { java.io.File f = new java.io.File(a[i]); System.out.println(a[i] + " exists=" + f.exists() + " dir=" + f.isDirectory() + " file=" + f.isFile() + " canRead=" + f.canRead() + " len=" + f.length()); } } }\n' > ../D.java
"${JIKES}" -bootclasspath "${GLIBJ}" -d .. ../D.java >&2 2>&1 && "${JAMVM}" ${JVMFLAGS} -cp .. D "$(pwd)" "$(pwd)/build" "$(pwd)/build/lib" "$(pwd)/build.xml" /nonexistent "${DST}" >&2 2>&1 || true
"${JAMVM}" -version >&2 2>&1 | head -2 || true; stat -f -c 'fs=%T' . >&2 2>&1 || true
printf 'public class E { public static void main(String[] a){ String[] ps = { "build/lib", "./build/lib", "/build/src/build/lib", "build/classes", "nothere" }; for (int r = 0; r < 3; r++) for (int i = 0; i < ps.length; i++) { java.io.File f = new java.io.File(ps[i]); System.out.println(r + " " + ps[i] + " abs=" + f.getAbsolutePath() + " exists=" + f.exists() + " isFile=" + f.isFile() + " isDir=" + f.isDirectory()); } System.out.println("user.dir=" + System.getProperty("user.dir")); } }\n' > ../E.java
"${JIKES}" -bootclasspath "${GLIBJ}" -d .. ../E.java >&2 2>&1 || true
for v in "plain" "LD_BIND_NOW=1" "noflags" "MALLOC_PERTURB_=85"; do echo "--- E under $v" >&2
case $v in plain) "${JAMVM}" ${JVMFLAGS} -cp .. E 2>&1 | head -2 >&2;; noflags) "${JAMVM}" -cp .. E 2>&1 | head -2 >&2;; *) env $v "${JAMVM}" ${JVMFLAGS} -cp .. E 2>&1 | head -2 >&2;; esac; done || true
readelf -d /usr/lib/classpath-0.93/lib/classpath/libjavaio.so 2>/dev/null | grep -E 'FLAGS|BIND' >&2 || true; readelf -d "${JAMVM}" 2>/dev/null | grep -E 'FLAGS|BIND' >&2 || true
echo "ant-bootstrap-1.8.4: bootstrap.sh failed" >&2; exit 1; }
unset CLASSPATH
cd "${BUILDROOT}"
# --- P3 gate ---
[ -s "${DST}/lib/ant.jar" ] || { echo "ant-bootstrap-1.8.4: lib/ant.jar missing" >&2; exit 1; }
[ "$(ls "${DST}"/lib/*.jar | wc -l)" -ge 5 ] || { echo "ant-bootstrap-1.8.4: too few jars" >&2; exit 1; }

# --- P4 deterministic archives: zip entry timestamps and order are build-time noise ---
python3 - "${DST}" <<'PYEOF'
import io, os, shutil, sys, zipfile
def norm_bytes(b):
"""Rewrite a zip: fixed entry timestamps, sorted entries (manifest first), nested jars normalised too."""
with zipfile.ZipFile(io.BytesIO(b)) as z:
infos = z.infolist(); data = {i.filename: z.read(i) for i in infos}
order = sorted(infos, key=lambda i: (0 if i.filename == 'META-INF/MANIFEST.MF' else 1 if i.filename.startswith('META-INF/') else 2, i.filename))
out = io.BytesIO()
with zipfile.ZipFile(out, 'w') as o:
for i in order:
d = data[i.filename]
if (i.filename.endswith(('.jar', '.zip')) or i.filename.endswith('ct.sym')) and zipfile.is_zipfile(io.BytesIO(d)): d = norm_bytes(d)
zi = zipfile.ZipInfo(i.filename, date_time=(1980, 1, 1, 0, 0, 0))
zi.compress_type = i.compress_type; zi.external_attr = i.external_attr; zi.create_system = 3
o.writestr(zi, d)
return out.getvalue()
root = sys.argv[1]; n = 0
for dp, _, fn in os.walk(root):
for f in fn:
p = os.path.join(dp, f)
if os.path.islink(p) or not (f.endswith(('.jar', '.zip', '.war', '.jmod')) or f == 'ct.sym'): continue
with open(p, 'rb') as fh: raw = fh.read()
head = b''
if f.endswith('.jmod'): # a jmod is a zip behind a 4-byte "JM" magic
if raw[:2] != b'JM': continue
head, raw = raw[:4], raw[4:]
if not zipfile.is_zipfile(io.BytesIO(raw)): continue
tmp = p + '.tmp'
with open(tmp, 'wb') as out: out.write(head); out.write(norm_bytes(raw))
shutil.copymode(p, tmp); os.replace(tmp, p); n += 1
print("normalised", n, "archives")
PYEOF
# class-data-sharing archives are dumped at build time from a live VM and do not reproduce; the VM runs without them
find "${DST}" -name 'classes*.jsa' -type f -delete
# src.zip carries generated sources that do not reproduce; a bootstrap JDK does not need it
find "${DST}" -name 'src.zip' -type f -delete
# the default class list is written in class-load order, which varies run to run; only its membership matters
[ ! -f "${DST}/lib/classlist" ] || { LC_ALL=C sort "${DST}/lib/classlist" > "${DST}/lib/classlist.sorted" && mv "${DST}/lib/classlist.sorted" "${DST}/lib/classlist"; }

mkdir -p "${OUTPUT_DIR}/usr/share/ant-bootstrap-1.8.4"
cat > "${OUTPUT_DIR}/usr/share/ant-bootstrap-1.8.4/BUILDINFO" <<EOF
ant-bootstrap-1.8.4
source: apache-ant-1.8.4-src.tar.bz2
compiler: jikes-1.22 on jamvm-1.5.1
c compiler: gcc ${GCC_VERSION}; sysroot: ${SR}
EOF
echo "ant-bootstrap-1.8.4: installed to ${PREFIX}"
73 changes: 36 additions & 37 deletions packages/ant-bootstrap-1.8.4/build.ncl
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ let gcc-bedrock = import "../gcc-15.2.0-glibc/build.ncl" in # asserted by build.
# /usr/lib, and a mixed pair crashes as
let binutils = import "../binutils/build.ncl" in
let glibc-bedrock = import "../glibc-bedrock-2.42/build.ncl" in # sysroot
let toolchain = import "../toolchain/build.ncl" in # aarch64: gcc, binutils and glibc, built from the hex0 seed
let glibc = import "../glibc/build.ncl" in
let autoconf = import "../autoconf/build.ncl" in # aarch64: config.sub refresh, autoreconf
let automake = import "../automake/build.ncl" in
let libtool = import "../libtool/build.ncl" in
let m4 = import "../m4/build.ncl" in
let is_arm = target.arch == 'Arm64 in
let bash = import "../bash/build.ncl" in
let make = import "../make/build.ncl" in
let sed = import "../sed/build.ncl" in
Expand All @@ -28,35 +35,36 @@ let diffutils = import "../diffutils/build.ncl" in
let bzip2 = import "../bzip2/build.ncl" in # the source is a .tar.bz2
# pkgmgr: bootstrap_rung = "jvm"
let version = "1.8.4" in
let amd64_spec =
let amd64_spec = # both arches: the x86_64 inputs or aarch64's, picked by is_arm
{
name = "ant-bootstrap-1.8.4",
build_deps = [
{ file = "build.sh" } | Local,
{
url = "gs://minimal-staging-archives/apache-ant-1.8.4-src.tar.bz2",
sha256 = "5de65f7ba3f67e436ffffcdc0a73f591d1006e9fb41af8632c1f1f84d4a3e0b1",
extract = false, # build.sh untars with --no-same-owner
} | Source,
jikes-1-22,
jamvm-1-5-1,
classpath-0-93,
gcc-bedrock,
binutils,
glibc-bedrock,
bash,
make,
sed,
grep,
coreutils,
findutils,
tar,
bzip2,
python,
gawk,
diffutils,
],
cmd = "./build.sh",
build_deps =
[
(if is_arm then { file = "build-aarch64.sh" } else { file = "build.sh" }) | Local,
{
url = "gs://minimal-staging-archives/apache-ant-1.8.4-src.tar.bz2",
sha256 = "5de65f7ba3f67e436ffffcdc0a73f591d1006e9fb41af8632c1f1f84d4a3e0b1",
extract = false, # build.sh untars with --no-same-owner
} | Source,
jikes-1-22,
jamvm-1-5-1,
classpath-0-93,
]
@ (if is_arm then [toolchain, autoconf, automake, libtool, m4] else [gcc-bedrock, binutils, glibc-bedrock])
@ [
bash,
make,
sed,
grep,
coreutils,
findutils,
tar,
bzip2,
python,
gawk,
diffutils,
],
cmd = if is_arm then "./build-aarch64.sh" else "./build.sh",
outputs = {
# consumed by the next rung by absolute path
prefix = { glob = "usr/lib/ant-bootstrap-1.8.4/**", allow_executable = true } | OutputData,
Expand All @@ -75,13 +83,4 @@ let amd64_spec =
} | Attrs,
} | BuildSpec
in
# amd64 only: this rung belongs to the amd64 bootstrap ladder; the spec collapses to an empty
# collection on arm64.
match {
{ arch = 'Amd64, .. } => amd64_spec,
{ arch = 'Arm64, .. } =>
{
name = "ant-bootstrap-1.8.4",
build_deps = [],
} | BuildSpec,
} target
amd64_spec
Loading
Loading
0