From 946b725af5c9271818e28afa0ac11237b9c91386 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 7 Jun 2024 14:49:37 -0600 Subject: [PATCH 1/2] add Linux/ARM64 cross-compilation support Currently, the Makefile assumes the LLVM toolchain it builds can be executed natively to build `wasi-libc` etc., which isn't true when cross-compiling for another platform, but we can work around that by: 1. Building the native LLVM toolchain and using it to build everything else, as usual 2. Deleting that LLVM build and rebuilding (and reinstalling) it with `LLVM_CMAKE_FLAGS` set to cross compile 3. Rebuilding and reinstalling a cross-compiled `wasm-component-ld` 4. Building deb and tar files from the above Note that we now label the tarfiles `linux-amd64` and `linux-arm64`, respectively for clarity. The whole approach is a bit hacky, but GitHub is planning to roll out ARM64 runner support for open source projects later this year, at which point we can start building natively, so I don't think we need to invest a lot of effort into this. I've run CI in my fork and verified the artifact produced there works on my Ubuntu 24.04 ARM64 machine (Asahi Linux on an Apple M2 Pro). Fixes #236 Fixes #347 Signed-off-by: Joel Dice --- .github/workflows/main.yml | 18 +++++++++++++++++- Dockerfile | 5 ++++- Makefile | 4 ++-- cross_build_arm64.sh | 9 +++++++++ deb_from_installation.sh | 8 ++++++-- docker/Dockerfile | 2 +- docker_build.sh | 3 ++- tar_from_installation.sh | 20 ++++++++++++-------- 8 files changed, 53 insertions(+), 16 deletions(-) create mode 100755 cross_build_arm64.sh diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 9ccef2620..00974ca60 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -60,7 +60,7 @@ jobs: run: sudo apt install ccache ninja-build if: matrix.os == 'ubuntu-latest' - name: Build - run: NINJA_FLAGS=-v make package LLVM_CMAKE_FLAGS=-DLLVM_CCACHE_BUILD=ON + run: NINJA_FLAGS=-v make package LLVM_CMAKE_FLAGS=-DLLVM_CCACHE_BUILD=ON DEB_ARCH=amd64 TAR_MACHINE=linux-amd64 shell: bash - name: Run the testsuite run: NINJA_FLAGS=-v make check RUNTIME=wasmtime @@ -168,6 +168,22 @@ jobs: - name: Run docker_build script run: ./docker_build.sh + + - name: Cross-compile for ARM64 + # Hacktastic cross-compilation step: build and install an ARM64 LLVM, + # reusing everything else we built using the native toolchain. Once + # GitHub provides ARM64 runners to open source projects (planned for + # second half of 2024) we'll be able to build natively and avoid this + # step. + run: | + docker run --rm \ + --user $(id -u):$(id -g) \ + -v "$PWD":/workspace:Z \ + -v ~/.ccache:/home/builder/.ccache:Z \ + --tmpfs /tmp:exec \ + wasi-sdk-builder:latest \ + bash cross_build_arm64.sh + - name: Upload artifacts uses: actions/upload-artifact@v4 with: diff --git a/Dockerfile b/Dockerfile index adddd029c..b0ff1e10d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,6 +18,8 @@ RUN apt-get update \ python3 \ git \ ninja-build \ + gcc-aarch64-linux-gnu \ + g++-aarch64-linux-gnu \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* @@ -31,7 +33,8 @@ ENV PATH /opt/cmake/bin:$PATH ENV RUSTUP_HOME=/rust/rustup CARGO_HOME=/rust/cargo PATH=$PATH:/rust/cargo/bin RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | \ sh -s -- -y --profile=minimal && \ - chmod -R a+w /rust + chmod -R a+w /rust && \ + rustup target add aarch64-unknown-linux-gnu RUN groupadd -g ${GID} builder && \ useradd --create-home --uid ${UID} --gid ${GID} builder diff --git a/Makefile b/Makefile index da92c1eab..accb151c7 100644 --- a/Makefile +++ b/Makefile @@ -283,8 +283,8 @@ package: build/package.BUILT build/package.BUILT: build strip mkdir -p dist - ./deb_from_installation.sh $(shell pwd)/dist "$(VERSION)" "$(BUILD_PREFIX)" - ./tar_from_installation.sh "$(shell pwd)/dist" "$(VERSION)" "$(BUILD_PREFIX)" + ./deb_from_installation.sh $(shell pwd)/dist "$(VERSION)" "$(BUILD_PREFIX)" "$(DEB_ARCH)" + ./tar_from_installation.sh "$(shell pwd)/dist" "$(VERSION)" "$(BUILD_PREFIX)" "$(TAR_MACHINE)" touch build/package.BUILT .PHONY: default clean build strip package check diff --git a/cross_build_arm64.sh b/cross_build_arm64.sh new file mode 100755 index 000000000..0267518aa --- /dev/null +++ b/cross_build_arm64.sh @@ -0,0 +1,9 @@ +#!/bin/sh +set -ex + +rm -r build/llvm build/llvm.BUILT +NINJA_FLAGS=-v make strip LLVM_CMAKE_FLAGS="-DLLVM_CCACHE_BUILD=ON -DCMAKE_C_COMPILER=aarch64-linux-gnu-gcc -DCMAKE_CXX_COMPILER=aarch64-linux-gnu-g++ -DCMAKE_CROSSCOMPILING=True -DCMAKE_CXX_FLAGS=-march=armv8-a -DCMAKE_SYSTEM_PROCESSOR=arm64 -DCMAKE_SYSTEM_NAME=Linux -DLLVM_HOST_TRIPLE=aarch64-linux-gnu" +CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc cargo install wasm-component-ld@0.5.0 --root "$(pwd)/build/install/opt/wasi-sdk" --target aarch64-unknown-linux-gnu +mkdir -p dist +./deb_from_installation.sh "$(pwd)/dist" "$(./version.py)" "$(pwd)/build/install/opt/wasi-sdk" "arm64" +./tar_from_installation.sh "$(pwd)/dist" "$(./version.py)" "$(pwd)/build/install/opt/wasi-sdk" "linux-arm64" diff --git a/deb_from_installation.sh b/deb_from_installation.sh index 2699c819c..779abeda2 100755 --- a/deb_from_installation.sh +++ b/deb_from_installation.sh @@ -27,13 +27,17 @@ else INSTALL_DIR=/opt/wasi-sdk fi +if [ -n "$4" ]; then + ARCH="$4" +else + ARCH=$(dpkg --print-architecture) +fi + if [ ! -d $INSTALL_DIR ] ; then echo "Directory $INSTALL_DIR doesn't exist. Nothing to copy from." exit 1 fi -ARCH=$(dpkg --print-architecture) - rm -rf build/pkg mkdir -p build/pkg/opt mkdir -p build/pkg/DEBIAN diff --git a/docker/Dockerfile b/docker/Dockerfile index 9fda47064..30ec63ee6 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -8,7 +8,7 @@ # separately. FROM ubuntu:22.04 as dist -ADD dist/wasi-sdk-*.*-linux.tar.gz / +ADD dist/wasi-sdk-*.*-linux-amd64.tar.gz / ADD dist/libclang_rt.builtins-wasm32-wasi-*.*.tar.gz /wasi-sysroot-clang_rt # Move versioned folder to unversioned to using bash glob to allow diff --git a/docker_build.sh b/docker_build.sh index 050862fac..6343c27f8 100755 --- a/docker_build.sh +++ b/docker_build.sh @@ -8,6 +8,7 @@ docker build \ echo "Building the package in docker image" mkdir -p ~/.ccache +arch=$(dpkg --print-architecture) docker run --rm \ --user $(id -u):$(id -g) \ -v "$PWD":/workspace:Z \ @@ -15,4 +16,4 @@ docker run --rm \ -e NINJA_FLAGS=-v \ --tmpfs /tmp:exec \ wasi-sdk-builder:latest \ - make package LLVM_CMAKE_FLAGS=-DLLVM_CCACHE_BUILD=ON + make package LLVM_CMAKE_FLAGS=-DLLVM_CCACHE_BUILD=ON DEB_ARCH=$arch TAR_MACHINE=linux-$arch diff --git a/tar_from_installation.sh b/tar_from_installation.sh index 7d0943266..ade0fcc47 100755 --- a/tar_from_installation.sh +++ b/tar_from_installation.sh @@ -19,14 +19,18 @@ else INSTALL_DIR=/opt/wasi-sdk fi -case "$(uname -s)" in - Linux*) MACHINE=linux;; - Darwin*) MACHINE=macos;; - CYGWIN*) MACHINE=cygwin;; - MINGW*) MACHINE=mingw;; - MSYS*) MACHINE=msys;; #MSYS_NT-10.0-19043 - *) MACHINE="UNKNOWN" -esac +if [ -n "$4" ]; then + MACHINE="$4" +else + case "$(uname -s)" in + Linux*) MACHINE=linux;; + Darwin*) MACHINE=macos;; + CYGWIN*) MACHINE=cygwin;; + MINGW*) MACHINE=mingw;; + MSYS*) MACHINE=msys;; #MSYS_NT-10.0-19043 + *) MACHINE="UNKNOWN" + esac +fi if [ ! -d $INSTALL_DIR ] ; then echo "Directory $INSTALL_DIR doesn't exist. Nothing to copy from." From aa8cc1caccccd9a7384059171a6b7ba918f5737d Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 10 Jun 2024 14:49:19 -0600 Subject: [PATCH 2/2] derive Linux tar suffix based on `uname -m` Signed-off-by: Joel Dice --- .github/workflows/main.yml | 2 +- docker_build.sh | 3 +-- tar_from_installation.sh | 15 ++++++++------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 00974ca60..aa5e82e58 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -60,7 +60,7 @@ jobs: run: sudo apt install ccache ninja-build if: matrix.os == 'ubuntu-latest' - name: Build - run: NINJA_FLAGS=-v make package LLVM_CMAKE_FLAGS=-DLLVM_CCACHE_BUILD=ON DEB_ARCH=amd64 TAR_MACHINE=linux-amd64 + run: NINJA_FLAGS=-v make package LLVM_CMAKE_FLAGS=-DLLVM_CCACHE_BUILD=ON shell: bash - name: Run the testsuite run: NINJA_FLAGS=-v make check RUNTIME=wasmtime diff --git a/docker_build.sh b/docker_build.sh index 6343c27f8..050862fac 100755 --- a/docker_build.sh +++ b/docker_build.sh @@ -8,7 +8,6 @@ docker build \ echo "Building the package in docker image" mkdir -p ~/.ccache -arch=$(dpkg --print-architecture) docker run --rm \ --user $(id -u):$(id -g) \ -v "$PWD":/workspace:Z \ @@ -16,4 +15,4 @@ docker run --rm \ -e NINJA_FLAGS=-v \ --tmpfs /tmp:exec \ wasi-sdk-builder:latest \ - make package LLVM_CMAKE_FLAGS=-DLLVM_CCACHE_BUILD=ON DEB_ARCH=$arch TAR_MACHINE=linux-$arch + make package LLVM_CMAKE_FLAGS=-DLLVM_CCACHE_BUILD=ON diff --git a/tar_from_installation.sh b/tar_from_installation.sh index ade0fcc47..f23971868 100755 --- a/tar_from_installation.sh +++ b/tar_from_installation.sh @@ -22,13 +22,14 @@ fi if [ -n "$4" ]; then MACHINE="$4" else - case "$(uname -s)" in - Linux*) MACHINE=linux;; - Darwin*) MACHINE=macos;; - CYGWIN*) MACHINE=cygwin;; - MINGW*) MACHINE=mingw;; - MSYS*) MACHINE=msys;; #MSYS_NT-10.0-19043 - *) MACHINE="UNKNOWN" + case "$(uname -s):$(uname -m)" in + Linux*:aarch64) MACHINE=linux-arm64;; + Linux*:x86_64) MACHINE=linux-amd64;; + Darwin*) MACHINE=macos;; + CYGWIN*) MACHINE=cygwin;; + MINGW*) MACHINE=mingw;; + MSYS*) MACHINE=msys;; #MSYS_NT-10.0-19043 + *) MACHINE="UNKNOWN" esac fi