Skip to content

Commit

Permalink
Initial implementation
Browse files Browse the repository at this point in the history
cross-llvm is a tool for easy cross (but also native) builds using LLVM
(clang, Rust).

It consists of:

- Container images which provide the toolchains for each target.
- A CLI tool, which is a wrapper about a container engine (Docker,
  podman) and allows easy execution of the toolchain.

Provided container images can be used with https://github.com/cross-rs/cross
  • Loading branch information
vadorovsky committed Oct 26, 2024
1 parent a6cf419 commit 49c1ef8
Show file tree
Hide file tree
Showing 19 changed files with 784 additions and 1 deletion.
2 changes: 2 additions & 0 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[alias]
xtask = "run --package xtask --"
86 changes: 86 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
name: CI

on:
push:
branches:
- main
pull_request:
branches:
- main
schedule:
- cron: 00 4 * * *

env:
CARGO_TERM_COLOR: always

jobs:
lint-stable:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- uses: dtolnay/rust-toolchain@master
with:
toolchain: stable
components: clippy, rust-src

- name: Run clippy
run: cargo clippy --all-targets --workspace -- --deny warnings

lint-nightly:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- uses: dtolnay/rust-toolchain@master
with:
toolchain: nightly
components: rustfmt, rust-src

- name: Check formatting
run: cargo fmt --all -- --check

build-container-image:
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
include:
- target: aarch64-unknown-linux-gnu
type: cross
- target: aarch64-unknown-linux-musl
type: cross
- target: riscv64gc-unknown-linux-gnu
type: cross
- target: x86_64-unknown-linux-gnu
type: native
- target: x86_64-unknown-linux-musl
type: native
name: container ${{ matrix.type }} ${{ matrix.target }}
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable

- name: Log in to GitHub Container Registry
run: |
set -euxo pipefail
echo "${{ secrets.GITHUB_TOKEN }}" | \
docker login ghcr.io -u ${{ github.actor }} --password-stdin
- name: Build container image
if: github.ref == 'refs/heads/main'
run: |
cargo xtask build-container-image \
--tag ghcr.io/${{ github.repository }}/${{ matrix.type }}-${{ matrix.target }}:latest \
--target ${{ matrix.target }} \
--push
- name: Build container image
if: github.ref != 'refs/heads/main'
run: |
cargo xtask build-container-image \
--tag ghcr.io/${{ github.repository }}/${{ matrix.type }}-${{ matrix.target }}:${{ github.head_ref }} \
--target ${{ matrix.target }} \
--push
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,8 @@ Cargo.lock
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
#.idea/

# Added by cargo

/target
16 changes: 16 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[workspace]
members = [
"cross-llvm",
"xtask",
]

[workspace.dependencies]
anyhow = "1.0.89"
chrono = "0.4"
clap = { version = "4.5", features = ["derive"] }
target-lexicon = "0.12"
thiserror = { version = "1.0.64" }
uuid = { version = "1.10", features = ["v4"] }
which = "6.0"

cross-llvm = { path = "cross-llvm" }
36 changes: 36 additions & 0 deletions containers/Dockerfile.cross-aarch64-unknown-linux-gnu
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
FROM docker.io/debian:bookworm

ENV PATH="/root/.cargo/bin:/usr/lib/llvm-18/bin:${PATH}"

# Even though we are using clang as a C compiler, we need the libgcc_s and
# libstdc++.
RUN dpkg --add-architecture arm64 \
&& apt update \
&& apt install -y \
build-essential \
cmake \
curl \
gcc-aarch64-linux-gnu \
g++-aarch64-linux-gnu \
gnupg \
libc6-dev-arm64-cross \
libzstd-dev \
libzstd-dev:arm64 \
lsb-release \
ninja-build \
qemu-user \
software-properties-common \
wget \
zlib1g-dev \
zlib1g-dev:arm64 \
&& wget https://apt.llvm.org/llvm.sh \
&& chmod +x llvm.sh \
&& ./llvm.sh 18 \
&& rm -f llvm.sh \
&& curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y \
&& rustup toolchain install stable --component rust-src \
&& rustup toolchain install nightly --component rust-src \
&& rustup target add aarch64-unknown-linux-gnu \
&& rustup +nightly target add aarch64-unknown-linux-gnu \
&& cargo install btfdump \
&& rm -rf /var/lib/apt/lists/*
76 changes: 76 additions & 0 deletions containers/Dockerfile.cross-aarch64-unknown-linux-musl
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
FROM docker.io/gentoo/stage3:musl-llvm

ENV PATH="/root/.cargo/bin:/usr/lib/llvm/18/bin:${PATH}"
# Install only aarch64 user-space wrapper when installing app-emulation/qemu.
ENV QEMU_USER_TARGETS="aarch64"
# Enable static libraries for installed packages (zstd, zlib etc.).
ENV USE="static-libs"

# Use clang-musl-overlay patches[0], needed for QEMU to build successfully.
#
# Install llvm-libgcc, which is a drop-in replacement for libgcc_s runtime
# library. It's needed by Rust binaries provided by rustup[1][2]. It's provided
# in vadorovsky's private overlay.
#
# Create a cross sysroot using crossdev[3], which also creates wrappers for:
# - clang, which can be used for compiling C/C++ projects without doing the
# whole dance with `--target` and `--sysroot` arguments.
# - emerge, which let you install packages in the cross sysroot.
#
# Unpack the stage3 tarball into that sysroot to avoiding compilation of the
# whole base system from scratch. Otherwise,
# `emerge-aarch64-unknown-linux-musl @system` would take an eternity to run on
# free GitHub runners.
#
# Patch the clang config to use libc++ and libunwind, before the necessary fix
# in crossdev gets released[4].
#
# [0] https://github.com/clang-musl-overlay/gentoo-patchset
# [1] https://github.com/rust-lang/rust/issues/119504
# [2] https://github.com/rust-lang/rustup/issues/2213#issuecomment-1888615413
# [3] https://wiki.gentoo.org/wiki/Crossdev
# [4] https://github.com/gentoo/crossdev/pull/23
RUN emerge --sync --quiet \
&& emerge \
app-eselect/eselect-repository \
dev-vcs/git \
sys-devel/crossdev \
&& eselect repository add vadorovsky git \
https://gitlab.com/vadorovsky/overlay \
&& git clone --depth 1 \
https://github.com/clang-musl-overlay/gentoo-patchset \
/etc/portage/patches \
&& emerge --sync --quiet \
&& emerge \
app-emulation/qemu \
sys-libs/llvm-libgcc \
&& eselect repository create crossdev \
&& crossdev --llvm --target aarch64-unknown-linux-musl \
&& curl -L "https://ftp-osl.osuosl.org/pub/gentoo/releases/arm64/autobuilds/current-stage3-arm64-musl-llvm/$(\
curl -L "https://ftp-osl.osuosl.org/pub/gentoo/releases/arm64/autobuilds/current-stage3-arm64-musl-llvm/latest-stage3-arm64-musl-llvm.txt" | \
grep tar.xz | cut -d ' ' -f 1)" | \
tar -xJpf - -C /usr/aarch64-unknown-linux-musl --exclude=dev --skip-old-files \
&& ln -s \
/etc/portage/repos.conf \
/usr/aarch64-unknown-linux-musl/etc/portage/repos.conf \
&& PORTAGE_CONFIGROOT=/usr/aarch64-unknown-linux-musl eselect profile set \
default/linux/arm64/23.0/musl/llvm \
&& sed -i -e "s/--unwindlib=none/--unwindlib=libunwind/" \
/etc/clang/cross/aarch64-unknown-linux-musl.cfg \
&& echo "--stdlib=libc++" >> \
/etc/clang/cross/aarch64-unknown-linux-musl.cfg \
&& aarch64-unknown-linux-musl-emerge --sync --quiet \
&& aarch64-unknown-linux-musl-emerge \
app-arch/zstd \
sys-libs/llvm-libgcc \
sys-libs/zlib \
&& curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y \
&& rustup toolchain install stable --component rust-src \
&& rustup toolchain install nightly --component rust-src \
&& rustup target add aarch64-unknown-linux-musl \
&& rustup +nightly target add aarch64-unknown-linux-musl \
&& cargo install btfdump \
&& rm -rf \
/var/cache/binpkgs/* \
/var/cache/distfiles/* \
/var/tmp/portage/*
45 changes: 45 additions & 0 deletions containers/Dockerfile.cross-riscv64gc-unknown-linux-gnu
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# NOTE(vadorovsky): Debian bookworm (stable) doesn't provide risv64 builds of
# libzstd-dev.[0]
#
# Debian trixie (testing) provides all riscv64 we need, but it doesn't provide
# `software-properties-common`, while stable versions and Debian sid (unstable)
# provide it.[1] Don't ask me why, let's just stick to sid. ¯\_(ツ)_/¯
#
# [0] https://packages.debian.org/search?keywords=libzstd-dev
# [1] https://packages.debian.org/search?keywords=software-properties-common
FROM docker.io/debian:sid

ENV PATH="/root/.cargo/bin:/usr/lib/llvm-18/bin:${PATH}"

# Even though we are using clang as a C compiler, we need the libgcc_s and
# libstdc++.
RUN dpkg --add-architecture riscv64 \
&& apt update \
&& apt install -y \
build-essential \
cmake \
curl \
gcc-riscv64-linux-gnu \
g++-riscv64-linux-gnu \
gnupg \
libc6-dev-riscv64-cross \
libzstd-dev \
libzstd-dev:riscv64 \
lsb-release \
ninja-build \
qemu-user \
software-properties-common \
wget \
zlib1g-dev \
zlib1g-dev:riscv64 \
&& wget https://apt.llvm.org/llvm.sh \
&& chmod +x llvm.sh \
&& ./llvm.sh 18 \
&& rm -f llvm.sh \
&& curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y \
&& rustup toolchain install stable --component rust-src \
&& rustup toolchain install nightly --component rust-src \
&& rustup target add riscv64gc-unknown-linux-gnu \
&& rustup +nightly target add riscv64gc-unknown-linux-gnu \
&& cargo install btfdump \
&& rm -rf /var/lib/apt/lists/*
25 changes: 25 additions & 0 deletions containers/Dockerfile.native-x86_64-unknown-linux-gnu
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
FROM docker.io/debian:bookworm

ENV PATH="/root/.cargo/bin:/usr/lib/llvm-18/bin:${PATH}"

RUN apt update \
&& apt install -y \
build-essential \
cmake \
curl \
gnupg \
libzstd-dev \
lsb-release \
ninja-build \
software-properties-common \
wget \
zlib1g-dev \
&& wget https://apt.llvm.org/llvm.sh \
&& chmod +x llvm.sh \
&& ./llvm.sh 18 \
&& rm -f llvm.sh \
&& curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y \
&& rustup toolchain install stable --component rust-src \
&& rustup toolchain install nightly --component rust-src \
&& cargo install btfdump \
&& rm -rf /var/lib/apt/lists/*
28 changes: 28 additions & 0 deletions containers/Dockerfile.native-x86_64-unknown-linux-musl
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
FROM docker.io/gentoo/stage3:musl-llvm

ENV PATH="/root/.cargo/bin:/usr/lib/llvm/18/bin:${PATH}"
# Enable static libraries for installed packages (zstd, zlib etc.).
ENV USE="static-libs"

# Install llvm-libgcc, which is a drop-in replacement for libgcc_s runtime
# library. It's needed by Rust binaries provided by rustup[0][1].
#
# [0] https://github.com/rust-lang/rust/issues/119504
# [1] https://github.com/rust-lang/rustup/issues/2213#issuecomment-1888615413
RUN emerge --sync --quiet \
&& emerge \
app-arch/zstd \
app-eselect/eselect-repository \
dev-vcs/git \
sys-libs/zlib \
&& eselect repository add vadorovsky git https://gitlab.com/vadorovsky/overlay \
&& emerge --sync --quiet \
&& emerge sys-libs/llvm-libgcc \
&& curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y \
&& rustup toolchain install stable --component rust-src \
&& rustup toolchain install nightly --component rust-src \
&& cargo install btfdump \
&& rm -rf \
/var/cache/binpkgs/* \
/var/cache/distfiles/* \
/var/tmp/portage/*
14 changes: 14 additions & 0 deletions cross-llvm/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "cross-llvm"
version = "0.1.0"
edition = "2021"

[dependencies]
anyhow = { workspace = true }
clap = { workspace = true }
target-lexicon = { workspace = true }
thiserror = { workspace = true }
which = { workspace = true }

[[bin]]
name = "cross-llvm"
26 changes: 26 additions & 0 deletions cross-llvm/src/bin/cross-llvm.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use clap::{Parser, Subcommand};

use cross_llvm::run::{run, Run};

/// Containerized (cross, but not only) LLVM toolchains.
#[derive(Parser)]
#[command(author, version, about, long_about = None)]
struct Cli {
/// Subcommands
#[command(subcommand)]
command: Commands,
}

#[derive(Subcommand)]
enum Commands {
/// Run a custom command.
Run(Run),
}

fn main() -> anyhow::Result<()> {
let cli = Cli::parse();

match cli.command {
Commands::Run(args) => run(args),
}
}
Loading

0 comments on commit 49c1ef8

Please sign in to comment.