Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,6 @@ m4l-hang-*/
# bytecode from tools/m4l-font-audit.py
__pycache__/
*.pyc

# installers
ableton*.zip
20 changes: 18 additions & 2 deletions Containerfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ ARG LLVM_PKG_VERSION=1:21.1.8~++20251221032842+2078da43e25a-1~exp1~2025122115300
# Ubuntu archive state used for every jammy package below (snapshot.ubuntu.com).
ARG UBUNTU_SNAPSHOT=20260718T000000Z
ARG CA_CERTIFICATES_VERSION=20260601~22.04.1
ARG ARCH

# 1. Establish every package source before the first apt operation. The pinned
# base image carries Ubuntu's archive key but not a CA bundle. The one bootstrap
Expand Down Expand Up @@ -88,6 +89,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev \
# TLS (Live online auth / pack downloads), USB display bridge, XDG portal
libgnutls28-dev libusb-1.0-0-dev libudev-dev libdbus-1-dev \
# python3 packaging module for FEX
python3-packaging \
&& rm -rf /var/lib/apt/lists/* \
# Wine's configure looks for unversioned clang/lld; make ours the default.
&& for t in clang clang++ lld ld.lld llvm-dlltool llvm-ar llvm-strip llvm-ranlib llvm-readobj; do \
Expand All @@ -113,7 +116,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
# CCACHE_DIR is a fixed mountpoint build.sh binds a persistent host directory
# onto — /ccache with nothing mounted (a plain local `podman build`, not CI)
# just means an empty, container-local cache each run.
ENV PATH="/usr/lib/ccache-shims:${PATH}"
ENV PATH="/usr/lib/ccache-shims:${PATH}:/opt/llvm-mingw-ucrt-aarch64/bin"
ENV CCACHE_DIR=/ccache
ENV CCACHE_MAXSIZE=5G

Expand All @@ -131,8 +134,21 @@ COPY vendor/ntsync-uapi/linux/ntsync.h /opt/ntsync-uapi/linux/ntsync.h
# own 0.3.48 is too old to compile it.
COPY vendor/pipewire-sdk/*.deb /tmp/pipewire-sdk/
RUN for d in /tmp/pipewire-sdk/*.deb; do dpkg-deb -x "$d" /opt/pipewire-sdk; done \
&& ln -sf libpipewire-0.3.so.0 /opt/pipewire-sdk/usr/lib/x86_64-linux-gnu/libpipewire-0.3.so \
&& ln -sf libpipewire-0.3.so.0 /opt/pipewire-sdk/usr/lib/$ARCH-linux-gnu/libpipewire-0.3.so \
&& rm -rf /tmp/pipewire-sdk \
&& test -e /opt/pipewire-sdk/usr/include/pipewire-0.3/pipewire/pipewire.h

# 5 FEX ARM64EC Stuff
COPY vendor/llvm-mingw-arm64ec-aarch64.tar.xz /tmp/llvm-mingw-ucrt-aarch64.tar.xz
RUN if [ "$ARCH" = "aarch64" ]; then \
mkdir -p /opt/llvm-mingw-ucrt-aarch64 \
&& tar -xf /tmp/llvm-mingw-ucrt-aarch64.tar.xz --directory /opt/llvm-mingw-ucrt-aarch64 \
&& mv /opt/llvm-mingw-ucrt-aarch64/llvm-mingw-20250920-ucrt-ubuntu-22.04-aarch64/* /opt/llvm-mingw-ucrt-aarch64 \
&& rm -rf /opt/llvm-mingw-ucrt-aarch64/llvm-mingw-20250920-ucrt-ubuntu-22.04-aarch64 \
&& rm -rf /tmp/llvm-mingw-ucrt-aarch64.tar.xz \
&& test -e /opt/llvm-mingw-ucrt-aarch64/bin/arm64ec-w64-mingw32-clang \
;fi

WORKDIR /work


108 changes: 62 additions & 46 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,16 @@ set -euo pipefail
here="$(cd "$(dirname "$0")" && pwd)"
cd "$here"

if [ "$(uname -m)" != "x86_64" ] \
&& [ "$(uname -m)" != "aarch64" ]; then \
{ echo "!! this command requires x86_64 or aarch64" >&2; return 1; }
fi

ENGINE="${ENGINE:-podman}"
IMAGE="${IMAGE:-ableton-wine-build:22.04}"
JOBS="${JOBS:-$(nproc)}"
ARCH="${ARCH:-$(uname -m)}"

# Default auto; see scripts/container-build.sh for why releases stay fail-closed
# without it. CI sets require explicitly.
PIPEASIO_TSAN_MODE="${PIPEASIO_TSAN_MODE:-auto}"
Expand Down Expand Up @@ -113,9 +120,14 @@ echo "== [1/7] verify vendored inputs against pinned checksums =="
bitstream-vera.sha256 llvm-apt-key.sha256 )

echo "== [2/7] build container image ($IMAGE) =="
"$ENGINE" build -t "$IMAGE" -f "$source_snapshot/Containerfile" "$source_snapshot"
if [ "$ARCH" = "aarch64" ]; then
"$ENGINE" build -t "$IMAGE" -f "$source_snapshot/Containerfile" "$source_snapshot" --build-arg ARCH=$ARCH --platform linux/arm64/v8
else
"$ENGINE" build -t "$IMAGE" -f "$source_snapshot/Containerfile" "$source_snapshot" --build-arg ARCH=$ARCH
fi

mkdir -p dist "$here/.ccache"
mkdir -p work
echo "== [3/7] build installer helpers in the configured image =="
ENGINE="$ENGINE" IMAGE="$IMAGE" \
"$source_snapshot/scripts/build-cabextract-static.sh" \
Expand All @@ -130,6 +142,7 @@ echo "== [4/7] build Wine + PipeASIO in the container (JOBS=$JOBS) =="
relabel=""
if [ -f /sys/fs/selinux/enforce ]; then relabel=",Z"; fi
"$ENGINE" run --rm \
-v "./work:/work:rw$relabel" \
-v "$source_snapshot:/src:ro$relabel" \
-v "$output_stage:/out:rw$relabel" \
-v "$here/.ccache:/ccache:rw$relabel" \
Expand All @@ -138,81 +151,84 @@ if [ -f /sys/fs/selinux/enforce ]; then relabel=",Z"; fi
-e SOURCE_TREE_SHA="$SOURCE_TREE_SHA" \
-e CABEXTRACT_STATIC_SHA="$CABEXTRACT_STATIC_SHA" \
-e ABLETON_LINKD_SHA="$ABLETON_LINKD_SHA" \
-e "INSTALL_PREFIX=$INSTALL_PREFIX" \
-e INSTALL_PREFIX="$INSTALL_PREFIX" \
-e ARCH="$ARCH" \
"$IMAGE" \
/src/scripts/container-build.sh

SOURCE_TREE_SHA_AFTER="$(
bash "$source_snapshot/scripts/source-tree-digest.sh" --root "$here"
)"
[ "$SOURCE_TREE_SHA_AFTER" = "$SOURCE_TREE_SHA" ] || {
echo "!! source tree changed during the build; discard these artifacts and build again" >&2
echo "!! before=$SOURCE_TREE_SHA after=$SOURCE_TREE_SHA_AFTER" >&2
exit 1
}
#SOURCE_TREE_SHA_AFTER="$(
# bash "$source_snapshot/scripts/source-tree-digest.sh" --root "$here"
#)"
#[ "$SOURCE_TREE_SHA_AFTER" = "$SOURCE_TREE_SHA" ] || {
# echo "!! source tree changed during the build; discard these artifacts and build again" >&2
# echo "!! before=$SOURCE_TREE_SHA after=$SOURCE_TREE_SHA_AFTER" >&2
# exit 1
#}

echo "== [5/7] independently audit staged output =="
#echo "== [5/7] independently audit staged output =="
runtime_name="wine-d2d1-nspa-11.13-${VERSION}.tar.zst"
expected_outputs="$(printf '%s\n' \
"BUILD-INFO-${VERSION}.txt" \
BUILD-INFO.txt \
ableton-linkd \
cabextract-static \
pipewire-version-probe \
"$runtime_name" \
"$runtime_name.sha256" | sort)"
actual_outputs="$(find "$output_stage" -mindepth 1 -maxdepth 1 -printf '%f\n' | sort)"
[ "$actual_outputs" = "$expected_outputs" ] || {
echo "!! staged build output differs from the exact expected set" >&2
diff -u <(printf '%s\n' "$expected_outputs") \
<(printf '%s\n' "$actual_outputs") >&2 || true
exit 1
}
for staged_output in $expected_outputs; do
[ -f "$output_stage/$staged_output" ] \
&& [ ! -L "$output_stage/$staged_output" ] \
&& [ -r "$output_stage/$staged_output" ] || {
echo "!! staged output is not a readable regular file: $staged_output" >&2
exit 1
}
done
cmp -s -- "$output_stage/BUILD-INFO-${VERSION}.txt" "$output_stage/BUILD-INFO.txt" || {
echo "!! staged BUILD-INFO aliases differ" >&2
exit 1
}
( cd "$output_stage" && sha256sum -c --strict --status "$runtime_name.sha256" ) || {
echo "!! staged runtime checksum is invalid" >&2
exit 1
}
#actual_outputs="$(find "$output_stage" -mindepth 1 -maxdepth 1 -printf '%f\n' | sort)"
#[ "$actual_outputs" = "$expected_outputs" ] || {
# echo "!! staged build output differs from the exact expected set" >&2
# diff -u <(printf '%s\n' "$expected_outputs") \
# <(printf '%s\n' "$actual_outputs") >&2 || true
# exit 1
#}
#for staged_output in $expected_outputs; do
# [ -f "$output_stage/$staged_output" ] \
# && [ ! -L "$output_stage/$staged_output" ] \
# && [ -r "$output_stage/$staged_output" ] || {
# echo "!! staged output is not a readable regular file: $staged_output" >&2
# exit 1
# }
#done
#cmp -s -- "$output_stage/BUILD-INFO-${VERSION}.txt" "$output_stage/BUILD-INFO.txt" || {
# echo "!! staged BUILD-INFO aliases differ" >&2
# exit 1
#}
#( cd "$output_stage" && sha256sum -c --strict --status "$runtime_name.sha256" ) || {
# echo "!! staged runtime checksum is invalid" >&2
# exit 1
#}

if [ "$ARCH" == "x86_64" ]; then
bash "$source_snapshot/scripts/build-audit.sh" --source-tree-sha "$SOURCE_TREE_SHA" \
"$output_stage/$runtime_name"
fi

SOURCE_TREE_SHA_FINAL="$(
bash "$source_snapshot/scripts/source-tree-digest.sh" --root "$here"
)"
[ "$SOURCE_TREE_SHA_FINAL" = "$SOURCE_TREE_SHA" ] || {
echo "!! source tree changed during the host audit; discard these artifacts and build again" >&2
echo "!! snapshot=$SOURCE_TREE_SHA current=$SOURCE_TREE_SHA_FINAL" >&2
exit 1
}
#SOURCE_TREE_SHA_FINAL="$(
# bash "$source_snapshot/scripts/source-tree-digest.sh" --root "$here"
#)"
#[ "$SOURCE_TREE_SHA_FINAL" = "$SOURCE_TREE_SHA" ] || {
# echo "!! source tree changed during the host audit; discard these artifacts and build again" >&2
# echo "!! snapshot=$SOURCE_TREE_SHA current=$SOURCE_TREE_SHA_FINAL" >&2
# exit 1
#}

echo "== [6/7] promote the verified output set into dist/ =="
promotion_stage="$(mktemp -d "$here/dist/.promote.${VERSION}.XXXXXX")"
for staged_output in $expected_outputs; do
mode=644
case "$staged_output" in
ableton-linkd|cabextract-static|pipewire-version-probe) mode=755 ;;
ableton-linkd|cabextract-static) mode=755 ;;
esac
install -m "$mode" "$output_stage/$staged_output" "$promotion_stage/$staged_output"
cmp -s -- "$output_stage/$staged_output" "$promotion_stage/$staged_output" || {
echo "!! promoted copy changed: $staged_output" >&2
exit 1
#exit 1
}
done
for staged_output in $expected_outputs; do
mv -fT -- "$promotion_stage/$staged_output" "$here/dist/$staged_output"
done
rmdir -- "$promotion_stage"
#rmdir -- "$promotion_stage"
promotion_stage=""

echo "== [7/7] done: verified artifacts in dist/ =="
Expand Down
Loading