···11#!/bin/bash
22+# SPDX-License-Identifier: AGPL-3.0-or-later
33+#
44+# Cross-compile Beaver for aarch64-unknown-linux-gnu using Docker.
55+# The source tree is bind-mounted — no separate clone needed.
66+#
77+# The target/ directory uses a Docker named volume because macOS has a
88+# case-insensitive filesystem which breaks mozjs (it generates both
99+# string.h and String.h system wrappers that collide).
210311set -e
412513PROFILE=${1:-"release"}
66-77-SYSROOT=`pwd`/scripts/servo-arm64-sysroot
88-99-export PKG_CONFIG_SYSROOT_DIR=${SYSROOT}
1010-export PKG_CONFIG_ALLOW_CROSS=1
1111-1212-export CC=clang
1313-export CXX=clang++
1414-export AR=llvm-ar
1515-1616-CXX_INCLUDES="-I${SYSROOT}/usr/include/c++/8/"
1717-1818-# We need -fuse-ld=lld here for jemalloc-sys
1919-export TARGET_CFLAGS="--sysroot=${SYSROOT} -fuse-ld=lld -I${SYSROOT}/usr/include/aarch64-linux-gnu"
2020-export TARGET_CXXFLAGS="--sysroot=${SYSROOT} $CXX_INCLUDES"
2121-2222-export CFLAGS="$TARGET_CFLAGS -I${SYSROOT}/usr/include/aarch64-linux-gnu"
2323-2424-# Needed for mozjs bindgen
2525-export BINDGEN_EXTRA_CLANG_ARGS="--sysroot=${SYSROOT} $CXX_INCLUDES"
2626-2727-# Needed for cmake
2828-export LDFLAGS="-L${SYSROOT}/lib/aarch64-linux-gnu -fuse-ld=lld"
2929-3030-# Build without tray icon or global key support
3131-cargo build --target aarch64-unknown-linux-gnu --profile ${PROFILE} -p beaver-shell \
3232- --no-default-features \
3333- --features="servo/clipboard,js_jit,max_log_level,webgpu"
3434-3535-llvm-strip target/aarch64-unknown-linux-gnu/${PROFILE}/beavershell
3636-3737-REMOTE_DIR=/home/mobian/beaver
3838-3939-echo "Pushing update..."
1414+IMAGE_NAME="beaver-arm64-builder"
1515+TARGET_VOLUME="beaver-arm64-target"
40164141-# Create the beaver directory if needed.
4242-ssh mobian@mobian 'mkdir -p /home/mobian/beaver'
1717+# Build Docker image if it doesn't exist yet.
1818+if ! docker image inspect "$IMAGE_NAME" &>/dev/null; then
1919+ echo "Building cross-compilation image..."
2020+ docker build -t "$IMAGE_NAME" -f support/docker/Dockerfile.arm64 .
2121+fi
43224444-# rsync the binary
4545-rsync -vz --progress target/aarch64-unknown-linux-gnu/${PROFILE}/beavershell \
4646- mobian@mobian:${REMOTE_DIR}/beavershell
2323+echo "Building beaver-shell for aarch64 (profile: ${PROFILE})..."
47244848-# rsync the resources
4949-rsync -avz --progress resources mobian@mobian:${REMOTE_DIR}/
2525+docker run --rm \
2626+ --memory=24g \
2727+ -v "$(pwd):/src" \
2828+ -v "${TARGET_VOLUME}:/src/target" \
2929+ -v "${HOME}/.cargo/registry:/root/.cargo/registry" \
3030+ -v "${HOME}/.cargo/git:/root/.cargo/git" \
3131+ -e PKG_CONFIG_ALLOW_CROSS=1 \
3232+ -e PKG_CONFIG_SYSROOT_DIR="" \
3333+ -e PKG_CONFIG_PATH="/usr/lib/aarch64-linux-gnu/pkgconfig" \
3434+ -e CC_aarch64_unknown_linux_gnu=aarch64-linux-gnu-gcc \
3535+ -e CXX_aarch64_unknown_linux_gnu=aarch64-linux-gnu-g++ \
3636+ -e AR_aarch64_unknown_linux_gnu=aarch64-linux-gnu-ar \
3737+ -e CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc \
3838+ -e BINDGEN_EXTRA_CLANG_ARGS="--target=aarch64-linux-gnu" \
3939+ -e CARGO_BUILD_JOBS="${CARGO_BUILD_JOBS:-8}" \
4040+ "$IMAGE_NAME" \
4141+ cargo build --target aarch64-unknown-linux-gnu --profile "$PROFILE" \
4242+ -p beaver-shell \
4343+ --no-default-features \
4444+ --features="servo/clipboard,servo/gstreamer,js_jit,max_log_level,native-bluetooth,webgpu"
50455151-# rsync the UI
5252-rsync -avz --progress ui mobian@mobian:${REMOTE_DIR}/
4646+# Copy the binary out of the Docker volume to the host for deploy.
4747+echo "Copying binary from Docker volume..."
4848+docker run --rm \
4949+ -v "${TARGET_VOLUME}:/target" \
5050+ -v "$(pwd)/dist:/out" \
5151+ "$IMAGE_NAME" \
5252+ sh -c "mkdir -p /out && cp /target/aarch64-unknown-linux-gnu/${PROFILE}/beavershell /out/"
53535454-echo "done!"
5454+echo "Build complete: dist/beavershell"
+31
deploy-arm64.sh
···11+#!/bin/bash
22+# SPDX-License-Identifier: AGPL-3.0-or-later
33+#
44+# Deploy a cross-compiled Beaver build to a remote ARM64 device.
55+66+set -e
77+88+BINARY="dist/beavershell"
99+REMOTE_HOST="mobian@mobian"
1010+REMOTE_DIR="/home/mobian/beaver"
1111+1212+if [ ! -f "$BINARY" ]; then
1313+ echo "Binary not found: $BINARY"
1414+ echo "Run ./build-arm64.sh first."
1515+ exit 1
1616+fi
1717+1818+# Strip the binary (try llvm-strip first, fall back to cross strip).
1919+llvm-strip "$BINARY" 2>/dev/null || \
2020+ aarch64-linux-gnu-strip "$BINARY" 2>/dev/null || \
2121+ echo "Warning: could not strip binary"
2222+2323+echo "Deploying to ${REMOTE_HOST}:${REMOTE_DIR}..."
2424+2525+ssh "$REMOTE_HOST" "mkdir -p ${REMOTE_DIR}"
2626+2727+rsync -vz --progress "$BINARY" "${REMOTE_HOST}:${REMOTE_DIR}/beavershell"
2828+rsync -avz --progress resources "${REMOTE_HOST}:${REMOTE_DIR}/"
2929+rsync -avz --progress ui "${REMOTE_HOST}:${REMOTE_DIR}/"
3030+3131+echo "Done!"
+34-9
readme.md
···38383939
40404141-## Mobile builds
4141+## Mobile builds (cross-compilation from macOS/Linux)
42424343-The only tested platform is the Pixel 3a running Mobian (see https://wiki.debian.org/InstallingDebianOn/Google/Pixel3a).
4343+The target platform is aarch64 Linux devices such as the Pixel 3a running Mobian (see https://wiki.debian.org/InstallingDebianOn/Google/Pixel3a).
44444545
46464747-First create a sysroot by running `sysroot.sh` in the `scripts` directory.
4747+### Prerequisites
4848+4949+- Docker Desktop (with at least 24GB memory allocated in Settings > Resources)
5050+5151+### Building
5252+5353+Cross-compilation uses a Docker container with an ARM64 toolchain and all native dependencies. The source tree is bind-mounted so no separate clone is needed.
5454+5555+```bash
5656+# First build creates the Docker image, then compiles (takes a while):
5757+./build-arm64.sh release
5858+5959+# Subsequent builds are incremental:
6060+./build-arm64.sh release
6161+6262+# Production build with LTO:
6363+./build-arm64.sh production
6464+```
6565+6666+The binary is output to `dist/beavershell`.
6767+6868+You can adjust parallelism if needed: `CARGO_BUILD_JOBS=2 ./build-arm64.sh release`
6969+7070+### Deploying to device
48714949-Then build with `./build-arm64.sh` or `./build-arm64.sh production`
7272+The deploy script rsyncs the binary, resources, and UI to a remote device over SSH:
50735151-The build script expects to be able to ssh with key authentication to `mobian@mobian`. You can then run on device with this command:
5252-`mobian@mobian:~$ ./beaver/beaver`
7474+```bash
7575+./deploy-arm64.sh
7676+```
53775454-Note that you will have to set these 2 environment variables:
7878+This expects key-based SSH access to `mobian@mobian`. Then run on device:
55795656-- SURFMAN_FORCE_GLES=1
5757-- WAYLAND_DISPLAY=wayland-0
8080+```bash
8181+SURFMAN_FORCE_GLES=1 WAYLAND_DISPLAY=wayland-0 ./beaver/beavershell
8282+```
58835984Here's what this looks like
6085
-67
scripts/sysroot.sh
···11-#!/bin/bash
22-33-# Simplified version of:
44-# https://searchfox.org/firefox-main/rev/e62801966f0afe75facf57d066b6e472fbbc1adb/taskcluster/scripts/misc/build-sysroot.sh
55-66-set -x
77-set -e
88-99-sysroot="servo-arm64-sysroot"
1010-1111-packages="
1212- linux-libc-dev
1313- libasound2-dev
1414- libstdc++-8-dev
1515- libfontconfig1-dev
1616- libfreetype6-dev
1717- libgconf2-dev
1818- libgcc-8-dev
1919- libgtk-3-dev
2020- libpango1.0-dev
2121- libpulse-dev
2222- libudev-dev
2323- libx11-xcb-dev
2424- libxt-dev
2525- $*
2626-"
2727-2828-echo "deb http://snapshot.debian.org/archive/debian/20230611T210420Z buster main" | mmdebstrap \
2929- --architectures=arm64 \
3030- --variant=extract \
3131- --mode=fakeroot \
3232- --include=$(echo $packages | tr ' ' ,) \
3333- buster $sysroot \
3434- --dpkgopt=path-exclude="*" \
3535- --dpkgopt=path-include="/lib/*" \
3636- --dpkgopt=path-include="/lib32/*" \
3737- --dpkgopt=path-include="/usr/include/*" \
3838- --dpkgopt=path-include="/usr/lib/*" \
3939- --dpkgopt=path-include="/usr/lib32/*" \
4040- --dpkgopt=path-exclude="/usr/lib/debug/*" \
4141- --dpkgopt=path-exclude="/usr/lib/python*" \
4242- --dpkgopt=path-include="/usr/share/pkgconfig/*" \
4343-4444-# Remove more unwanted files
4545-rm -rf $sysroot/etc $sysroot/dev $sysroot/tmp $sysroot/var
4646-4747-# Remove empty directories
4848-find $sysroot -depth -type d -empty -delete
4949-5050-# Adjust symbolic links to link into the sysroot instead of absolute
5151-# paths that end up pointing at the host system.
5252-find $sysroot -type l | while read l; do
5353- t=$(readlink $l)
5454- case "$t" in
5555- /*)
5656- # We have a path in the form "$sysroot/a/b/c/d" and we want ../../..,
5757- # which is how we get from d to the root of the sysroot. For that,
5858- # we start from the directory containing d ("$sysroot/a/b/c"), remove
5959- # all non-slash characters, leaving is with "///", replace each slash
6060- # with "../", which gives us "../../../", and then we remove the last
6161- # slash.
6262- rel=$(dirname $l | sed 's,[^/],,g;s,/,../,g;s,/$,,')
6363- ln -sf $rel$t $l
6464- ;;
6565- esac
6666-done
6767-