158 lines
5.2 KiB
Bash
Executable file
158 lines
5.2 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# Build qroissant wheels via Docker. Both Linux and Windows builds run inside
|
|
# the qroissant-build:latest image (defined in scripts/Dockerfile.build) so the
|
|
# host needs only Docker + Python.
|
|
#
|
|
# Usage:
|
|
# scripts/build.sh image Build the qroissant-build Docker image.
|
|
# scripts/build.sh linux Build a manylinux x86_64 wheel -> dist-linux/
|
|
# scripts/build.sh windows Build a win_amd64 wheel -> dist-windows/
|
|
# scripts/build.sh all image + linux + windows.
|
|
# scripts/build.sh check Install the latest linux wheel into .venv
|
|
# and import qroissant as a smoke test.
|
|
# scripts/build.sh clean Remove dist-*/ output dirs (volumes kept).
|
|
# scripts/build.sh clean-cache Also drop the Docker volumes (cargo
|
|
# registry, target dir, xwin SDK cache).
|
|
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)
|
|
ROOT_DIR=$(cd -- "$SCRIPT_DIR/.." &>/dev/null && pwd)
|
|
cd "$ROOT_DIR"
|
|
|
|
IMAGE=qroissant-build:latest
|
|
VOL_CARGO=qroissant-cargo-registry
|
|
VOL_TARGET=qroissant-target
|
|
VOL_XWIN=qroissant-xwin
|
|
|
|
need_docker() {
|
|
command -v docker >/dev/null 2>&1 || {
|
|
echo "error: docker is required but not on PATH" >&2
|
|
exit 1
|
|
}
|
|
}
|
|
|
|
ensure_volumes() {
|
|
local uid gid
|
|
uid=$(id -u); gid=$(id -g)
|
|
for v in "$VOL_CARGO" "$VOL_TARGET" "$VOL_XWIN"; do
|
|
if ! docker volume inspect "$v" >/dev/null 2>&1; then
|
|
docker volume create "$v" >/dev/null
|
|
fi
|
|
# Re-chown the volume to the invoking user every run; cheap and idempotent.
|
|
docker run --rm -v "$v":/v --entrypoint=sh "$IMAGE" -c "chown -R $uid:$gid /v" >/dev/null
|
|
done
|
|
}
|
|
|
|
ensure_image() {
|
|
if ! docker image inspect "$IMAGE" >/dev/null 2>&1; then
|
|
echo ">>> building $IMAGE"
|
|
docker build -t "$IMAGE" -f "$SCRIPT_DIR/Dockerfile.build" "$SCRIPT_DIR"
|
|
fi
|
|
}
|
|
|
|
run_in_image() {
|
|
# Run as the invoking user so produced wheels are owned by them, not root.
|
|
# CARGO_HOME / XDG_CACHE_HOME are redirected into the persistent volumes,
|
|
# which must therefore be owned by the same uid (handled by ensure_volumes).
|
|
docker run --rm \
|
|
--user "$(id -u):$(id -g)" \
|
|
-e CARGO_HOME=/cargo \
|
|
-e XDG_CACHE_HOME=/xdg-cache \
|
|
-e HOME=/tmp \
|
|
-e XWIN_ACCEPT_LICENSE=1 \
|
|
-v "$ROOT_DIR":/io -w /io \
|
|
-v "$VOL_CARGO":/cargo \
|
|
-v "$VOL_TARGET":/io/target \
|
|
-v "$VOL_XWIN":/xdg-cache/cargo-xwin \
|
|
--entrypoint=sh \
|
|
"$IMAGE" -c "$1"
|
|
}
|
|
|
|
cmd_image() {
|
|
need_docker
|
|
echo ">>> (re)building $IMAGE"
|
|
docker build -t "$IMAGE" -f "$SCRIPT_DIR/Dockerfile.build" "$SCRIPT_DIR"
|
|
}
|
|
|
|
cmd_linux() {
|
|
need_docker
|
|
ensure_image
|
|
ensure_volumes
|
|
echo ">>> building Linux wheel -> dist-linux/"
|
|
run_in_image 'maturin build --release --out /io/dist-linux'
|
|
ls -1 dist-linux/*.whl
|
|
}
|
|
|
|
cmd_windows() {
|
|
need_docker
|
|
ensure_image
|
|
ensure_volumes
|
|
echo ">>> building Windows wheel -> dist-windows/"
|
|
run_in_image '
|
|
maturin build --release --target x86_64-pc-windows-msvc --out /io/dist-windows
|
|
# Copy the PDB next to the wheel when one was produced (release profile
|
|
# has debug = "line-tables-only"). Place it next to _native.pyd at
|
|
# runtime on Windows to get resolved panic backtraces.
|
|
pdb=$(find /io/target/x86_64-pc-windows-msvc/release -maxdepth 2 -name "_native.pdb" 2>/dev/null | head -1)
|
|
if [ -n "$pdb" ]; then
|
|
cp "$pdb" /io/dist-windows/
|
|
echo "+ copied $(basename "$pdb") -> dist-windows/"
|
|
fi
|
|
'
|
|
ls -1 dist-windows/
|
|
}
|
|
|
|
cmd_check() {
|
|
local venv="$ROOT_DIR/.venv"
|
|
if [[ ! -x "$venv/bin/python" ]]; then
|
|
echo ">>> creating venv at $venv"
|
|
python3 -m venv "$venv"
|
|
"$venv/bin/pip" install --quiet --upgrade pip
|
|
fi
|
|
local wheel
|
|
wheel=$(ls -t dist-linux/qroissant-*-linux*.whl dist-linux/qroissant-*-manylinux*.whl 2>/dev/null | head -1 || true)
|
|
if [[ -z "$wheel" ]]; then
|
|
echo "error: no Linux wheel in dist-linux/; run '$0 linux' first" >&2
|
|
exit 1
|
|
fi
|
|
echo ">>> installing $wheel"
|
|
"$venv/bin/pip" install --quiet --force-reinstall "$wheel"
|
|
"$venv/bin/python" -c 'import qroissant; print("ok: qroissant", qroissant.__version__ if hasattr(qroissant, "__version__") else "(no __version__)")'
|
|
if [[ -f dist-windows/qroissant-*-win_amd64.whl ]] 2>/dev/null || ls dist-windows/qroissant-*-win_amd64.whl >/dev/null 2>&1; then
|
|
echo ">>> inspecting Windows wheel"
|
|
for w in dist-windows/qroissant-*-win_amd64.whl; do
|
|
python3 -m zipfile -l "$w" | grep -E '_native\.pyd|WHEEL' || true
|
|
done
|
|
fi
|
|
}
|
|
|
|
cmd_clean() {
|
|
rm -rf dist-linux dist-windows
|
|
echo ">>> removed dist-linux/ dist-windows/"
|
|
}
|
|
|
|
cmd_clean_cache() {
|
|
cmd_clean
|
|
for v in "$VOL_CARGO" "$VOL_TARGET" "$VOL_XWIN"; do
|
|
docker volume rm "$v" >/dev/null 2>&1 && echo ">>> removed volume $v" || true
|
|
done
|
|
}
|
|
|
|
case "${1:-}" in
|
|
image) cmd_image ;;
|
|
linux) cmd_linux ;;
|
|
windows) cmd_windows ;;
|
|
all) cmd_image; cmd_linux; cmd_windows ;;
|
|
check) cmd_check ;;
|
|
clean) cmd_clean ;;
|
|
clean-cache) cmd_clean_cache ;;
|
|
""|-h|--help)
|
|
sed -n '2,/^set -euo/p' "${BASH_SOURCE[0]}" | sed 's/^# \{0,1\}//' | sed '/^set -euo/d'
|
|
;;
|
|
*)
|
|
echo "error: unknown command: $1" >&2
|
|
echo "run '$0 --help' for usage" >&2
|
|
exit 2
|
|
;;
|
|
esac
|