Skip to content

Commit

Permalink
Add a zig cc-based image.
Browse files Browse the repository at this point in the history
Uses cargo-zigbuild as a backend, and adds configuration options for zig under `[build.zig]` and `[target.(...).zig]`. If enabled, and an image override is not provided, `cross` will always use the `zig` image. The feature can be enabled by providing `zig` as a table, bool, or string.

It supports custom glibc versions by passing the `zig.version` key, and `zig` can be separately enabled or disabled by providing `zig.enable`.

```
[target.x86_64-unknown-linux-gnu.zig]
enable = true       # enable use of the zig image
version = "2.17"    # glibc version to use
image = "ghcr.io/cross-rs/zig:local"    # custom image to use
```

If provided as a bool, it will use the default glibc version:

```
[target.x86_64-unknown-linux-gnu]
\# equivalent to { enable = true }
zig = true
```

If provided as a string, `zig` will be automatically enabled:

```
[target.x86_64-unknown-linux-gnu]
\# equivalent to { enable = true, version = "2.17" }
zig = "2.17"
```

The image does not provide runners, `bindgen` Clang args, or `pkg-config` paths, since `zig cc` does not provide the dynamic library loader (`ld-linux*.so`) required, meaning none of the binaries can be run. For `bindgen`, `zig cc` has an unusual directory structure, so there is no traditional sysroot with `usr`, `lib`, and `include` subdirectories. Finally, since we don't have system packages we can work with, exporting a `pkg-config` path makes little sense.
  • Loading branch information
Alexhuszagh committed Jul 16, 2022
1 parent a82b90b commit 1e8446f
Show file tree
Hide file tree
Showing 16 changed files with 738 additions and 46 deletions.
5 changes: 5 additions & 0 deletions .changes/880.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"description": "added a zig-based image, allowing multiple targets to be built from the same image, using cargo-zigbuild.",
"type": "added",
"issues": [860]
}
6 changes: 6 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ jobs:
- { target: thumbv7em-none-eabihf, os: ubuntu-latest, std: 1 }
- { target: thumbv7m-none-eabi, os: ubuntu-latest, std: 1 }
- { target: cross, os: ubuntu-latest }
- { target: zig, os: ubuntu-latest }
build:
name: target (${{ matrix.pretty }},${{ matrix.os }})
Expand Down Expand Up @@ -302,6 +303,11 @@ jobs:
target: ${{ matrix.target }}
image: ${{ steps.build-docker-image.outputs.image }}

- name: Test Zig Image
if: steps.prepare-meta.outputs.has-image && steps.prepare-meta.outputs.test-variant == 'zig'
run: ./ci/test-zig-image.sh
shell: bash

- name: Test Cross Image
if: steps.prepare-meta.outputs.has-image && steps.prepare-meta.outputs.test-variant == 'cross'
run: ./ci/test-cross-image.sh
Expand Down
55 changes: 55 additions & 0 deletions ci/test-zig-image.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#!/usr/bin/env bash
# shellcheck disable=SC2086,SC1091,SC1090

set -x
set -eo pipefail

# NOTE: "${@}" is an unbound variable for bash 3.2, which is the
# installed version on macOS. likewise, "${var[@]}" is an unbound
# error if var is an empty array.

ci_dir=$(dirname "${BASH_SOURCE[0]}")
ci_dir=$(realpath "${ci_dir}")
project_home=$(dirname "${ci_dir}")
. "${ci_dir}"/shared.sh

# zig cc is very slow: only use a few targets.
TARGETS=(
"aarch64-unknown-linux-gnu"
"aarch64-unknown-linux-musl"
"i586-unknown-linux-gnu"
"i586-unknown-linux-musl"
)

# on CI, it sets `CROSS_TARGET_ZIG_IMAGE` rather than `CROSS_TARGET_ZIG_IMAGE`
if [[ -n "${CROSS_TARGET_ZIG_IMAGE}" ]]; then
export CROSS_BUILD_ZIG_IMAGE="${CROSS_TARGET_ZIG_IMAGE}"
unset CROSS_TARGET_ZIG_IMAGE
fi

main() {
export CROSS_BUILD_ZIG=1

local td=
local target=

retry cargo fetch
cargo build
export CROSS="${project_home}/target/debug/cross"

td="$(mktemp -d)"
git clone --depth 1 https://github.com/cross-rs/rust-cpp-hello-word "${td}"
pushd "${td}"

for target in "${TARGETS[@]}"; do
"${CROSS}" build --target "${target}" --verbose
# note: ensure #724 doesn't replicate during CI.
# https://github.com/cross-rs/cross/issues/724
cargo clean
done

popd
rm -rf "${td}"
}

main "${@}"
22 changes: 22 additions & 0 deletions docker/Dockerfile.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
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 TARGETPLATFORM
COPY zig.sh /
RUN /zig.sh $TARGETPLATFORM

# we don't export `BINDGEN_EXTRA_CLANG_ARGS`, `QEMU_LD_PREFIX`, or
# `PKG_CONFIG_PATH` since zig doesn't have a traditional sysroot structure,
# and we're not using standard, shared packages. none of the packages
# have runners either, since they do not ship with the required
# dynamic linker (`ld-linux-${arch}.so`).
ENV PATH=$PATH:/opt/zig
197 changes: 197 additions & 0 deletions docker/zig.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
#!/usr/bin/env bash

set -x
set -eo pipefail

# shellcheck disable=SC1091
. lib.sh

main() {
local platform="${1}"
install_packages ca-certificates curl xz-utils

install_zig "${platform}"
install_zigbuild "${platform}"

purge_packages
rm "${0}"
}

install_zig() {
local platform="${1}"
local version="0.9.1"
local dst="/opt/zig"
local arch=
local os=
local triple=

case "${platform}" in
'linux/386')
arch="i386"
os="linux"
;;
'linux/amd64')
arch="x86_64"
os="linux"
;;
'linux/arm64')
arch="aarch64"
os="linux"
;;
'linux/riscv64')
arch="riscv64"
os="linux"
;;
'linux/ppc64le')
triple="powerpc64le-linux-gnu"
;;
'linux/s390x')
triple="s390x-linux-gnu"
;;
'darwin/amd64')
arch="x86_64"
os="macos"
;;
'darwin/arm64')
arch="aarch64"
os="macos"
;;
# NOTE: explicitly don't support linux/arm/v6
*)
echo "Unsupported target platform '${platform}'" 1>&2
exit 1
;;
esac

if [[ -n "${arch}" ]]; then
install_zig_tarball "${arch}" "${os}" "${version}" "${dst}"
else
install_zig_source "${triple}" "${version}" "${dst}"
fi
}

install_zig_tarball() {
local arch="${1}"
local os="${2}"
local version="${3}"
local dst="${4}"
local filename="zig-${os}-${arch}-${version}.tar.xz"

local td
td="$(mktemp -d)"

pushd "${td}"

curl --retry 3 -sSfL "https://ziglang.org/download/${version}/${filename}" -O
mkdir -p "${dst}"
tar --strip-components=1 -xJf "${filename}" --directory "${dst}"

popd

rm -rf "${td}"
}

install_zig_source() {
local triple="${1}"
local version="${2}"
local dst="${3}"
local filename="zig-bootstrap-${version}.tar.xz"

local td
td="$(mktemp -d)"

pushd "${td}"

curl --retry 3 -sSfL "https://ziglang.org/download/${version}/${filename}" -O
mkdir zig
tar --strip-components=1 -xJf "${filename}" --directory zig

pushd zig
install_packages python3 make g++
./build -j5 "${triple}" native
mv "out/zig-${triple}-native" /opt/zig

popd
popd

rm -rf "${td}"
}

install_zigbuild() {
local platform="${1}"
local version=0.11.0
local dst="/usr/local"
local triple=

# we don't know if `linux/arm/v7` is hard-float,
# and we don't know the the zigbuild `apple-darwin`
# target doesn't manually specify the architecture.
case "${platform}" in
'linux/386')
triple="i686-unknown-linux-musl"
;;
'linux/amd64')
triple="x86_64-unknown-linux-musl"
;;
'linux/arm64')
triple="aarch64-unknown-linux-musl"
;;
*)
;;
esac

if [[ -n "${triple}" ]]; then
install_zigbuild_tarball "${triple}" "${version}" "${dst}"
else
install_zigbuild_source "${version}" "${dst}"
fi
}

install_zigbuild_tarball() {
local triple="${1}"
local version="${2}"
local dst="${3}"
local repo="https://github.com/messense/cargo-zigbuild"
local filename="cargo-zigbuild-v${version}.${triple}.tar.gz"

local td
td="$(mktemp -d)"

pushd "${td}"

curl --retry 3 -sSfL "${repo}/releases/download/v${version}/${filename}" -O
mkdir -p "${dst}/bin"
tar -xzf "${filename}" --directory "${dst}/bin"

popd

rm -rf "${td}"
}

install_zigbuild_source() {
local version="${1}"
local dst="${2}"

local td
td="$(mktemp -d)"

pushd "${td}"

export RUSTUP_HOME="${td}/rustup"
export CARGO_HOME="${td}/cargo"

curl --retry 3 -sSfL https://sh.rustup.rs -o rustup-init.sh
sh rustup-init.sh -y --no-modify-path --profile minimal

PATH="${CARGO_HOME}/bin:${PATH}" \
cargo install cargo-zigbuild \
--version "${version}" \
--root "${dst}" \
--locked

popd

rm -rf "${td}"
}

main "${@}"
24 changes: 24 additions & 0 deletions docs/cross_toml.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ The `target` key allows you to specify parameters for specific compilation targe
[target.aarch64-unknown-linux-gnu]
xargo = false
build-std = false
zig = "2.17"
image = "test-image"
pre-build = ["apt-get update"] # can also be the path to a file to run
runner = "custom-runner"
Expand Down Expand Up @@ -92,3 +93,26 @@ also supports
[target.x86_64-unknown-linux-gnu]
dockerfile = "./Dockerfile"
```

# `target.TARGET.zig`

```toml
[target.x86_64-unknown-linux-gnu.zig]
enable = true # enable use of the zig image
version = "2.17" # glibc version to use
image = "zig:local" # custom zig image to use
```

also supports

```toml
[target.x86_64-unknown-linux-gnu]
zig = true
```

or

```toml
[target.x86_64-unknown-linux-gnu]
zig = "2.17"
```
Loading

0 comments on commit 1e8446f

Please sign in to comment.