diff --git a/.cargo/config.toml b/.cargo/config.toml index 0f2c636..35049cb 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,11 +1,2 @@ [alias] xtask = "run --package xtask --" - -[target.x86_64-unknown-linux-gnu] -linker = "x86_64-linux-gnu-gcc" - -[target.arm-unknown-linux-musleabihf] -linker = "arm-linux-gnueabihf-gcc" - -[target.aarch64-unknown-linux-musl] -linker = "aarch64-linux-gnu-gcc" diff --git a/bakery/Dockerfile b/bakery/Dockerfile index 219b0d0..f333e72 100644 --- a/bakery/Dockerfile +++ b/bakery/Dockerfile @@ -1,67 +1,4 @@ -######################################################################################### -# Rust Build Environment -# -# The image contains everything necessary to (cross)-compile our Rust crates. -######################################################################################### -FROM debian:latest as build-env - -COPY bakery/layers/build-env/00-base.sh /tmp/rugpi-docker/00-base.sh -RUN /tmp/rugpi-docker/00-base.sh - -# Install Rust toolchain. -ENV RUSTUP_HOME="/usr/local/rustup" \ - CARGO_HOME="/usr/local/cargo" \ - PATH="/usr/local/cargo/bin:${PATH}" \ - RUST_VERSION="1.76.0" - -COPY bakery/layers/build-env/10-rust.sh /tmp/rugpi-docker/10-rust.sh -RUN /tmp/rugpi-docker/10-rust.sh - -# Install libraries and configure for cross compilation. -ENV PKG_CONFIG_SYSROOT_DIR="/" - -COPY bakery/layers/build-env/20-libs.sh /tmp/rugpi-docker/20-libs.sh -RUN /tmp/rugpi-docker/20-libs.sh - -ENV RUGPI_BUILD_ENV="true" - -WORKDIR /project -CMD /usr/bin/zsh - - -######################################################################################### -# `cargo-chef` Planner -# -# We are using `cargo-chef` to speed up builds of the image. -######################################################################################### -FROM build-env AS planner - -COPY . . -RUN cargo chef prepare --recipe-path recipe.json - - -######################################################################################### -# `cargo-chef` Builder -# -# Build all Rust crates with `cargo-chef`. -######################################################################################### -FROM build-env AS builder - -COPY --from=planner /project/recipe.json recipe.json -COPY bakery/layers/builder/00-prepare.sh /tmp/rugpi-docker/00-prepare.sh -RUN /tmp/rugpi-docker/00-prepare.sh - -COPY . . -COPY bakery/layers/builder/10-build.sh /tmp/rugpi-docker/10-build.sh -RUN /tmp/rugpi-docker/10-build.sh - - -######################################################################################### -# Rugpi Bakery Image -# -# Now combine everything in the `rugpi-bakery` image. -######################################################################################### -FROM debian:latest AS bakery +FROM debian:latest ARG TARGETPLATFORM diff --git a/bakery/layers/build-env/00-base.sh b/bakery/layers/build-env/00-base.sh deleted file mode 100755 index cbbcb0c..0000000 --- a/bakery/layers/build-env/00-base.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail - -export DEBIAN_FRONTEND=noninteractive - -apt-get -y update - -apt-get -y install \ - build-essential \ - curl \ - wget \ - zsh \ - git \ - file \ - python3 \ - python3-pip - -apt-get -y clean && rm -rf /var/lib/apt/lists/* - -wget -O /etc/zsh/zshrc https://git.grml.org/f/grml-etc-core/etc/zsh/zshrc -touch /root/.zshrc diff --git a/bakery/layers/build-env/10-rust.sh b/bakery/layers/build-env/10-rust.sh deleted file mode 100755 index 7d76811..0000000 --- a/bakery/layers/build-env/10-rust.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail - -DEBIAN_ARCH=$(dpkg --print-architecture) - -echo "Architecture: ${DEBIAN_ARCH}" - -export DEBIAN_FRONTEND=noninteractive - - -# Add `armhf` toolchain regardless of host architecture. -dpkg --add-architecture armhf -apt-get -y update -apt-get install -y gcc-arm-linux-gnueabihf libc6:armhf - - -# Add `arm64` toolchain on `amd64` only. -case "${DEBIAN_ARCH}" in - "arm64") - ;; - "amd64") - dpkg --add-architecture arm64 - apt-get -y update - apt-get -y install gcc-aarch64-linux-gnu libc6:arm64 - ;; - *) - echo "Error: Unsupported architecture \`${DEBIAN_ARCH}\`." - exit 1 - ;; -esac - - -apt-get install -y clang - -apt-get -y clean && rm -rf /var/lib/apt/lists/* - - -curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \ - | sh -s -- -y --no-modify-path --default-toolchain "${RUST_VERSION}" - -rustup target add arm-unknown-linux-musleabihf # Raspberry Pi (32-bit) -rustup target add aarch64-unknown-linux-musl # Raspberry Pi (64-bit) - -cargo install cargo-chef --locked diff --git a/bakery/layers/build-env/20-libs.sh b/bakery/layers/build-env/20-libs.sh deleted file mode 100755 index 20a3fe3..0000000 --- a/bakery/layers/build-env/20-libs.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail - -export DEBIAN_FRONTEND=noninteractive - -apt-get -y update - -apt-get -y install pkg-config - -apt-get -y clean && rm -rf /var/lib/apt/lists/* diff --git a/bakery/layers/builder/00-prepare.sh b/bakery/layers/builder/00-prepare.sh deleted file mode 100755 index 5bc77ff..0000000 --- a/bakery/layers/builder/00-prepare.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail - -cargo chef cook --release --bin rugpi-bakery --recipe-path recipe.json - -# Prepare to build binaries for both, 32-bit and 64-bit Raspberry Pi. -cargo chef cook --release --target arm-unknown-linux-musleabihf --recipe-path recipe.json -cargo chef cook --release --target aarch64-unknown-linux-musl --recipe-path recipe.json diff --git a/bakery/layers/builder/10-build.sh b/bakery/layers/builder/10-build.sh deleted file mode 100755 index d114c69..0000000 --- a/bakery/layers/builder/10-build.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail - -cargo build --release --bin rugpi-bakery - -# Build binaries for both, 32-bit and 64-bit Raspberry Pi. -cargo build --release --target arm-unknown-linux-musleabihf -cargo build --release --target aarch64-unknown-linux-musl diff --git a/xfile b/xfile old mode 100644 new mode 100755 index 64c4ff6..3b472b2 --- a/xfile +++ b/xfile @@ -1 +1,31 @@ -!cargo xtask \ No newline at end of file +#!/usr/bin/env bash + +set -euo pipefail + +DOCKER=${DOCKER:-"docker"} + +COMPOSE_FILE="./xtask/devenv/compose.yml" + +if [ $($DOCKER compose --file "$COMPOSE_FILE" ps -q | wc -l) -gt 0 ]; then + echo "Development environment is already running." +else + echo "Starting development environment." + $DOCKER compose --file "$COMPOSE_FILE" up --build -d +fi + +if [ "${1:-}" = "devenv" ]; then + shift + exec $DOCKER compose \ + --file ./xtask/devenv/compose.yml \ + "$@" +fi + +if [ "${1:-}" = "shell" ]; then + exec $DOCKER compose \ + --file ./xtask/devenv/compose.yml \ + exec --privileged devenv "/project/xtask/devenv/run.sh" zsh +fi + +exec $DOCKER compose \ + --file ./xtask/devenv/compose.yml \ + exec --privileged devenv "/project/xtask/devenv/run.sh" cargo xtask "$@" diff --git a/xtask/devenv/Dockerfile b/xtask/devenv/Dockerfile new file mode 100644 index 0000000..7676b53 --- /dev/null +++ b/xtask/devenv/Dockerfile @@ -0,0 +1,7 @@ +FROM rust:latest + +COPY xtask/devenv/setup.sh . + +RUN ./setup.sh && rm -f ./setup.sh + +WORKDIR /project diff --git a/xtask/devenv/compose.yml b/xtask/devenv/compose.yml new file mode 100644 index 0000000..7fca49b --- /dev/null +++ b/xtask/devenv/compose.yml @@ -0,0 +1,14 @@ +name: rugpi + +services: + devenv: + build: + context: ../../ + dockerfile: xtask/devenv/Dockerfile + environment: + - CARGO_HOME=/tmp/.cargo + - CARGO_TARGET_DIR=/tmp/target + volumes: + - ../../:/project + - /var/run/docker.sock:/var/run/docker.sock + entrypoint: "sleep infinity" diff --git a/xtask/devenv/run.sh b/xtask/devenv/run.sh new file mode 100755 index 0000000..832c650 --- /dev/null +++ b/xtask/devenv/run.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash + +set -euo pipefail + +export CC_x86_64_unknown_linux_musl=x86_64-linux-gnu-gcc +export CARGO_TARGET_X86_64_UNKNOWN_LINUX_MUSL_RUSTFLAGS="-Clink-self-contained=yes -Clinker=rust-lld" + +export CC_aarch64_unknown_linux_musl=aarch64-linux-gnu-gcc +export CARGO_TARGET_AARCH64_UNKNOWN_LINUX_MUSL_RUSTFLAGS="-Clink-self-contained=yes -Clinker=rust-lld" + +export CC_arm_unknown_linux_musleabihf=arm-linux-gnueabihf-gcc +export CARGO_TARGET_ARM_UNKNOWN_LINUX_MUSLEABIHF_RUSTFLAGS="-Clink-self-contained=yes -Clinker=rust-lld" + +exec "$@" diff --git a/xtask/devenv/setup.sh b/xtask/devenv/setup.sh new file mode 100755 index 0000000..2ac8730 --- /dev/null +++ b/xtask/devenv/setup.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash + +set -euo pipefail + +HOST_ARCH=$(dpkg --print-architecture) + +echo "Host Architecture: ${HOST_ARCH}" + +export DEBIAN_FRONTEND=noninteractive + +apt-get -y update + +apt-get -y install \ + build-essential \ + curl \ + file \ + git \ + python3 \ + python3-pip \ + wget \ + zsh + +wget -O /etc/zsh/zshrc https://git.grml.org/f/grml-etc-core/etc/zsh/zshrc +touch /root/.zshrc + +case "${HOST_ARCH}" in + "arm64") + apt-get -y install gcc-x86-64-linux-gnu libc6-dev-amd64-cross + ;; + "amd64") + apt-get -y install gcc-aarch64-linux-gnu libc6-dev-arm64-cross + ;; + *) + echo "Error: Unsupported architecture \`${HOST_ARCH}\`." + exit 1 + ;; +esac + +# Add `armhf` toolchain regardless of host architecture. +apt-get install -y gcc-arm-linux-gnueabihf libc6-dev-armhf-cross + +apt-get install -y musl-tools clang pkg-config docker.io + +apt-get -y clean && rm -rf /var/lib/apt/lists/* + +rustup target add arm-unknown-linux-musleabihf +rustup target add aarch64-unknown-linux-musl +rustup target add x86_64-unknown-linux-musl diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 90a3e17..b50e59e 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -22,6 +22,14 @@ pub fn project_path() -> PathBuf { path } +pub fn get_target_dir() -> PathBuf { + if let Ok(target_dir) = std::env::var("CARGO_TARGET_DIR") { + target_dir.into() + } else { + project_path().join("target") + } +} + fn main() -> anyhow::Result<()> { let args = Args::parse(); let env = LocalEnv::new(project_path()); @@ -63,7 +71,7 @@ fn main() -> anyhow::Result<()> { std::fs::remove_dir_all(&binaries_dir)?; } std::fs::create_dir_all(&binaries_dir)?; - let target_dir = project_path().join("target").join(target).join("release"); + let target_dir = get_target_dir().join(target).join("release"); for entry in std::fs::read_dir(&target_dir)? { let entry = entry?; let file_type = entry.file_type()?; @@ -76,7 +84,7 @@ fn main() -> anyhow::Result<()> { if !file_name.starts_with("rugpi-") || file_name.ends_with(".d") { continue; } - std::fs::hard_link(entry.path(), binaries_dir.join(file_name))?; + std::fs::copy(entry.path(), binaries_dir.join(file_name))?; } } }