feat: add cross-platform & cross-architecture build script
This commit is contained in:
443
build.sh
Executable file
443
build.sh
Executable file
@@ -0,0 +1,443 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
CYAN='\033[0;36m'
|
||||||
|
NC='\033[0m'
|
||||||
|
|
||||||
|
info() { echo -e "${GREEN}[INFO]${NC} $*"; }
|
||||||
|
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
|
||||||
|
error() { echo -e "${RED}[ERROR]${NC} $*"; exit 1; }
|
||||||
|
|
||||||
|
USAGE="
|
||||||
|
Usage: $(basename "$0") [OPTIONS]
|
||||||
|
|
||||||
|
Cross-platform & cross-architecture build script for AirDisplay Client (Tauri)
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-p, --platform TARGET Target platform: macos, windows, linux, all (default: current OS)
|
||||||
|
-a, --arch ARCH Target architecture: x64, arm64, armhf, universal (default: current arch)
|
||||||
|
-t, --tool TOOL Cross-compile toolchain: cross, xwin, cargo (default: auto-detect)
|
||||||
|
-r, --release Build in release mode (default)
|
||||||
|
-d, --debug Build in debug mode
|
||||||
|
-c, --clean Clean before building
|
||||||
|
-l, --list List supported platform/arch combinations
|
||||||
|
-h, --help Show this help message
|
||||||
|
|
||||||
|
Supported targets:
|
||||||
|
macos x64, arm64, universal
|
||||||
|
windows x64, arm64
|
||||||
|
linux x64, arm64, armhf
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
$(basename "$0") Build for current platform & arch
|
||||||
|
$(basename "$0") -p macos -a universal Universal macOS binary (x64+arm64)
|
||||||
|
$(basename "$0") -p linux -a arm64 Linux ARM64 (e.g. Raspberry Pi 5)
|
||||||
|
$(basename "$0") -p linux -a armhf Linux ARM32 hard-float
|
||||||
|
$(basename "$0") -p windows -a arm64 Windows ARM64
|
||||||
|
$(basename "$0") -p all Build for all platform+arch combos
|
||||||
|
$(basename "$0") -p macos -a arm64 -t cross Force use cross toolchain
|
||||||
|
$(basename "$0") -c -p linux -a arm64 Clean + build Linux ARM64
|
||||||
|
"
|
||||||
|
|
||||||
|
BUILD_TYPE="release"
|
||||||
|
CLEAN=false
|
||||||
|
LIST=false
|
||||||
|
TOOLCHAIN=""
|
||||||
|
PLATFORM=""
|
||||||
|
ARCH=""
|
||||||
|
|
||||||
|
detect_current_platform() {
|
||||||
|
case "$(uname -s)" in
|
||||||
|
Darwin) echo "macos" ;;
|
||||||
|
Linux) echo "linux" ;;
|
||||||
|
MINGW*|MSYS*|CYGWIN*) echo "windows" ;;
|
||||||
|
*) error "Unsupported OS: $(uname -s)" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
detect_current_arch() {
|
||||||
|
case "$(uname -m)" in
|
||||||
|
x86_64|amd64) echo "x64" ;;
|
||||||
|
arm64|aarch64) echo "arm64" ;;
|
||||||
|
armv7l|armv7) echo "armhf" ;;
|
||||||
|
*) echo "x64" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
CURRENT_PLATFORM=$(detect_current_platform)
|
||||||
|
CURRENT_ARCH=$(detect_current_arch)
|
||||||
|
PLATFORM="${CURRENT_PLATFORM}"
|
||||||
|
ARCH="${CURRENT_ARCH}"
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
-p|--platform) PLATFORM="$2"; shift 2 ;;
|
||||||
|
-a|--arch) ARCH="$2"; shift 2 ;;
|
||||||
|
-t|--tool) TOOLCHAIN="$2"; shift 2 ;;
|
||||||
|
-r|--release) BUILD_TYPE="release"; shift ;;
|
||||||
|
-d|--debug) BUILD_TYPE="debug"; shift ;;
|
||||||
|
-c|--clean) CLEAN=true; shift ;;
|
||||||
|
-l|--list) LIST=true; shift ;;
|
||||||
|
-h|--help) echo "$USAGE"; exit 0 ;;
|
||||||
|
*) error "Unknown option: $1\n$USAGE" ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
VALID_ARCHS_MACOS="x64 arm64 universal"
|
||||||
|
VALID_ARCHS_WINDOWS="x64 arm64"
|
||||||
|
VALID_ARCHS_LINUX="x64 arm64 armhf"
|
||||||
|
|
||||||
|
validate_arch() {
|
||||||
|
local platform="$1" arch="$2"
|
||||||
|
case "$platform" in
|
||||||
|
macos) echo "$VALID_ARCHS_MACOS" | grep -qw "$arch" || error "macos does not support arch '$arch'. Valid: $VALID_ARCHS_MACOS" ;;
|
||||||
|
windows) echo "$VALID_ARCHS_WINDOWS" | grep -qw "$arch" || error "windows does not support arch '$arch'. Valid: $VALID_ARCHS_WINDOWS" ;;
|
||||||
|
linux) echo "$VALID_ARCHS_LINUX" | grep -qw "$arch" || error "linux does not support arch '$arch'. Valid: $VALID_ARCHS_LINUX" ;;
|
||||||
|
*) error "Unknown platform: $platform" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ "$LIST" == true ]]; then
|
||||||
|
echo -e "${CYAN}Supported platform/arch combinations:${NC}"
|
||||||
|
echo ""
|
||||||
|
printf " %-10s %s\n" "macos" "$VALID_ARCHS_MACOS"
|
||||||
|
printf " %-10s %s\n" "windows" "$VALID_ARCHS_WINDOWS"
|
||||||
|
printf " %-10s %s\n" "linux" "$VALID_ARCHS_LINUX"
|
||||||
|
echo ""
|
||||||
|
echo -e "${CYAN}Rust targets mapping:${NC}"
|
||||||
|
echo ""
|
||||||
|
printf " %-20s %-30s %s\n" "PLATFORM/ARCH" "RUST TARGET" "NOTES"
|
||||||
|
printf " %-20s %-30s %s\n" "macos/x64" "x86_64-apple-darwin" ""
|
||||||
|
printf " %-20s %-30s %s\n" "macos/arm64" "aarch64-apple-darwin" "Apple Silicon"
|
||||||
|
printf " %-20s %-30s %s\n" "macos/universal" "x86_64+aarch64-apple-darwin" "Merged fat binary"
|
||||||
|
printf " %-20s %-30s %s\n" "windows/x64" "x86_64-pc-windows-msvc" ""
|
||||||
|
printf " %-20s %-30s %s\n" "windows/arm64" "aarch64-pc-windows-msvc" "ARM64 devices"
|
||||||
|
printf " %-20s %-30s %s\n" "linux/x64" "x86_64-unknown-linux-gnu" ""
|
||||||
|
printf " %-20s %-30s %s\n" "linux/arm64" "aarch64-unknown-linux-gnu" "RPi 5, AWS Graviton, etc."
|
||||||
|
printf " %-20s %-30s %s\n" "linux/armhf" "armv7-unknown-linux-gnueabihf" "RPi 3/4, 32-bit ARM"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
validate_arch "$PLATFORM" "$ARCH"
|
||||||
|
|
||||||
|
rust_target_for() {
|
||||||
|
local platform="$1" arch="$2"
|
||||||
|
case "$platform/$arch" in
|
||||||
|
macos/x64) echo "x86_64-apple-darwin" ;;
|
||||||
|
macos/arm64) echo "aarch64-apple-darwin" ;;
|
||||||
|
macos/universal) echo "universal-apple-darwin" ;;
|
||||||
|
windows/x64) echo "x86_64-pc-windows-msvc" ;;
|
||||||
|
windows/arm64) echo "aarch64-pc-windows-msvc" ;;
|
||||||
|
linux/x64) echo "x86_64-unknown-linux-gnu" ;;
|
||||||
|
linux/arm64) echo "aarch64-unknown-linux-gnu" ;;
|
||||||
|
linux/armhf) echo "armv7-unknown-linux-gnueabihf" ;;
|
||||||
|
*) error "Unsupported combination: $platform/$arch" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
needs_cross_tool() {
|
||||||
|
local platform="$1" arch="$2"
|
||||||
|
local target
|
||||||
|
target=$(rust_target_for "$platform" "$arch")
|
||||||
|
|
||||||
|
if [[ "$platform" != "$CURRENT_PLATFORM" ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$CURRENT_PLATFORM/$CURRENT_ARCH" in
|
||||||
|
macos/x64)
|
||||||
|
[[ "$arch" == "arm64" ]] && return 0
|
||||||
|
;;
|
||||||
|
macos/arm64)
|
||||||
|
[[ "$arch" == "x64" ]] && return 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
local current_rust_arch
|
||||||
|
current_rust_arch=$(rust_target_for "$CURRENT_PLATFORM" "$CURRENT_ARCH")
|
||||||
|
[[ "$target" != "$current_rust_arch" ]] && return 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
detect_toolchain() {
|
||||||
|
local platform="$1" arch="$2"
|
||||||
|
|
||||||
|
if [[ -n "$TOOLCHAIN" ]]; then
|
||||||
|
echo "$TOOLCHAIN"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! needs_cross_tool "$platform" "$arch"; then
|
||||||
|
echo "native"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$platform" in
|
||||||
|
windows)
|
||||||
|
if command -v cargo-xwin &>/dev/null; then
|
||||||
|
echo "xwin"
|
||||||
|
else
|
||||||
|
echo "cross"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
linux)
|
||||||
|
if command -v cross &>/dev/null; then
|
||||||
|
echo "cross"
|
||||||
|
elif command -v cargo-zigbuild &>/dev/null; then
|
||||||
|
echo "zigbuild"
|
||||||
|
else
|
||||||
|
echo "cross"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
macos)
|
||||||
|
if [[ "$arch" == "universal" ]]; then
|
||||||
|
echo "native"
|
||||||
|
else
|
||||||
|
echo "native"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "cross"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
check_command() {
|
||||||
|
if ! command -v "$1" &>/dev/null; then
|
||||||
|
error "$1 is not installed. Please install it first."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
check_node_deps() {
|
||||||
|
if [[ ! -d "node_modules" ]]; then
|
||||||
|
info "Installing Node.js dependencies..."
|
||||||
|
npm install
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
check_rust_target() {
|
||||||
|
local target="$1"
|
||||||
|
if [[ "$target" == *"universal"* ]]; then
|
||||||
|
check_rust_target "x86_64-apple-darwin"
|
||||||
|
check_rust_target "aarch64-apple-darwin"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
if ! rustup target list --installed | grep -q "$target"; then
|
||||||
|
info "Installing Rust target: $target"
|
||||||
|
rustup target add "$target"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
install_cross_tools() {
|
||||||
|
local toolchain="$1"
|
||||||
|
|
||||||
|
case "$toolchain" in
|
||||||
|
cross)
|
||||||
|
if ! command -v cross &>/dev/null; then
|
||||||
|
warn "cross not found. Installing..."
|
||||||
|
cargo install cross --git https://github.com/cross-rs/cross
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
xwin)
|
||||||
|
if ! command -v cargo-xwin &>/dev/null; then
|
||||||
|
warn "cargo-xwin not found. Installing..."
|
||||||
|
cargo install cargo-xwin
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
zigbuild)
|
||||||
|
if ! command -v cargo-zigbuild &>/dev/null; then
|
||||||
|
warn "cargo-zigbuild not found. Installing..."
|
||||||
|
pip3 install ziglang
|
||||||
|
cargo install cargo-zigbuild
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
do_clean() {
|
||||||
|
info "Cleaning build artifacts..."
|
||||||
|
npm run build -- --clearScreen false 2>/dev/null || true
|
||||||
|
(cd src-tauri && cargo clean)
|
||||||
|
rm -rf dist
|
||||||
|
info "Clean complete."
|
||||||
|
}
|
||||||
|
|
||||||
|
build_macos_universal() {
|
||||||
|
info "Building macOS universal binary (x64 + arm64 → universal)..."
|
||||||
|
check_rust_target "x86_64-apple-darwin"
|
||||||
|
check_rust_target "aarch64-apple-darwin"
|
||||||
|
|
||||||
|
local tauri_args=(tauri build --target universal-apple-darwin)
|
||||||
|
if [[ "$BUILD_TYPE" == "debug" ]]; then
|
||||||
|
tauri_args=(tauri build --target universal-apple-darwin --debug)
|
||||||
|
fi
|
||||||
|
|
||||||
|
info "Running: npm run ${tauri_args[*]}"
|
||||||
|
npm run "${tauri_args[@]}"
|
||||||
|
}
|
||||||
|
|
||||||
|
build_platform() {
|
||||||
|
local platform="$1" arch="$2"
|
||||||
|
|
||||||
|
info "==========================================="
|
||||||
|
info " Building for $platform ($arch)"
|
||||||
|
info "==========================================="
|
||||||
|
|
||||||
|
if [[ "$platform/$arch" == "macos/universal" ]]; then
|
||||||
|
build_macos_universal
|
||||||
|
return $?
|
||||||
|
fi
|
||||||
|
|
||||||
|
local rust_target
|
||||||
|
rust_target=$(rust_target_for "$platform" "$arch")
|
||||||
|
|
||||||
|
local toolchain
|
||||||
|
toolchain=$(detect_toolchain "$platform" "$arch")
|
||||||
|
info "Using toolchain: $toolchain for $platform/$arch"
|
||||||
|
|
||||||
|
if [[ "$toolchain" == "native" ]]; then
|
||||||
|
check_rust_target "$rust_target"
|
||||||
|
local tauri_args=(tauri build --target "$rust_target")
|
||||||
|
if [[ "$BUILD_TYPE" == "debug" ]]; then
|
||||||
|
tauri_args+=(--debug)
|
||||||
|
fi
|
||||||
|
case "$platform" in
|
||||||
|
macos) tauri_args+=(--bundles app) ;;
|
||||||
|
windows) tauri_args+=(--bundles nsis) ;;
|
||||||
|
linux) tauri_args+=(--bundles deb) ;;
|
||||||
|
esac
|
||||||
|
info "Running: npm run ${tauri_args[*]}"
|
||||||
|
npm run "${tauri_args[@]}"
|
||||||
|
elif [[ "$toolchain" == "cross" ]]; then
|
||||||
|
install_cross_tools "cross"
|
||||||
|
check_rust_target "$rust_target"
|
||||||
|
info "Cross-compiling with cross for target: $rust_target"
|
||||||
|
local build_flag=""
|
||||||
|
if [[ "$BUILD_TYPE" == "release" ]]; then
|
||||||
|
build_flag="--release"
|
||||||
|
fi
|
||||||
|
(cd src-tauri && cross build --target "$rust_target" $build_flag --lib)
|
||||||
|
local tauri_args=(tauri build --target "$rust_target")
|
||||||
|
if [[ "$BUILD_TYPE" == "debug" ]]; then
|
||||||
|
tauri_args+=(--debug)
|
||||||
|
fi
|
||||||
|
case "$platform" in
|
||||||
|
windows) tauri_args+=(--bundles nsis) ;;
|
||||||
|
linux) tauri_args+=(--bundles deb) ;;
|
||||||
|
esac
|
||||||
|
info "Running: npm run ${tauri_args[*]}"
|
||||||
|
npm run "${tauri_args[@]}"
|
||||||
|
elif [[ "$toolchain" == "xwin" ]]; then
|
||||||
|
install_cross_tools "xwin"
|
||||||
|
check_rust_target "$rust_target"
|
||||||
|
info "Cross-compiling with cargo-xwin for target: $rust_target"
|
||||||
|
local build_flag=""
|
||||||
|
if [[ "$BUILD_TYPE" == "release" ]]; then
|
||||||
|
build_flag="--release"
|
||||||
|
fi
|
||||||
|
(cd src-tauri && cargo xwin build --target "$rust_target" $build_flag)
|
||||||
|
local tauri_args=(tauri build --target "$rust_target" --bundles nsis)
|
||||||
|
if [[ "$BUILD_TYPE" == "debug" ]]; then
|
||||||
|
tauri_args+=(--debug)
|
||||||
|
fi
|
||||||
|
info "Running: npm run ${tauri_args[*]}"
|
||||||
|
npm run "${tauri_args[@]}"
|
||||||
|
elif [[ "$toolchain" == "zigbuild" ]]; then
|
||||||
|
install_cross_tools "zigbuild"
|
||||||
|
check_rust_target "$rust_target"
|
||||||
|
info "Cross-compiling with cargo-zigbuild for target: $rust_target"
|
||||||
|
local build_flag=""
|
||||||
|
if [[ "$BUILD_TYPE" == "release" ]]; then
|
||||||
|
build_flag="--release"
|
||||||
|
fi
|
||||||
|
(cd src-tauri && cargo zigbuild --target "$rust_target" $build_flag)
|
||||||
|
local tauri_args=(tauri build --target "$rust_target")
|
||||||
|
if [[ "$BUILD_TYPE" == "debug" ]]; then
|
||||||
|
tauri_args+=(--debug)
|
||||||
|
fi
|
||||||
|
case "$platform" in
|
||||||
|
linux) tauri_args+=(--bundles deb) ;;
|
||||||
|
esac
|
||||||
|
info "Running: npm run ${tauri_args[*]}"
|
||||||
|
npm run "${tauri_args[@]}"
|
||||||
|
else
|
||||||
|
error "Unknown toolchain: $toolchain"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
declare -A BUILD_PLATFORMS
|
||||||
|
|
||||||
|
case "$PLATFORM" in
|
||||||
|
all)
|
||||||
|
BUILD_PLATFORMS=(
|
||||||
|
["macos-x64"]=1
|
||||||
|
["macos-arm64"]=1
|
||||||
|
["macos-universal"]=1
|
||||||
|
["windows-x64"]=1
|
||||||
|
["windows-arm64"]=1
|
||||||
|
["linux-x64"]=1
|
||||||
|
["linux-arm64"]=1
|
||||||
|
["linux-armhf"]=1
|
||||||
|
)
|
||||||
|
;;
|
||||||
|
macos|windows|linux)
|
||||||
|
key="${PLATFORM}-${ARCH}"
|
||||||
|
BUILD_PLATFORMS=(["$key"]=1)
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
error "Unknown platform: $PLATFORM. Use: macos, windows, linux, all"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
echo -e "${CYAN}"
|
||||||
|
echo " ╔═══════════════════════════════════════════╗"
|
||||||
|
echo " ║ AirDisplay Client Build System ║"
|
||||||
|
echo " ╚═══════════════════════════════════════════╝"
|
||||||
|
echo -e "${NC}"
|
||||||
|
info "Build type : $BUILD_TYPE"
|
||||||
|
info "Host : $CURRENT_PLATFORM ($CURRENT_ARCH)"
|
||||||
|
info "Targets : ${!BUILD_PLATFORMS[*]}"
|
||||||
|
|
||||||
|
check_command node
|
||||||
|
check_command npm
|
||||||
|
check_command cargo
|
||||||
|
check_command rustup
|
||||||
|
|
||||||
|
check_node_deps
|
||||||
|
|
||||||
|
if [[ "$CLEAN" == true ]]; then
|
||||||
|
do_clean
|
||||||
|
fi
|
||||||
|
|
||||||
|
FAILED=()
|
||||||
|
SUCCESS=()
|
||||||
|
|
||||||
|
for key in "${!BUILD_PLATFORMS[@]}"; do
|
||||||
|
IFS=- read -r plat arch <<< "$key"
|
||||||
|
if build_platform "$plat" "$arch"; then
|
||||||
|
SUCCESS+=("$plat ($arch)")
|
||||||
|
else
|
||||||
|
FAILED+=("$plat ($arch)")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
info "==========================================="
|
||||||
|
info " Build Summary"
|
||||||
|
info "==========================================="
|
||||||
|
if [[ ${#SUCCESS[@]} -gt 0 ]]; then
|
||||||
|
echo -e "${GREEN}Successful:${NC}"
|
||||||
|
for s in "${SUCCESS[@]}"; do echo " ✓ $s"; done
|
||||||
|
fi
|
||||||
|
if [[ ${#FAILED[@]} -gt 0 ]]; then
|
||||||
|
echo -e "${RED}Failed:${NC}"
|
||||||
|
for f in "${FAILED[@]}"; do echo " ✗ $f"; done
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
info "All builds completed successfully!"
|
||||||
Reference in New Issue
Block a user