680845cb1c
Linux build / Determine Swift version (push) Waiting to run
Linux build / Linux compile check (push) Blocked by required conditions
Build containerization / Verify commit signatures (push) Has been skipped
Build containerization / containerization (push) Successful in 0s
244 lines
9.9 KiB
Bash
Executable File
244 lines
9.9 KiB
Bash
Executable File
#!/bin/bash
|
|
# Copyright © 2026 Apple Inc. and the Containerization project authors.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# https://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
# Builds the x86_64 deployment tarball.
|
|
#
|
|
# Runs INSIDE the aarch64 Linux dev container (invoked by
|
|
# `make dist-x86_64` via the linux_run macro). Cross-compiles all four
|
|
# host-side binaries — cctl, vminitd, cloud-hypervisor, virtiofsd —
|
|
# to x86_64-linux-musl, packs an initfs.ext4 with the x86_64 guest
|
|
# binaries inside, and emits bin/containerization-x86_64-<sha>.tar.gz.
|
|
#
|
|
# See docs/x86_64-build.md for full documentation: prerequisites,
|
|
# pipeline stages, toolchain rationale, and troubleshooting.
|
|
#
|
|
# Force-rebuild env vars (default = skip stages whose outputs are
|
|
# up-to-date):
|
|
# REBUILD_VMINITD=1 vminitd + vmexec
|
|
# REBUILD_INITFS=1 initfs.ext4 (and the native aarch64 cctl packer)
|
|
# REBUILD_CH=1 cloud-hypervisor
|
|
# REBUILD_VIRTIOFSD=1 virtiofsd
|
|
# cctl x86 cross always rebuilds (Swift incremental handles no-ops).
|
|
|
|
set -euo pipefail
|
|
|
|
cd /workspace
|
|
|
|
GIT_SHA=$(git rev-parse --short HEAD 2>/dev/null || echo unknown)
|
|
DIST_NAME="containerization-x86_64-${GIT_SHA}"
|
|
DIST_DIR="bin/dist-x86_64"
|
|
STAGE="${DIST_DIR}/${DIST_NAME}"
|
|
TGZ="bin/${DIST_NAME}.tar.gz"
|
|
|
|
CROSS_PREFIX=/opt/cross-x86_64-musl
|
|
GNU_PREFIX=/opt/cross-x86_64-gnu
|
|
PATCH=/workspace/scripts/patches/virtiofsd-skip-cap-drop-with-sandbox-none.patch
|
|
|
|
# Cargo cross env for the musl stages (cctl, vminitd, cloud-hypervisor).
|
|
# CC/CXX/AR are used by cc-rs (Rust build scripts that compile C, e.g.
|
|
# zstd-sys, libseccomp-sys, capng) — points them at the Zig-backed
|
|
# wrappers. Linker is intentionally NOT set here: cargo-zigbuild
|
|
# installs its own linker wrapper that strips Rust's self-contained
|
|
# musl crt files (which would otherwise collide with Zig's musl crt).
|
|
# Setting CARGO_TARGET_*_LINKER ourselves would override that and
|
|
# cause duplicate-symbol link errors.
|
|
# pkg-config (used by libseccomp-sys and libcap-ng's capng-sys) points
|
|
# at the static-musl prefix, not the aarch64 host.
|
|
# PKG_CONFIG_ALL_STATIC=1 makes pkg-config-rs emit
|
|
# `rustc-link-lib=static=...` for resolved libs — required because
|
|
# the C libs at $CROSS_PREFIX are static-only (.a, no .so), so the
|
|
# default dynamic link would fail to find the .so.
|
|
#
|
|
# virtiofsd has its own glibc-dynamic env block below; it overrides
|
|
# PKG_CONFIG_LIBDIR / SYSROOT_DIR in a subshell so the musl values
|
|
# stay correct for cloud-hypervisor.
|
|
. /root/.cargo/env
|
|
export CC_x86_64_unknown_linux_musl=x86_64-linux-musl-gcc
|
|
export CXX_x86_64_unknown_linux_musl=x86_64-linux-musl-g++
|
|
export AR_x86_64_unknown_linux_musl=x86_64-linux-musl-ar
|
|
export PKG_CONFIG_LIBDIR="${CROSS_PREFIX}/lib/pkgconfig"
|
|
export PKG_CONFIG_SYSROOT_DIR="${CROSS_PREFIX}"
|
|
export PKG_CONFIG_ALLOW_CROSS=1
|
|
# Add the static-musl cross prefix to rustc's native library search
|
|
# path so the linker finds the libseccomp.so / libcap-ng.so linker
|
|
# scripts that build-musl-x86_64-deps.sh installs alongside the .a
|
|
# files. The scripts redirect resolution to the static archives.
|
|
export CARGO_TARGET_X86_64_UNKNOWN_LINUX_MUSL_RUSTFLAGS="-L native=${CROSS_PREFIX}/lib"
|
|
|
|
# Pre-flight checks
|
|
[ -f .local/cloud-hypervisor/Cargo.toml ] || {
|
|
echo "ERROR: missing .local/cloud-hypervisor source checkout." >&2
|
|
echo " git clone -b v52.0 https://github.com/cloud-hypervisor/cloud-hypervisor .local/cloud-hypervisor" >&2
|
|
exit 1
|
|
}
|
|
[ -f .local/virtiofsd/Cargo.toml ] || {
|
|
echo "ERROR: missing .local/virtiofsd source checkout." >&2
|
|
echo " git clone https://gitlab.com/virtio-fs/virtiofsd .local/virtiofsd" >&2
|
|
exit 1
|
|
}
|
|
|
|
# Kernel candidates (prefer the compressed bzImage produced by
|
|
# `make -C kernel TARGET_ARCH=x86_64`, fall back to an uncompressed
|
|
# vmlinux). The kernel is required — a tarball without one isn't
|
|
# usable, so fail hard rather than silently producing one.
|
|
KERNEL_SRC=
|
|
for candidate in kernel/vmlinuz-x86_64 kernel/vmlinux-x86_64; do
|
|
if [ -f "$candidate" ]; then
|
|
if file "$candidate" | grep -qE 'x86 boot|x86-64'; then
|
|
KERNEL_SRC=$candidate
|
|
break
|
|
else
|
|
echo "ERROR: $candidate exists but is not x86_64." >&2
|
|
file "$candidate" >&2
|
|
exit 1
|
|
fi
|
|
fi
|
|
done
|
|
if [ -z "${KERNEL_SRC}" ]; then
|
|
echo "ERROR: no x86_64 kernel found at kernel/vmlinuz-x86_64 or kernel/vmlinux-x86_64." >&2
|
|
echo " build one with 'make -C kernel TARGET_ARCH=x86_64'." >&2
|
|
exit 1
|
|
fi
|
|
|
|
mkdir -p "${DIST_DIR}"
|
|
|
|
# Decide which steps need to run before doing any work, so log messages
|
|
# match what's actually happening.
|
|
|
|
NEED_VMINITD=1
|
|
if [ "${REBUILD_VMINITD:-0}" != "1" ] \
|
|
&& [ -x "${DIST_DIR}/vminitd" ] && [ -x "${DIST_DIR}/vmexec" ] \
|
|
&& [ -z "$(find vminitd/Sources vminitd/Package.swift Sources/Containerization/SandboxContext \
|
|
-newer "${DIST_DIR}/vminitd" -print -quit 2>/dev/null)" ] \
|
|
&& [ -z "$(find vminitd/Sources vminitd/Package.swift Sources/Containerization/SandboxContext \
|
|
-newer "${DIST_DIR}/vmexec" -print -quit 2>/dev/null)" ]; then
|
|
NEED_VMINITD=0
|
|
fi
|
|
|
|
NEED_INITFS=1
|
|
if [ "${REBUILD_INITFS:-0}" != "1" ] \
|
|
&& [ "${NEED_VMINITD}" = "0" ] \
|
|
&& [ -f "${DIST_DIR}/initfs.ext4" ] \
|
|
&& [ "${DIST_DIR}/initfs.ext4" -nt "${DIST_DIR}/vminitd" ] \
|
|
&& [ "${DIST_DIR}/initfs.ext4" -nt "${DIST_DIR}/vmexec" ]; then
|
|
NEED_INITFS=0
|
|
fi
|
|
|
|
NEED_CH=1
|
|
if [ "${REBUILD_CH:-0}" != "1" ] && [ -x "${DIST_DIR}/cloud-hypervisor" ]; then
|
|
NEED_CH=0
|
|
fi
|
|
|
|
NEED_VIRTIOFSD=1
|
|
if [ "${REBUILD_VIRTIOFSD:-0}" != "1" ] && [ -x "${DIST_DIR}/virtiofsd" ]; then
|
|
NEED_VIRTIOFSD=0
|
|
fi
|
|
|
|
echo "==> Cross-compiling cctl to x86_64-linux-musl"
|
|
swift build -c release \
|
|
--swift-sdk x86_64-swift-linux-musl \
|
|
--product cctl \
|
|
-Xswiftc -warnings-as-errors \
|
|
-Xlinker -L"${CROSS_PREFIX}/lib" \
|
|
--disable-automatic-resolution
|
|
CCTL_X86_64_BIN="$(swift build -c release --swift-sdk x86_64-swift-linux-musl --show-bin-path)/cctl"
|
|
install -m 755 "${CCTL_X86_64_BIN}" "${DIST_DIR}/cctl"
|
|
|
|
if [ "${NEED_VMINITD}" = "1" ]; then
|
|
echo "==> Cross-compiling vminitd + vmexec to x86_64-linux-musl"
|
|
make -C vminitd \
|
|
LIBC=musl \
|
|
MUSL_ARCH=x86_64 \
|
|
BUILD_CONFIGURATION=release \
|
|
INSTALL_DIR="$(pwd)/${DIST_DIR}"
|
|
else
|
|
echo "==> Reusing staged vminitd + vmexec (sources unchanged; set REBUILD_VMINITD=1 to force)"
|
|
fi
|
|
|
|
if [ "${NEED_CH}" = "1" ]; then
|
|
echo "==> Cross-compiling cloud-hypervisor to x86_64-unknown-linux-musl"
|
|
(
|
|
cd .local/cloud-hypervisor
|
|
cargo zigbuild --release --target x86_64-unknown-linux-musl --bin cloud-hypervisor
|
|
)
|
|
install -m 755 \
|
|
".local/cloud-hypervisor/target/x86_64-unknown-linux-musl/release/cloud-hypervisor" \
|
|
"${DIST_DIR}/cloud-hypervisor"
|
|
else
|
|
echo "==> Reusing staged cloud-hypervisor (set REBUILD_CH=1 to force)"
|
|
fi
|
|
|
|
if [ "${NEED_VIRTIOFSD}" = "1" ]; then
|
|
echo "==> Cross-compiling virtiofsd to x86_64-unknown-linux-gnu.2.35 (glibc-dynamic, with cap-drop patch)"
|
|
# virtiofsd ships glibc-dynamic: the deployment host provides
|
|
# libseccomp.so.2 and libcap-ng.so.0 at runtime. Subshell scopes
|
|
# the gnu env so it doesn't bleed into other stages.
|
|
(
|
|
export CC_x86_64_unknown_linux_gnu=x86_64-linux-gnu-gcc
|
|
export CXX_x86_64_unknown_linux_gnu=x86_64-linux-gnu-g++
|
|
export AR_x86_64_unknown_linux_gnu=x86_64-linux-gnu-ar
|
|
export PKG_CONFIG_LIBDIR="${GNU_PREFIX}/lib/pkgconfig"
|
|
export PKG_CONFIG_SYSROOT_DIR="${GNU_PREFIX}"
|
|
export CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUSTFLAGS="-L native=${GNU_PREFIX}/lib"
|
|
cd .local/virtiofsd
|
|
if git apply --check "${PATCH}" 2>/dev/null; then
|
|
git apply "${PATCH}"
|
|
echo "applied virtiofsd cap-drop patch"
|
|
elif git apply --reverse --check "${PATCH}" 2>/dev/null; then
|
|
echo "virtiofsd cap-drop patch already applied"
|
|
else
|
|
echo "ERROR: virtiofsd cap-drop patch does not apply cleanly" >&2
|
|
exit 1
|
|
fi
|
|
cargo zigbuild --release --target x86_64-unknown-linux-gnu.2.35
|
|
)
|
|
install -m 755 \
|
|
".local/virtiofsd/target/x86_64-unknown-linux-gnu/release/virtiofsd" \
|
|
"${DIST_DIR}/virtiofsd"
|
|
else
|
|
echo "==> Reusing staged virtiofsd (set REBUILD_VIRTIOFSD=1 to force)"
|
|
fi
|
|
|
|
if [ "${NEED_INITFS}" = "1" ]; then
|
|
echo "==> Building aarch64 cctl natively (used to pack initfs.ext4)"
|
|
swift build -c release --product cctl -Xswiftc -warnings-as-errors --disable-automatic-resolution
|
|
NATIVE_CCTL="$(swift build -c release --show-bin-path)/cctl"
|
|
|
|
echo "==> Building initfs.ext4 with x86_64 guest binaries"
|
|
rm -f "${DIST_DIR}/init.rootfs.tar.gz" "${DIST_DIR}/initfs.ext4"
|
|
"${NATIVE_CCTL}" rootfs create \
|
|
--vminitd "${DIST_DIR}/vminitd" \
|
|
--vmexec "${DIST_DIR}/vmexec" \
|
|
--ext4 "${DIST_DIR}/initfs.ext4" \
|
|
--label org.opencontainers.image.source=https://github.com/apple/containerization \
|
|
--image vminit-x86_64:latest \
|
|
"${DIST_DIR}/init.rootfs.tar.gz"
|
|
else
|
|
echo "==> Reusing staged initfs.ext4 (vminitd/vmexec unchanged; set REBUILD_INITFS=1 to force)"
|
|
fi
|
|
|
|
echo "==> Staging tree at ${STAGE} and packaging"
|
|
rm -rf "${STAGE}"
|
|
mkdir -p "${STAGE}/bin"
|
|
install -m 755 "${DIST_DIR}/cctl" "${STAGE}/bin/cctl"
|
|
install -m 755 "${DIST_DIR}/cloud-hypervisor" "${STAGE}/bin/cloud-hypervisor"
|
|
install -m 755 "${DIST_DIR}/virtiofsd" "${STAGE}/bin/virtiofsd"
|
|
mkdir -p "${STAGE}/kernel"
|
|
cp "${KERNEL_SRC}" "${STAGE}/kernel/$(basename "${KERNEL_SRC}")"
|
|
cp "${DIST_DIR}/initfs.ext4" "${STAGE}/initfs.ext4"
|
|
rm -f "${TGZ}"
|
|
tar -czf "${TGZ}" -C "${DIST_DIR}" "${DIST_NAME}"
|
|
echo "wrote ${TGZ}"
|