234 lines
7.5 KiB
Bash
Executable File
234 lines
7.5 KiB
Bash
Executable File
#!/bin/sh
|
|
set -eu
|
|
PATH=/usr/bin:/bin:/usr/sbin:/sbin
|
|
export PATH
|
|
|
|
usage() {
|
|
echo "usage: $0 --output ABSOLUTE_DIR --target-dir ABSOLUTE_DIR" >&2
|
|
exit 2
|
|
}
|
|
|
|
output=
|
|
target_dir=
|
|
while test "$#" -gt 0; do
|
|
case "$1" in
|
|
--output)
|
|
test "$#" -ge 2 || usage
|
|
output=$2
|
|
shift 2
|
|
;;
|
|
--target-dir)
|
|
test "$#" -ge 2 || usage
|
|
target_dir=$2
|
|
shift 2
|
|
;;
|
|
*) usage ;;
|
|
esac
|
|
done
|
|
|
|
test -n "$output" || usage
|
|
test -n "$target_dir" || usage
|
|
ROOT=$(CDPATH= cd -P -- "$(dirname "$0")/../.." && pwd -P)
|
|
CORE="$ROOT/core"
|
|
|
|
resolve_new_path() {
|
|
requested=$1
|
|
label=$2
|
|
case "$requested" in
|
|
/*) ;;
|
|
*) usage ;;
|
|
esac
|
|
if test -e "$requested" || test -L "$requested"; then
|
|
echo "$label must not exist: $requested" >&2
|
|
exit 2
|
|
fi
|
|
parent=$(dirname -- "$requested")
|
|
name=$(basename -- "$requested")
|
|
case "$name" in
|
|
''|.|..) usage ;;
|
|
esac
|
|
physical_parent=$(CDPATH= cd -P -- "$parent" 2>/dev/null && pwd -P) || {
|
|
echo "$label parent must already exist: $parent" >&2
|
|
exit 2
|
|
}
|
|
candidate="$physical_parent/$name"
|
|
case "$candidate" in
|
|
"$ROOT"|"$ROOT"/*)
|
|
echo "$label must be outside the repository: $requested" >&2
|
|
exit 2
|
|
;;
|
|
esac
|
|
printf '%s\n' "$candidate"
|
|
}
|
|
|
|
output=$(resolve_new_path "$output" output)
|
|
target_dir=$(resolve_new_path "$target_dir" "target directory")
|
|
case "$output/:$target_dir/" in
|
|
"$target_dir/"*:*|*:"$output/"*)
|
|
echo "output and target directory must be separate" >&2
|
|
exit 2
|
|
;;
|
|
esac
|
|
|
|
mkdir "$output"
|
|
if ! mkdir "$target_dir"; then
|
|
rmdir "$output"
|
|
exit 2
|
|
fi
|
|
output=$(CDPATH= cd -P -- "$output" && pwd -P)
|
|
target_dir=$(CDPATH= cd -P -- "$target_dir" && pwd -P)
|
|
for reserved_path in "$output" "$target_dir"; do
|
|
case "$reserved_path" in
|
|
"$ROOT"|"$ROOT"/*)
|
|
echo "reserved packaging path resolved inside the repository: $reserved_path" >&2
|
|
exit 2
|
|
;;
|
|
esac
|
|
done
|
|
case "$output/:$target_dir/" in
|
|
"$target_dir/"*:*|*:"$output/"*)
|
|
echo "reserved output and target directory must be separate" >&2
|
|
exit 2
|
|
;;
|
|
esac
|
|
|
|
test "$(/usr/bin/uname -s)" = Darwin || {
|
|
echo "XCFramework packaging requires macOS" >&2
|
|
exit 2
|
|
}
|
|
test "$(/usr/bin/uname -m)" = arm64 || {
|
|
echo "XCFramework packaging requires an arm64 host" >&2
|
|
exit 2
|
|
}
|
|
|
|
user_record=$(/usr/bin/dscacheutil -q user -a name "$(/usr/bin/id -un)")
|
|
trusted_home=$(printf '%s\n' "$user_record" | awk '$1 == "dir:" { print $2; exit }')
|
|
rustup="$trusted_home/.cargo/bin/rustup"
|
|
test -x "$rustup" || {
|
|
echo "rustup not found at trusted user path" >&2
|
|
exit 2
|
|
}
|
|
cargo_bin=$(/usr/bin/env -i \
|
|
HOME="$trusted_home" \
|
|
PATH="$PATH" \
|
|
RUSTUP_HOME="$trusted_home/.rustup" \
|
|
"$rustup" which --toolchain 1.97.1 cargo)
|
|
rustc_bin=$(/usr/bin/env -i \
|
|
HOME="$trusted_home" \
|
|
PATH="$PATH" \
|
|
RUSTUP_HOME="$trusted_home/.rustup" \
|
|
"$rustup" which --toolchain 1.97.1 rustc)
|
|
rustc_version=$(/usr/bin/env -i HOME="$trusted_home" PATH="$PATH" "$rustc_bin" --version)
|
|
cargo_version=$(/usr/bin/env -i HOME="$trusted_home" PATH="$PATH" "$cargo_bin" --version)
|
|
test "$rustc_version" = 'rustc 1.97.1 (8bab26f4f 2026-07-14)' || {
|
|
echo "unexpected rustc identity: $rustc_version" >&2
|
|
exit 2
|
|
}
|
|
test "$cargo_version" = 'cargo 1.97.1 (c980f4866 2026-06-30)' || {
|
|
echo "unexpected cargo identity: $cargo_version" >&2
|
|
exit 2
|
|
}
|
|
xcodebuild=$(/usr/bin/env -i PATH="$PATH" /usr/bin/xcrun --find xcodebuild)
|
|
xcode_version=$(/usr/bin/env -i HOME="$trusted_home" PATH="$PATH" "$xcodebuild" -version)
|
|
test "$xcode_version" = 'Xcode 26.6
|
|
Build version 17F113' || {
|
|
echo "unexpected Xcode identity: $xcode_version" >&2
|
|
exit 2
|
|
}
|
|
clang=$(/usr/bin/env -i PATH="$PATH" /usr/bin/xcrun --find clang)
|
|
ar=$(/usr/bin/env -i PATH="$PATH" /usr/bin/xcrun --find ar)
|
|
clang_identity=$(/usr/bin/env -i HOME="$trusted_home" PATH="$PATH" "$clang" --version)
|
|
clang_version=$(printf '%s\n' "$clang_identity" | sed -n '1p')
|
|
sdk=$(/usr/bin/env -i PATH="$PATH" /usr/bin/xcrun --sdk macosx --show-sdk-path)
|
|
|
|
config_dir=$CORE
|
|
while :; do
|
|
if test -e "$config_dir/.cargo/config" || test -e "$config_dir/.cargo/config.toml"; then
|
|
echo "Cargo config is not permitted in the packaging path: $config_dir/.cargo" >&2
|
|
exit 2
|
|
fi
|
|
test "$config_dir" = / && break
|
|
config_dir=$(dirname "$config_dir")
|
|
done
|
|
|
|
source_commit=$(/usr/bin/env -i HOME="$trusted_home" PATH="$PATH" \
|
|
/usr/bin/git -C "$ROOT" rev-parse HEAD)
|
|
source_epoch=$(/usr/bin/env -i HOME="$trusted_home" PATH="$PATH" \
|
|
/usr/bin/git -C "$ROOT" show -s --format=%ct HEAD)
|
|
rustflags="--remap-path-prefix=$ROOT=. --remap-path-prefix=$target_dir=/cargo-target"
|
|
cflags="-fdebug-prefix-map=$ROOT=. -ffile-prefix-map=$ROOT=. -fdebug-prefix-map=$target_dir=/cargo-target -ffile-prefix-map=$target_dir=/cargo-target"
|
|
cargo_home="$target_dir/cargo-home"
|
|
build_tmp="$target_dir/tmp"
|
|
mkdir "$cargo_home" "$build_tmp"
|
|
for cache in registry git; do
|
|
if test -e "$trusted_home/.cargo/$cache"; then
|
|
ln -s "$trusted_home/.cargo/$cache" "$cargo_home/$cache"
|
|
fi
|
|
done
|
|
(
|
|
cd "$CORE"
|
|
/usr/bin/env -i \
|
|
AR="$ar" \
|
|
AR_aarch64_apple_darwin="$ar" \
|
|
CARGO_HOME="$cargo_home" \
|
|
CARGO_INCREMENTAL=0 \
|
|
CARGO_PROFILE_RELEASE_CODEGEN_UNITS=1 \
|
|
CARGO_PROFILE_RELEASE_INCREMENTAL=false \
|
|
CARGO_PROFILE_RELEASE_LTO=fat \
|
|
CARGO_PROFILE_RELEASE_PANIC=abort \
|
|
CARGO_TARGET_AARCH64_APPLE_DARWIN_LINKER="$clang" \
|
|
CARGO_TARGET_DIR="$target_dir" \
|
|
CC="$clang" \
|
|
CC_aarch64_apple_darwin="$clang" \
|
|
CFLAGS="$cflags" \
|
|
CFLAGS_aarch64_apple_darwin="$cflags" \
|
|
HOME="$trusted_home" \
|
|
MACOSX_DEPLOYMENT_TARGET=14.0 \
|
|
PATH="$PATH" \
|
|
RUSTC="$rustc_bin" \
|
|
RUSTFLAGS="$rustflags" \
|
|
SDKROOT="$sdk" \
|
|
SOURCE_DATE_EPOCH="$source_epoch" \
|
|
TMPDIR="$build_tmp" \
|
|
ZERO_AR_DATE=1 \
|
|
"$cargo_bin" build \
|
|
--target aarch64-apple-darwin \
|
|
--release \
|
|
--frozen
|
|
)
|
|
|
|
headers="$target_dir/xcframework-headers"
|
|
mkdir -p "$headers" "$output"
|
|
cp "$ROOT/core/include/versevdi_core.h" "$headers/"
|
|
cp "$ROOT/core/include/module.modulemap" "$headers/"
|
|
|
|
/usr/bin/env -i \
|
|
HOME="$trusted_home" \
|
|
PATH="$PATH" \
|
|
TMPDIR="$build_tmp" \
|
|
"$xcodebuild" -create-xcframework \
|
|
-library "$target_dir/aarch64-apple-darwin/release/libversevdi_core.a" \
|
|
-headers "$headers" \
|
|
-output "$output/VerseVDICore.xcframework"
|
|
|
|
timestamp=$(date -r "$source_epoch" +%Y%m%d%H%M.%S)
|
|
find "$output/VerseVDICore.xcframework" -exec touch -h -t "$timestamp" {} +
|
|
|
|
{
|
|
printf 'rustc=%s\n' "$rustc_version"
|
|
printf 'cargo=%s\n' "$cargo_version"
|
|
printf 'cargo_path=%s\n' "$cargo_bin"
|
|
printf 'rustc_path=%s\n' "$rustc_bin"
|
|
printf 'xcode=%s\n' "$xcode_version"
|
|
printf 'clang=%s\n' "$clang_version"
|
|
printf 'sdk=%s\n' "$sdk"
|
|
printf 'cargo_config=isolated-home-and-no-project-config\n'
|
|
printf 'target=aarch64-apple-darwin\n'
|
|
printf 'deployment_target=14.0\n'
|
|
printf 'source_commit=%s\n' "$source_commit"
|
|
printf 'source_epoch=%s\n' "$source_epoch"
|
|
printf 'rustflags=--remap-path-prefix=<repository>=. --remap-path-prefix=<target>=/cargo-target\n'
|
|
printf 'cflags=-fdebug-prefix-map/-ffile-prefix-map for <repository> and <target>\n'
|
|
} >"$output/build-environment.txt"
|
|
touch -t "$timestamp" "$output/build-environment.txt" "$output"
|