Skip to content

Commit 25e592e

Browse files
committed
Add concept of native Dockerfile.
Generalizes the creation of toolchains where the image platform and the toolchain target match, rather than hard-code only using a native toolchain targeting `x86_64-unknown-linux-gnu` (which fails if the image platform is not `linux/amd64`).
1 parent 557bac5 commit 25e592e

11 files changed

+242
-10
lines changed

.changes/982.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type": "internal",
3+
"description": "use a generic dockerfiles for when the toolchain and image platfom match."
4+
}

docker/Dockerfile.native

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
FROM ubuntu:20.04
2+
ARG DEBIAN_FRONTEND=noninteractive
3+
4+
COPY common.sh lib.sh /
5+
RUN /common.sh
6+
7+
COPY cmake.sh /
8+
RUN /cmake.sh
9+
10+
COPY xargo.sh /
11+
RUN /xargo.sh
12+
13+
ARG TARGETARCH
14+
ARG TARGETVARIANT
15+
ARG CROSS_TRIPLE
16+
17+
COPY qemu.sh native-qemu.sh /
18+
RUN /native-qemu.sh
19+
20+
COPY dropbear.sh /
21+
RUN /dropbear.sh
22+
23+
COPY linux-image.sh native-linux-image.sh /
24+
RUN /native-linux-image.sh
25+
26+
COPY linux-runner native-linux-runner /
27+
28+
ENV CROSS_TARGETARCH=$TARGETARCH
29+
ENV CROSS_TARGETVARIANT=$TARGETVARIANT
30+
ENV CARGO_TARGET_${CROSS_TRIPLE}_RUNNER="/native-linux-runner"

docker/Dockerfile.x86_64-unknown-linux-gnu

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,15 @@ RUN /cmake.sh
1010
COPY xargo.sh /
1111
RUN /xargo.sh
1212

13+
RUN apt-get update && apt-get install --assume-yes --no-install-recommends \
14+
g++-x86-64-linux-gnu \
15+
libc6-dev-amd64-cross
16+
17+
COPY deny-debian-packages.sh /
18+
RUN TARGET_ARCH=amd64 /deny-debian-packages.sh \
19+
binutils \
20+
binutils-x86-64-linux-gnu
21+
1322
COPY qemu.sh /
1423
RUN /qemu.sh x86_64 softmmu
1524

@@ -21,4 +30,11 @@ RUN /linux-image.sh x86_64
2130

2231
COPY linux-runner /
2332

24-
ENV CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER="/linux-runner x86_64"
33+
ENV CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=x86_64-linux-gnu-gcc \
34+
CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER="/linux-runner x86_64" \
35+
CC_x86_64_unknown_linux_gnu=x86_64-linux-gnu-gcc \
36+
CXX_x86_64_unknown_linux_gnu=x86_64-linux-gnu-g++ \
37+
BINDGEN_EXTRA_CLANG_ARGS_x86_64_unknown_linux_gnu="--sysroot=/usr/x86_64-linux-gnu" \
38+
QEMU_LD_PREFIX=/usr/x86_64-linux-gnu \
39+
RUST_TEST_THREADS=1 \
40+
PKG_CONFIG_PATH="/usr/lib/x86_64-linux-gnu/pkgconfig/:${PKG_CONFIG_PATH}"

docker/lib.sh

100644100755
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,3 +86,72 @@ download_gcc() {
8686

8787
download_mirrors "gcc/gcc-${version}" "${filename}" "${GNU_MIRRORS[@]}"
8888
}
89+
90+
docker_to_qemu_arch() {
91+
local arch="${1}"
92+
case "${arch}" in
93+
arm64)
94+
echo "aarch64"
95+
;;
96+
386)
97+
echo "i386"
98+
;;
99+
amd64)
100+
echo "x86_64"
101+
;;
102+
arm|ppc64le|riscv64|s390x)
103+
echo "${arch}"
104+
;;
105+
*)
106+
echo "Unknown Docker image architecture, got \"${arch}\"." >&2
107+
exit 1
108+
;;
109+
esac
110+
}
111+
112+
docker_to_linux_arch() {
113+
# variant may not be provided
114+
local oldstate
115+
oldstate="$(set +o)"
116+
set +u
117+
118+
local arch="${1}"
119+
local variant="${2}"
120+
case "${arch}" in
121+
arm64)
122+
echo "aarch64"
123+
;;
124+
386)
125+
echo "i686"
126+
;;
127+
amd64)
128+
echo "x86_64"
129+
;;
130+
ppc64le)
131+
echo "powerpc64le"
132+
;;
133+
arm)
134+
case "${variant}" in
135+
v6)
136+
echo "arm"
137+
;;
138+
""|v7)
139+
echo "armv7"
140+
;;
141+
*)
142+
echo "Unknown Docker image variant, got \"${variant}\"." >&2
143+
exit 1
144+
;;
145+
esac
146+
;;
147+
riscv64|s390x)
148+
echo "${arch}"
149+
;;
150+
*)
151+
echo "Unknown Docker image architecture, got \"${arch}\"." >&2
152+
exit 1
153+
;;
154+
esac
155+
156+
eval "${oldstate}"
157+
}

docker/linux-image.sh

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -165,12 +165,14 @@ main() {
165165
sharutils \
166166
gnupg
167167

168-
# amd64 has conflicting versions of the packages installed, so
168+
# image arch has conflicting versions of the packages installed, so
169169
# we need to remove the system installs later. since apt relies
170170
# on these packages, we need to download them and reinstall
171171
# using dpkg later, since we cannot redownload via apt.
172+
local image_arch
173+
image_arch=$(dpkg --print-architecture)
172174
local libgcc_packages=("${libgcc}:${arch}" "libstdc++6:${arch}")
173-
if [[ "${arch}" == "amd64" ]]; then
175+
if [[ "${arch}" == "${image_arch}" ]]; then
174176
local libgcc_root=/qemu/libgcc
175177
mkdir -p "${libgcc_root}"
176178
pushd "${libgcc_root}"
@@ -180,6 +182,7 @@ main() {
180182

181183
# Download packages
182184
mv /etc/apt/sources.list /etc/apt/sources.list.bak
185+
mv /etc/apt/sources.list.d /etc/apt/sources.list.d.bak
183186
echo -e "${debsource}" > /etc/apt/sources.list
184187

185188
# Old ubuntu does not support --add-architecture, so we directly change multiarch file
@@ -234,10 +237,10 @@ main() {
234237
ncurses-base"${ncurses}" \
235238
"zlib1g:${arch}"
236239

237-
if [[ "${arch}" != "amd64" ]]; then
240+
if [[ "${arch}" != "${image_arch}" ]]; then
238241
apt-get -d --no-install-recommends download "${libgcc_packages[@]}"
239242
else
240-
# amd64 has conflicting versions of the packages installed
243+
# host arch has conflicting versions of the packages installed
241244
# this prevents us from downloading them, so we need to
242245
# simply grab the last version from the debian sources.
243246
# we're search for a paragraph with:
@@ -374,7 +377,7 @@ EOF
374377
find . | cpio --create --format='newc' --quiet | gzip > ../initrd.gz
375378
cd -
376379

377-
if [[ "${arch}" == "amd64" ]]; then
380+
if [[ "${arch}" == "${image_arch}" ]]; then
378381
# need to reinstall these packages, since basic utilities rely on them.
379382
pushd "${libgcc_root}"
380383
dpkg -i --force-depends "${libgcc_root}"/*.deb
@@ -385,15 +388,16 @@ EOF
385388
# Clean up
386389
rm -rf "/qemu/${root}" "/qemu/${arch}"
387390
mv -f /etc/apt/sources.list.bak /etc/apt/sources.list
391+
mv -f /etc/apt/sources.list.d.bak /etc/apt/sources.list.d
388392
if [ -f /etc/dpkg/dpkg.cfg.d/multiarch.bak ]; then
389393
mv /etc/dpkg/dpkg.cfg.d/multiarch.bak /etc/dpkg/dpkg.cfg.d/multiarch
390394
fi
391-
# can fail if arch is used (amd64 and/or i386)
395+
# can fail if arch is used (image arch, such as amd64 and/or i386)
392396
dpkg --remove-architecture "${arch}" || true
393397
apt-get update
394398

395399
# need to reinstall the removed libgcc packages, which are required for apt
396-
if [[ "${arch}" == "amd64" ]]; then
400+
if [[ "${arch}" == "${image_arch}" ]]; then
397401
apt-get install --no-install-recommends --assume-yes "${packages[@]}"
398402
fi
399403

docker/native-linux-image.sh

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#!/usr/bin/env bash
2+
3+
set -x
4+
set -eo pipefail
5+
6+
# shellcheck disable=SC1091
7+
. lib.sh
8+
9+
main() {
10+
local arch
11+
arch=$(docker_to_linux_arch "${TARGETARCH}" "${TARGETVARIANT}")
12+
/linux-image.sh "${arch}"
13+
rm "${0}"
14+
}
15+
16+
main "${@}"

docker/native-linux-runner

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/usr/bin/env bash
2+
3+
set -eo pipefail
4+
5+
# shellcheck disable=SC1091
6+
. lib.sh
7+
8+
main() {
9+
local arch
10+
arch=$(docker_to_linux_arch "${CROSS_TARGETARCH}" "${CROSS_TARGETVARIANT}")
11+
exec /linux-runner "${arch}" "${@}"
12+
}
13+
14+
main "${@}"

docker/native-qemu.sh

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#!/usr/bin/env bash
2+
3+
set -x
4+
set -euo pipefail
5+
6+
# shellcheck disable=SC1091
7+
. lib.sh
8+
9+
main() {
10+
local arch
11+
arch=$(docker_to_qemu_arch "${TARGETARCH}")
12+
/qemu.sh "${arch}" softmmu
13+
rm "${0}"
14+
}
15+
16+
main "${@}"

xtask/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
[package]
2+
build = "src/build.rs"
23
documentation = "https://github.com/cross-rs/cross"
34
license = "MIT OR Apache-2.0"
45
name = "xtask"

xtask/src/build.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
fn main() {
2+
let target = std::env::var("TARGET").expect("rustc must set the TARGET environment variable");
3+
println!("cargo:rustc-cfg=cross_triple=\"{target}\"",);
4+
println!("cargo:rustc-env=CROSS_TRIPLE=\"{target}\"",);
5+
}

xtask/src/build_docker_image.rs

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ pub fn build_docker_image(
165165
platform
166166
};
167167

168+
let native_dockerfile = docker_root.join("Dockerfile.native").to_utf8()?.to_string();
168169
let mut results = vec![];
169170
for (platform, (target, dockerfile)) in targets
170171
.iter()
@@ -179,7 +180,18 @@ pub fn build_docker_image(
179180
docker_build.args(&["buildx", "build"]);
180181
docker_build.current_dir(&docker_root);
181182

182-
docker_build.args(&["--platform", &platform.docker_platform()]);
183+
// add our platform, and determine if we need to use a native docker image
184+
let docker_platform = platform.docker_platform();
185+
let mut dockerfile = dockerfile.clone();
186+
docker_build.args(&["--platform", &docker_platform]);
187+
docker_build.args(&[
188+
"--build-arg",
189+
&format!("CROSS_TRIPLE={}", env!("CROSS_TRIPLE")),
190+
]);
191+
if target.sub.is_none() && is_native(docker_platform.as_str(), target, msg_info)? {
192+
println!("is_native");
193+
dockerfile = native_dockerfile.clone();
194+
}
183195

184196
if push {
185197
docker_build.arg("--push");
@@ -259,7 +271,7 @@ pub fn build_docker_image(
259271
),
260272
]);
261273

262-
docker_build.args(&["-f", dockerfile]);
274+
docker_build.args(&["-f", &dockerfile]);
263275

264276
if gha || progress == "plain" {
265277
docker_build.args(&["--progress", "plain"]);
@@ -321,6 +333,51 @@ pub fn build_docker_image(
321333
Ok(())
322334
}
323335

336+
fn is_armv6() -> bool {
337+
cfg!(any(
338+
cross_triple = "arm-unknown-linux-gnueabi",
339+
cross_triple = "arm-unknown-linux-musleabi"
340+
))
341+
}
342+
343+
fn is_armv7() -> bool {
344+
cfg!(any(
345+
cross_triple = "armv7-unknown-linux-gnueabihf",
346+
cross_triple = "armv7-unknown-linux-musleabihf"
347+
))
348+
}
349+
350+
fn is_native(
351+
platform: &str,
352+
target: &crate::ImageTarget,
353+
msg_info: &mut MessageInfo,
354+
) -> cross::Result<bool> {
355+
Ok(match target.sub {
356+
Some(_) => false,
357+
None => match (platform, target.name.as_str()) {
358+
("linux/386", "i686-unknown-linux-gnu")
359+
| ("linux/amd64", "x86_64-unknown-linux-gnu")
360+
| ("linux/arm64" | "linux/arm64/v8", "aarch64-unknown-linux-gnu")
361+
| ("linux/ppc64le", "powerpc64le-unknown-linux-gnu")
362+
| ("linux/riscv64", "riscv64gc-unknown-linux-gnu")
363+
| ("linux/s390x", "s390x-unknown-linux-gnu") => true,
364+
("linux/arm/v6", "arm-unknown-linux-gnueabi") if is_armv6() => {
365+
note_host_target_detection(msg_info)?;
366+
true
367+
}
368+
("linux/arm" | "linux/arm/v7", "armv7-unknown-linux-gnueabihf") if is_armv7() => {
369+
note_host_target_detection(msg_info)?;
370+
true
371+
}
372+
_ => false,
373+
},
374+
})
375+
}
376+
377+
fn note_host_target_detection(msg_info: &mut MessageInfo) -> cross::Result<()> {
378+
msg_info.note("using the rust target triple to determine the host triple to determine if the docker platform is native. this may fail if cross-compiling xtask.")
379+
}
380+
324381
pub fn determine_image_name(
325382
target: &crate::ImageTarget,
326383
repository: &str,

0 commit comments

Comments
 (0)