Running Dart on Arm Servers

The @ Company
May 10 · 4 min read

By Chris Swan, engineer at The @ Company

Last week I wrote about easier automation using GitHub Actions to build multi-architecture Docker images. That led me to another question — how to create the binaries to go into those builds? If I’m making an Arm image, then I need an Arm binary to go into that image.

At the moment dart compile only compiles self-contained executable files for the architecture it’s being run on. This is a shame, as the underlying tooling is perfectly capable of doing cross-compilation as J-P Nurmi explains in Cross-compiling Dart apps.

Without cross-compilation the only alternative is to run dart compile from the Dart SDK on each of the target platforms. Google handily packages up the SDK into a Docker image google/dart but unfortunately, that's only available for x86_64 (aka amd64). The Dockerfile for that image also makes use of the SDK apt package, but that too is only available for x86_64.

So to run dart compile on multiple architectures, I first needed a multi-arch build image:

FROM debian:stableARG DART_VERSION="2.12.4"WORKDIR /tmp/RUN \
apt-get -q update && apt-get install --no-install-recommends -y -q \
gnupg2 curl git ca-certificates unzip openssh-client && \
case "$(uname -m)" in armv7l | armv7) ARCH="arm";; aarch64) ARCH="arm64";; *) ARCH="x64";; esac && \
curl -O$DART_VERSION/sdk/dartsdk-linux-$ && \
unzip dartsdk-linux-$ -d /usr/lib/ && \
rm dartsdk-linux-$ && \
mv /usr/lib/dart-sdk /usr/lib/dart
ENV DART_SDK /usr/lib/dart
ENV PATH $DART_SDK/bin:/root/.pub-cache/bin:$PATH

This is installing some key dependencies (the same as google/dart) and then downloading and installing the Dart SDK according to the output from uname -m to establish the underlying architecture.

With the build image it’s then possible to create a lightweight run image based on the work by Google engineer Tony Pujals with his subfuzion/dart-docker-slim:

# Originally based on subfuzion/dart-docker-slim
# Using our buildimage as it supports x64|arm|arm64
FROM atsigncompany/buildimage AS dart
# Do all the copying to an output dir here first
# as the buildimage has a shell that can be used
# for multi-arch conditionals
mkdir -p /output/lib && mkdir -p /output/etc && \
mkdir -p /output/etc/ssl/certs && \
mkdir -p /output/usr/share/ca-certificates && \
case "$(uname -m)" in \
armv7l | armv7) ARCH="arm-linux-gnueabihf" ; \
mkdir -p /output/lib/$ARCH ; \
cp /lib/ /output/lib/ ; \
cp /lib/arm-linux-gnueabihf/ \
/output/lib/arm-linux-gnueabihf/ ;; \
aarch64) ARCH="aarch64-linux-gnu" ; \
mkdir -p /output/lib/$ARCH ; \
cp /lib/ /output/lib/ ; \
cp /lib/aarch64-linux-gnu/ \
/output/lib/aarch64-linux-gnu/ ;; \
*) ARCH="x86_64-linux-gnu" ; \
mkdir -p /output/lib/$ARCH ; mkdir -p /output/lib64/ ; \
cp /lib64/ /output/lib64/ ;; \
esac && \
cp /lib/$ARCH/ /output/lib/$ARCH/ && \
cp /lib/$ARCH/ /output/lib/$ARCH/ && \
cp /lib/$ARCH/ /output/lib/$ARCH/ && \
cp /lib/$ARCH/ /output/lib/$ARCH/ && \
cp /lib/$ARCH/ /output/lib/$ARCH/ && \
cp /lib/$ARCH/ /output/lib/$ARCH/ && \
cp /lib/$ARCH/ /output/lib/$ARCH/ && \
cp /etc/nsswitch.conf /output/etc/nsswitch.conf && \
cp /etc/resolv.conf /output/etc/resolv.conf && \
cp -R /usr/share/ca-certificates /output/usr/share/ca-certificates && \
cp -R /etc/ssl/certs /output/etc/ssl/certs
FROM scratch
COPY --from=dart /output /
# Is this even really needed, as Docker uses host hosts?
COPY ./at-runimage/etc-hosts /etc/hosts

Once again this is using the output of uname -m to determine the correct dependencies to copy in from the build image.

The build image and run image can then be brought together with a Dart application. I put together a trivial one dartshowplatform that prints out version and platform information like:

$ sudo docker run -it  atsigncompany/dartshowplatform
2.12.4 (stable) (Thu Apr 15 12:26:53 2021 +0200) on "linux_arm64"

Here’s the Dockerfile:

FROM atsigncompany/buildimage
COPY ./dartshowplatform/showplatform.dart .
RUN dart compile exe /app/showplatform.dart -o /app/dartshowplatform
FROM atsigncompany/runimage
COPY --from=0 /app/dartshowplatform /app/dartshowplatform
ENTRYPOINT ["/app/dartshowplatform"]

The build image is used to run dart compile and then the binary created from that is copied into the run image.

The full source etc. for the stuff above is available on GitHub atsign-company/at_dockerfiles.

If you’re wondering why we’re doing this, it’s because people are asking us to support Arm and Arm64, as there’s huge growth in the Arm footprint as illustrated above. We can expect it won’t be long before we’re having to add RISC-V support too, as that Instruction Set Architecture (ISA) gains traction and wider adoption. The days of WinTel hegemony are over, which means dealing with a lot more heterogeneity, and that demands greater automation to avoid being drowned by the complexity of it all.

The @ Company is a tech startup committed to transforming how the modern Internet treats people’s data. To learn more about The @ Company and their mission, check out their website.

Follow Flutter Community on Twitter:

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store