Skip to content

Commit

Permalink
Add concept of native Dockerfile.
Browse files Browse the repository at this point in the history
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`).
  • Loading branch information
Alexhuszagh committed Jul 29, 2022
1 parent 557bac5 commit 25e592e
Show file tree
Hide file tree
Showing 11 changed files with 242 additions and 10 deletions.
4 changes: 4 additions & 0 deletions .changes/982.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"type": "internal",
"description": "use a generic dockerfiles for when the toolchain and image platfom match."
}
30 changes: 30 additions & 0 deletions docker/Dockerfile.native
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
FROM ubuntu:20.04
ARG DEBIAN_FRONTEND=noninteractive

COPY common.sh lib.sh /
RUN /common.sh

COPY cmake.sh /
RUN /cmake.sh

COPY xargo.sh /
RUN /xargo.sh

ARG TARGETARCH
ARG TARGETVARIANT
ARG CROSS_TRIPLE

COPY qemu.sh native-qemu.sh /
RUN /native-qemu.sh

COPY dropbear.sh /
RUN /dropbear.sh

COPY linux-image.sh native-linux-image.sh /
RUN /native-linux-image.sh

COPY linux-runner native-linux-runner /

ENV CROSS_TARGETARCH=$TARGETARCH
ENV CROSS_TARGETVARIANT=$TARGETVARIANT
ENV CARGO_TARGET_${CROSS_TRIPLE}_RUNNER="/native-linux-runner"
18 changes: 17 additions & 1 deletion docker/Dockerfile.x86_64-unknown-linux-gnu
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@ RUN /cmake.sh
COPY xargo.sh /
RUN /xargo.sh

RUN apt-get update && apt-get install --assume-yes --no-install-recommends \
g++-x86-64-linux-gnu \
libc6-dev-amd64-cross

COPY deny-debian-packages.sh /
RUN TARGET_ARCH=amd64 /deny-debian-packages.sh \
binutils \
binutils-x86-64-linux-gnu

COPY qemu.sh /
RUN /qemu.sh x86_64 softmmu

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

COPY linux-runner /

ENV CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER="/linux-runner x86_64"
ENV CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=x86_64-linux-gnu-gcc \
CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER="/linux-runner x86_64" \
CC_x86_64_unknown_linux_gnu=x86_64-linux-gnu-gcc \
CXX_x86_64_unknown_linux_gnu=x86_64-linux-gnu-g++ \
BINDGEN_EXTRA_CLANG_ARGS_x86_64_unknown_linux_gnu="--sysroot=/usr/x86_64-linux-gnu" \
QEMU_LD_PREFIX=/usr/x86_64-linux-gnu \
RUST_TEST_THREADS=1 \
PKG_CONFIG_PATH="/usr/lib/x86_64-linux-gnu/pkgconfig/:${PKG_CONFIG_PATH}"
69 changes: 69 additions & 0 deletions docker/lib.sh
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,72 @@ download_gcc() {

download_mirrors "gcc/gcc-${version}" "${filename}" "${GNU_MIRRORS[@]}"
}

docker_to_qemu_arch() {
local arch="${1}"
case "${arch}" in
arm64)
echo "aarch64"
;;
386)
echo "i386"
;;
amd64)
echo "x86_64"
;;
arm|ppc64le|riscv64|s390x)
echo "${arch}"
;;
*)
echo "Unknown Docker image architecture, got \"${arch}\"." >&2
exit 1
;;
esac
}

docker_to_linux_arch() {
# variant may not be provided
local oldstate
oldstate="$(set +o)"
set +u

local arch="${1}"
local variant="${2}"
case "${arch}" in
arm64)
echo "aarch64"
;;
386)
echo "i686"
;;
amd64)
echo "x86_64"
;;
ppc64le)
echo "powerpc64le"
;;
arm)
case "${variant}" in
v6)
echo "arm"
;;
""|v7)
echo "armv7"
;;
*)
echo "Unknown Docker image variant, got \"${variant}\"." >&2
exit 1
;;
esac
;;
riscv64|s390x)
echo "${arch}"
;;
*)
echo "Unknown Docker image architecture, got \"${arch}\"." >&2
exit 1
;;
esac

eval "${oldstate}"
}
18 changes: 11 additions & 7 deletions docker/linux-image.sh
Original file line number Diff line number Diff line change
Expand Up @@ -165,12 +165,14 @@ main() {
sharutils \
gnupg

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

# Download packages
mv /etc/apt/sources.list /etc/apt/sources.list.bak
mv /etc/apt/sources.list.d /etc/apt/sources.list.d.bak
echo -e "${debsource}" > /etc/apt/sources.list

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

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

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

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

Expand Down
16 changes: 16 additions & 0 deletions docker/native-linux-image.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/usr/bin/env bash

set -x
set -eo pipefail

# shellcheck disable=SC1091
. lib.sh

main() {
local arch
arch=$(docker_to_linux_arch "${TARGETARCH}" "${TARGETVARIANT}")
/linux-image.sh "${arch}"
rm "${0}"
}

main "${@}"
14 changes: 14 additions & 0 deletions docker/native-linux-runner
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/usr/bin/env bash

set -eo pipefail

# shellcheck disable=SC1091
. lib.sh

main() {
local arch
arch=$(docker_to_linux_arch "${CROSS_TARGETARCH}" "${CROSS_TARGETVARIANT}")
exec /linux-runner "${arch}" "${@}"
}

main "${@}"
16 changes: 16 additions & 0 deletions docker/native-qemu.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/usr/bin/env bash

set -x
set -euo pipefail

# shellcheck disable=SC1091
. lib.sh

main() {
local arch
arch=$(docker_to_qemu_arch "${TARGETARCH}")
/qemu.sh "${arch}" softmmu
rm "${0}"
}

main "${@}"
1 change: 1 addition & 0 deletions xtask/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
[package]
build = "src/build.rs"
documentation = "https://github.com/cross-rs/cross"
license = "MIT OR Apache-2.0"
name = "xtask"
Expand Down
5 changes: 5 additions & 0 deletions xtask/src/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
fn main() {
let target = std::env::var("TARGET").expect("rustc must set the TARGET environment variable");
println!("cargo:rustc-cfg=cross_triple=\"{target}\"",);
println!("cargo:rustc-env=CROSS_TRIPLE=\"{target}\"",);
}
61 changes: 59 additions & 2 deletions xtask/src/build_docker_image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ pub fn build_docker_image(
platform
};

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

docker_build.args(&["--platform", &platform.docker_platform()]);
// add our platform, and determine if we need to use a native docker image
let docker_platform = platform.docker_platform();
let mut dockerfile = dockerfile.clone();
docker_build.args(&["--platform", &docker_platform]);
docker_build.args(&[
"--build-arg",
&format!("CROSS_TRIPLE={}", env!("CROSS_TRIPLE")),
]);
if target.sub.is_none() && is_native(docker_platform.as_str(), target, msg_info)? {
println!("is_native");
dockerfile = native_dockerfile.clone();
}

if push {
docker_build.arg("--push");
Expand Down Expand Up @@ -259,7 +271,7 @@ pub fn build_docker_image(
),
]);

docker_build.args(&["-f", dockerfile]);
docker_build.args(&["-f", &dockerfile]);

if gha || progress == "plain" {
docker_build.args(&["--progress", "plain"]);
Expand Down Expand Up @@ -321,6 +333,51 @@ pub fn build_docker_image(
Ok(())
}

fn is_armv6() -> bool {
cfg!(any(
cross_triple = "arm-unknown-linux-gnueabi",
cross_triple = "arm-unknown-linux-musleabi"
))
}

fn is_armv7() -> bool {
cfg!(any(
cross_triple = "armv7-unknown-linux-gnueabihf",
cross_triple = "armv7-unknown-linux-musleabihf"
))
}

fn is_native(
platform: &str,
target: &crate::ImageTarget,
msg_info: &mut MessageInfo,
) -> cross::Result<bool> {
Ok(match target.sub {
Some(_) => false,
None => match (platform, target.name.as_str()) {
("linux/386", "i686-unknown-linux-gnu")
| ("linux/amd64", "x86_64-unknown-linux-gnu")
| ("linux/arm64" | "linux/arm64/v8", "aarch64-unknown-linux-gnu")
| ("linux/ppc64le", "powerpc64le-unknown-linux-gnu")
| ("linux/riscv64", "riscv64gc-unknown-linux-gnu")
| ("linux/s390x", "s390x-unknown-linux-gnu") => true,
("linux/arm/v6", "arm-unknown-linux-gnueabi") if is_armv6() => {
note_host_target_detection(msg_info)?;
true
}
("linux/arm" | "linux/arm/v7", "armv7-unknown-linux-gnueabihf") if is_armv7() => {
note_host_target_detection(msg_info)?;
true
}
_ => false,
},
})
}

fn note_host_target_detection(msg_info: &mut MessageInfo) -> cross::Result<()> {
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.")
}

pub fn determine_image_name(
target: &crate::ImageTarget,
repository: &str,
Expand Down

0 comments on commit 25e592e

Please sign in to comment.