-
Notifications
You must be signed in to change notification settings - Fork 71
/
Dockerfile
166 lines (146 loc) · 5.61 KB
/
Dockerfile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# syntax=docker/dockerfile:1
ARG GO_VERSION=1.21
ARG ALPINE_VERSION=3.20
ARG XX_VERSION=1.4.0
ARG QEMU_VERSION=HEAD
ARG QEMU_REPO=https://github.com/qemu/qemu
# xx is a helper for cross-compilation
FROM --platform=$BUILDPLATFORM tonistiigi/xx:${XX_VERSION} AS xx
FROM --platform=$BUILDPLATFORM alpine:${ALPINE_VERSION} AS src
RUN apk add --no-cache git patch
WORKDIR /src
ARG QEMU_VERSION
ARG QEMU_REPO
RUN git clone $QEMU_REPO && cd qemu && git checkout $QEMU_VERSION
COPY patches patches
# QEMU_PATCHES defines additional patches to apply before compilation
ARG QEMU_PATCHES=cpu-max-arm
# QEMU_PATCHES_ALL defines all patches to apply before compilation
ARG QEMU_PATCHES_ALL=${QEMU_PATCHES},alpine-patches
ARG QEMU_PRESERVE_ARGV0
RUN <<eof
set -ex
if [ "${QEMU_PATCHES_ALL#*alpine-patches}" != "${QEMU_PATCHES_ALL}" ]; then
ver="$(cat qemu/VERSION)"
for l in $(cat patches/aports.config); do
pver=$(echo $l | cut -d, -f1)
if [ "${ver%.*}" = "${pver%.*}" ]; then
commit=$(echo $l | cut -d, -f2)
rmlist=$(echo $l | cut -d, -f3)
break
fi
done
mkdir -p aports && cd aports && git init
git fetch --depth 1 https://github.com/alpinelinux/aports.git "$commit"
git checkout FETCH_HEAD
mkdir -p ../patches/alpine-patches
for f in $(echo $rmlist | tr ";" "\n"); do
rm community/qemu/*${f}*.patch || true
done
cp -a community/qemu/*.patch ../patches/alpine-patches/
cd - && rm -rf aports
fi
if [ -n "${QEMU_PRESERVE_ARGV0}" ]; then
QEMU_PATCHES_ALL="${QEMU_PATCHES_ALL},preserve-argv0"
fi
cd qemu
for p in $(echo $QEMU_PATCHES_ALL | tr ',' '\n'); do
for f in ../patches/$p/*.patch; do echo "apply $f"; patch -p1 < $f; done
done
scripts/git-submodule.sh update ui/keycodemapdb tests/fp/berkeley-testfloat-3 tests/fp/berkeley-softfloat-3 dtc slirp
eof
FROM --platform=$BUILDPLATFORM alpine:${ALPINE_VERSION} AS base
RUN apk add --no-cache git clang lld python3 llvm make ninja pkgconfig glib-dev gcc musl-dev perl bash
COPY --from=xx / /
ENV PATH=/qemu/install-scripts:$PATH
WORKDIR /qemu
ARG TARGETPLATFORM
RUN xx-apk add --no-cache musl-dev gcc glib-dev glib-static linux-headers zlib-static
RUN set -e; \
[ "$(xx-info arch)" = "ppc64le" ] && XX_CC_PREFER_LINKER=ld xx-clang --setup-target-triple; \
[ "$(xx-info arch)" = "386" ] && XX_CC_PREFER_LINKER=ld xx-clang --setup-target-triple; \
true
FROM base AS build
ARG TARGETPLATFORM
# QEMU_TARGETS sets architectures that emulators are built for (default all)
ARG QEMU_VERSION QEMU_TARGETS
ENV AR=llvm-ar STRIP=llvm-strip
RUN --mount=target=.,from=src,src=/src/qemu,rw --mount=target=./install-scripts,src=scripts \
TARGETPLATFORM=${TARGETPLATFORM} configure_qemu.sh && \
make -j "$(getconf _NPROCESSORS_ONLN)" && \
make install && \
cd /usr/bin && for f in $(ls qemu-*); do xx-verify --static $f; done
ARG BINARY_PREFIX
RUN cd /usr/bin; [ -z "$BINARY_PREFIX" ] || for f in $(ls qemu-*); do ln -s $f $BINARY_PREFIX$f; done
FROM --platform=$BUILDPLATFORM golang:${GO_VERSION}-alpine AS binfmt
COPY --from=xx / /
ENV CGO_ENABLED=0
ARG TARGETPLATFORM
ARG QEMU_VERSION
WORKDIR /src
RUN apk add --no-cache git
RUN --mount=target=. \
TARGETPLATFORM=$TARGETPLATFORM xx-go build \
-ldflags "-X main.revision=$(git rev-parse --short HEAD) -X main.qemuVersion=${QEMU_VERSION}" \
-o /go/bin/binfmt ./cmd/binfmt && \
xx-verify --static /go/bin/binfmt
FROM build AS build-archive
COPY --from=binfmt /go/bin/binfmt /usr/bin/binfmt
RUN cd /usr/bin && mkdir -p /archive && \
tar czvfh "/archive/${BINARY_PREFIX}qemu_${QEMU_VERSION}_$(echo $TARGETPLATFORM | sed 's/\//-/g').tar.gz" ${BINARY_PREFIX}qemu* && \
tar czvfh "/archive/binfmt_$(echo $TARGETPLATFORM | sed 's/\//-/g').tar.gz" binfmt
# binaries contains only the compiled QEMU binaries
FROM scratch AS binaries
# BINARY_PREFIX sets prefix string to all QEMU binaries
ARG BINARY_PREFIX
COPY --from=build usr/bin/${BINARY_PREFIX}qemu-* /
# archive returns the tarball of binaries
FROM scratch AS archive
COPY --from=build-archive /archive/* /
FROM --platform=$BUILDPLATFORM tonistiigi/bats-assert AS assert
FROM --platform=$BUILDPLATFORM alpine:${ALPINE_VERSION} AS alpine-crossarch
RUN apk add --no-cache bash
# Runs on the build platform without emulation, but we need to get hold of the cross arch busybox binary
# for use with tests using emulation
ARG BUILDARCH
RUN <<eof
bash -euo pipefail -c '
if [ "$BUILDARCH" == "amd64" ]; then
echo "aarch64" > /etc/apk/arch
else
echo "x86_64" > /etc/apk/arch
fi
'
eof
RUN apk add --allow-untrusted --no-cache busybox-static
# Recreate all the symlinks for commands handled by the busybox multi-call binary such that they will use
# the cross-arch binary, and work under emulation
RUN <<eof
bash -euo pipefail -c '
mkdir -p /crossarch/bin /crossarch/usr/bin
mv /bin/busybox.static /crossarch/bin/
for i in $(echo /bin/*; echo /usr/bin/*); do
if [[ $(readlink -f "$i") != *busybox* ]]; then
continue
fi
ln -s /crossarch/bin/busybox.static /crossarch$i
done'
eof
# buildkit-test runs test suite for buildkit embedded QEMU
FROM golang:${GO_VERSION}-alpine AS buildkit-test
RUN apk add --no-cache bash bats
WORKDIR /work
COPY --from=assert . .
COPY test .
COPY --from=binaries / /usr/bin
COPY --from=alpine-crossarch /crossarch /crossarch/
RUN ./run.sh
# image builds binfmt installation image
FROM scratch AS image
COPY --from=binaries / /usr/bin/
COPY --from=binfmt /go/bin/binfmt /usr/bin/binfmt
# QEMU_PRESERVE_ARGV0 defines if argv0 is used to set the binary name
ARG QEMU_PRESERVE_ARGV0
ENV QEMU_PRESERVE_ARGV0=${QEMU_PRESERVE_ARGV0}
ENTRYPOINT [ "/usr/bin/binfmt" ]
VOLUME /tmp