Skip to content

Commit

Permalink
Add Docker-based build system
Browse files Browse the repository at this point in the history
Now, we can add other runtimes like Podman, too.
  • Loading branch information
TheAssassin committed Jul 27, 2024
1 parent 8c7c95d commit 12f2ba9
Show file tree
Hide file tree
Showing 6 changed files with 171 additions and 10 deletions.
19 changes: 9 additions & 10 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,6 @@ concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

# The default Debian shell (dash) is faster than bash at running scripts,
# and using bash when it is not needed doesn't make sense.
defaults:
Expand All @@ -31,10 +28,10 @@ jobs:
fail-fast: false
matrix:
include:
- { qemu_arch: x86, appimage_arch: x86 }
- { qemu_arch: x86_64, appimage_arch: x86_64 }
- { qemu_arch: armv7, appimage_arch: armhf }
- { qemu_arch: aarch64, appimage_arch: aarch64 }
- appimage_arch: i686
- appimage_arch: x86_64
- appimage_arch: armhf
- appimage_arch: aarch64

steps:
- name: Checkout
Expand All @@ -45,12 +42,14 @@ jobs:
echo -n "https://github.com/${GITHUB_REPOSITORY}/commit/" > src/runtime/version
git rev-parse --short HEAD | xargs >> src/runtime/version
- name: Set up QEMU integration for Docker
run: docker run --rm --privileged multiarch/qemu-user-static --reset -p yes

- name: Build
env:
ARCHITECTURE: ${{ matrix.appimage_arch }}
ARCH: ${{ matrix.appimage_arch }}
run: |
sudo apt-get -y install qemu-user-static
./chroot_build.sh
./build-with-docker.sh
- name: Sign
env:
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,6 @@ modules.order
Module.symvers
Mkfile.old
dkms.conf

# resulting binaries
runtime-*
20 changes: 20 additions & 0 deletions BUILD.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# How to build the runtime

## Docker

As the runtime build requires a special environment with specific dependencies prebuilt and installed as static binaries, we provide a containerized build environment. We use Docker as a runtime for now.

Using containers provides the following advantages:

- Speed up local development by caching the built dependencies in the built image
- Automatically rebuild the image upon changes in the image's definition
- Isolate build environment from the host
- "Out-of-source" builds (in a naive way, we just copy the entire source code to a temporary build directory)

The build process has been automated completely. As a user, you just need to run the `build-with-docker.sh` script:

```sh
> env ARCH=<arch> ./build-with-docker.sh
```

The resulting AppImages will end up in your current working directory.
37 changes: 37 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
FROM alpine:latest

# includes dependencies from https://git.alpinelinux.org/aports/tree/main/fuse3/APKBUILD
RUN apk add --no-cache \
bash alpine-sdk util-linux strace file autoconf automake libtool xz \
eudev-dev gettext-dev linux-headers meson \
zstd-dev zstd-static zlib-dev zlib-static # fuse3-dev fuse3-static fuse-static fuse-dev

COPY patches/ /tmp/patches/

WORKDIR /tmp

RUN wget https://github.com/libfuse/libfuse/releases/download/fuse-3.15.0/fuse-3.15.0.tar.xz && \
echo "70589cfd5e1cff7ccd6ac91c86c01be340b227285c5e200baa284e401eea2ca0 fuse-3.15.0.tar.xz" | sha256sum -c && \
tar xf fuse-3.*.tar.xz && \
cd fuse-3*/ && \
patch -p1 < /tmp/patches/libfuse/mount.c.diff && \
mkdir build && \
cd build && \
meson setup --prefix=/usr .. && \
meson configure --default-library static && \
ninja -v install && \
rm -r /tmp/fuse-*

# Minimize binary size
ENV CFLAGS="-ffunction-sections -fdata-sections -Os"

RUN wget "https://github.com/vasi/squashfuse/archive/e51978c.tar.gz" && \
echo "f544029ad30d8fbde4e4540c574b8cdc6d38b94df025a98d8551a9441f07d341 e51978c.tar.gz" | sha256sum -c && \
tar xf e51978c.tar.gz && \
cd squashfuse-*/ && \
./autogen.sh && \
./configure CFLAGS="${CFLAGS} -no-pie" LDFLAGS=-static && \
make -j"$(nproc)" && \
make install && \
/usr/bin/install -c -m 644 ./*.h '/usr/local/include/squashfuse' && \
rm -r /tmp/e51978c* /tmp/squashfuse*
56 changes: 56 additions & 0 deletions build-in-container.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#! /bin/bash

set -euo pipefail

# we'll copy the outcome to the current working directory
out_dir="$(readlink -f "$(pwd)")"

# we create a temporary build directory
build_dir="$(mktemp -d -t type2-runtime-build-XXXXXX)"

# since the plain ol' Makefile doesn't support out-of-source builds at all, we need to copy all the files
cp -R src "$build_dir"/

pushd "$build_dir"

pushd src/runtime/
make -j"$(nproc)" runtime-fuse3

file runtime-fuse3

# optimize for size
# TODO: should be part of the Makefile
strip runtime-fuse3

# "classic" magic bytes which cannot be embedded with compiler magic, always do AFTER strip
# TODO: should be part of the Makefile
echo -ne 'AI\x02' | dd of=runtime-fuse3 bs=1 count=3 seek=8 conv=notrunc

ls -lh runtime-fuse3

# append architecture prefix
# since we expect to be built in a Dockerized environment, i.e., either run in a native environment or have it emulated transparently with QEMU, we can just use uname
# all we have to do is convert uname's expected output to AppImage's semi-official suffix style
case "$(uname -m)" in
x86_64)
architecture=x86_64
;;
i386|i586|i686)
architecture=i686
;;
aarch64|arm64v8)
architecture=aarch64
;;
arm32v7|armv7l|armhf)
architecture=armhf
;;
*)
echo "Unsupported architecture: $(uname -m)"
exit 2
;;
esac

mv runtime-fuse3 runtime-fuse3-"$architecture"
cp runtime-fuse3-"$architecture" "$out_dir"/


46 changes: 46 additions & 0 deletions build-with-docker.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#! /bin/bash

set -euo pipefail

image_name=type2-runtime-build

if [[ "${ARCH:-}" == "" ]]; then
echo "Usage: env ARCH=[...] $0"
exit 2
fi

# guess architecture name compatible with Docker from $ARCH
case "${ARCH}" in
x86_64)
docker_arch=amd64
;;
i686)
docker_arch=i386
;;
armhf)
docker_arch=arm32v7
;;
aarch64)
docker_arch=aarch64
;;
*)
echo "Unsupported architecture: $ARCH"
exit 3
;;
esac

docker_platform="linux/$docker_arch"

# first, we need to build the image
# if nothing has changed, it'll run over this within a few seconds
docker build --platform "$docker_platform" -t "$image_name" .

docker_run_args=()
[[ -t 0 ]] && docker_run_args+=("-t")

# next, build the binary in a container running this image
# we run the build as an unprivileged user to a) make sure that the build process does not require root permissions and b) make the resulting binary writable to the current user
docker run -u "$(id -u):$(id -g)" --platform "$docker_platform" --rm -i "${docker_run_args[@]}" -w /ws -v "$(readlink -f .)":/ws "$image_name" bash build-in-container.sh

# done!
# you should now have the binary in your current working directory

0 comments on commit 12f2ba9

Please sign in to comment.