Merge pull request #83 from crazy-max/cargo-tests

xx-cargo: add tests and docs
This commit is contained in:
Tõnis Tiigi
2022-11-02 23:34:47 -07:00
committed by GitHub
10 changed files with 402 additions and 78 deletions

View File

@@ -1,5 +1,9 @@
name: build
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
on:
workflow_dispatch:
push:

269
README.md
View File

@@ -1,14 +1,43 @@
## xx - Dockerfile cross-compilation helpers
# xx - Dockerfile cross-compilation helpers
[![CI Status](https://github.com/tonistiigi/xx/workflows/build/badge.svg)](https://github.com/tonistiigi/xx/actions?query=workflow%3Abuild)
[![Docker Pulls](https://img.shields.io/docker/pulls/tonistiigi/xx.svg?logo=docker)](https://hub.docker.com/r/tonistiigi/xx/)
`xx` provides tools to support cross-compilation from Dockerfiles that understand the `--platform` flag passed in from `docker build` or `docker buildx build`. These helpers allow you to build multi-platform images from any architecture into any architecture supported by your compiler with native performance. Adding `xx` to your Dockerfile should only need minimal updates and should not require custom conditions for specific architectures.
### Dockerfile cross-compilation primer
___
* [Dockerfile cross-compilation primer](#dockerfile-cross-compilation-primer)
* [Installation](#installation)
* [Supported targets](#supported-targets)
* [`xx-info` - Information about the build context](#xx-info---information-about-the-build-context)
* [Parsing current target](#parsing-current-target)
* [Architecture formats](#architecture-formats)
* [Target triple](#target-triple)
* [Build context](#build-context)
* [`xx-apk`, `xx-apt`, `xx-apt-get` - Installing packages for target architecture](#xx-apk-xx-apt-xx-apt-get---installing-packages-for-target-architecture)
* [`xx-verify` - Verifying compilation results](#xx-verify---verifying-compilation-results)
* [C/C++](#cc)
* [Building on Alpine](#building-on-alpine)
* [Building on Debian](#building-on-debian)
* [Wrapping as default](#wrapping-as-default)
* [Autotools](#autotools)
* [CMake](#cmake)
* [Go / Cgo](#go--cgo)
* [Rust](#rust)
* [Building on Alpine](#building-on-alpine-1)
* [Building on Debian](#building-on-debian-1)
* [External SDK support](#external-sdk-support)
* [Used by](#used-by)
* [Issues](#issues)
## Dockerfile cross-compilation primer
Cross-compilation can be achieved in Dockerfiles by using multi-stage builds and defining some of the stages to always run on the native architecture used by the builder and execute the cross-compiling compiler. By default, a Dockerfile stage started with `FROM` keyword default to the target architecture, but this can be overridden with a `FROM --platform` flag. Using [automatic platform ARGs in global scope](https://docs.docker.com/engine/reference/builder/#automatic-platform-args-in-the-global-scope), the platform of the cross-compiler stage can be set to `$BUILDPLATFORM` while the value of `$TARGETPLATFORM` can be passed to the compiler with an environment variable.
After compilation, the resulting assets can be copied into another stage that will become the result of the build. Usually, this stage does not use `FROM --platform` so that every stage is based on the expected target architecture.
```
```dockerfile
FROM --platform=$BUILDPLATFORM alpine AS xbuild
ARG TARGETPLATFORM
RUN ./compile --target=$TARGETPLATFORM -o /out/myapp
@@ -17,12 +46,11 @@ FROM alpine
COPY --from=xbuild /out/myapp /bin
```
### Installation
## Installation
`xx` is distributed with a Docker image `tonistiigi/xx` that contains a collection of helper scripts that read `TARGET*` environment variables to automatically configure the compilation targets. The scripts are based on Posix Shell, so they should work on top of any image but currently `xx` is expected to work on Alpine and Debian/Ubuntu based distros. In order to avoid unexpected changes, you may want to pin the image using an immutable digest. Although `xx` only contains shell scripts that are identical for every platform it is recommended to also import `xx` with `FROM --platform=$BUILDPLATFORM`, so that import commands are shared for all compilation targets.
```
```dockerfile
FROM --platform=$BUILDPLATFORM tonistiigi/xx AS xx
FROM --platform=$BUILDPLATFORM alpine
@@ -34,28 +62,27 @@ ARG TARGETPLATFORM
RUN xx-info env
```
`xx` currently contains `xx-info`, `xx-apk`, `xx-apt-get`, `xx-cc`, `xx-c++`, `xx-clang`, `xx-clang++`, `xx-go`, `xx-verify`. `xx-clang` (and its aliases) creates additional aliases, eg. `${triple}-clang`, `${triple}-pkg-config`, on first invocation or on `xx-clang --setup-target-triple` call.
`xx` currently contains `xx-info`, `xx-apk`, `xx-apt-get`, `xx-cc`, `xx-c++`, `xx-clang`, `xx-clang++`, `xx-go`, `xx-cargo`, `xx-verify`. `xx-clang` (and its aliases) creates additional aliases, eg. `${triple}-clang`, `${triple}-pkg-config`, on first invocation or on `xx-clang --setup-target-triple` call.
### Supported targets
## Supported targets
`xx` supports building from and into Linux amd64, arm64, arm/v7, s390x, ppc64le and 386, and Alpine, Debian and Ubuntu. Risc-V is supported for Go builds and for newer distros that provide Risc-V packages like `alpine:edge` or `debian:sid`.
`xx` supports building from and into Linux amd64, arm64, arm/v7, s390x, ppc64le and 386, and Alpine, Debian and Ubuntu. Risc-V is supported for Go and Rust builds and for newer distros that provide Risc-V packages like `alpine:edge` or `debian:sid`.
Go builds that don't depend on system packages can additionally target MacOS and Windows on all architectures. C/C++/CGo builds are supported for MacOS targets when an external SDK image is provided.
Go builds that don't depend on system packages can additionally target MacOS and Windows on all architectures. C/C++/CGo/Rust builds are supported for MacOS targets when an external SDK image is provided.
`xx-info` command also works on RHEL-style distros but no support is provided for package manager wrappers(eg. yum, dnf) there.
### xx-info - Information about the build context
## `xx-info` - Information about the build context
`xx-info` command returns normalized information about the current build context. It allows you to get various information about your build target and configuration and avoid the need for converting from one format to another in your own code. Invoking `xx-info` without any additional arguments will invoke `xx-info triple`.
#### Parsing current target
### Parsing current target
- `xx-info os` - prints operating system component of TARGETPLATFORM (linux,darwin,windows,wasi)
- `xx-info arch` - architecture component of TARGETPLATFORM
- `xx-info variant` - variant component of TARGETPLATFORM if architecture is arm (eg. v7
#### Architecture formats
### Architecture formats
These commands return architecture names as used by specific tools to avoid conversion and tracking exceptions in your own code. E.g. arm64 repositories are called `aarch64` in Alpine, but `arm64` in Debian. `uname -m` returns `aarch64` in Linux, but `arm64` in Darwin etc.
@@ -65,7 +92,7 @@ These commands return architecture names as used by specific tools to avoid conv
- `xx-info rhel-arch` - Target architecture for [RPM package repositories](https://docs.fedoraproject.org/ro/Fedora_Draft_Documentation/0.1/html/RPM_Guide/ch01s03.html)
- `xx-info pkg-arch` - Either alpine-arch, debian-arch or rhel-arch depending on the context
#### Target triple
### Target triple
Target triple is the target format taken as input in various gcc and llvm based compilers.
@@ -73,13 +100,13 @@ Target triple is the target format taken as input in various gcc and llvm based
- `xx-info vendor` - Vendor component of target triple
- `xx-info libc` - Used libc (musl or gnu)
#### Build context
### Build context
- `xx-info is-cross` - Exit cleanly if target is not native architecture
- `xx-info env` - Print XX_* variables defining target environment
```
> xx-info env
```console
$ xx-info env
XX_OS=linux
XX_MARCH=x86_64
XX_VENDOR=alpine
@@ -91,18 +118,17 @@ TARGETARCH=amd64
TARGETVARIANT=
```
### xx-apk, xx-apt, xx-apt-get - Installing packages for target architecture
## `xx-apk`, `xx-apt`, `xx-apt-get` - Installing packages for target architecture
These scripts allow managing packages (most commonly installing new packages) from either Alpine or Debian repositories. They can be invoked with any arguments regular `apk` or `apt/apt-get` commands accept. If cross-compiling for non-native architectures, the repositories for the target architecture are added automatically, and packages are installed from there. On Alpine, installing packages for a different architecture under the same root is not allowed, so `xx-apk` installs packages under a secondary root `/${triple}`. These scripts are meant for installing headers and libraries that compilers may need. To avoid unnecessary garbage, the non-native binaries under `*/bin` are skipped on installation.
```
```dockerfile
# alpine
ARG TARGETPLATFORM
RUN xx-apk add --no-cache musl-dev zlib-dev
```
```
```dockerfile
# debian
ARG TARGETPLATFORM
RUN xx-apt-get install -y libc6-dev zlib1g-dev
@@ -110,17 +136,17 @@ RUN xx-apt-get install -y libc6-dev zlib1g-dev
Installing two meta-libraries, `xx-c-essentials`, `xx-cxx-essentials` is also allowed that expand the minimum necessary packages for either base image.
### xx-verify - Verifying compilation results
## `xx-verify` - Verifying compilation results
`xx-verify` allows verifying that the cross-compile toolchain was correctly configured and outputted binaries for the expected target platform. `xx-verify` works by calling `file` utility and comparing the expected output. Optionally `--static` option can be passed to verify that the compiler produced a static binary that can be safely copied to another Dockerfile stage without runtime libraries. If the binary does not match the expected value, `xx-verify` returns with a non-zero exit code and error message.
```
```dockerfile
ARG TARGETPLATFORM
RUN xx-clang --static -o /out/myapp app.c && \
xx-verify --static /out/myapp
```
### C/C++
## C/C++
The recommended method for C-based build is to use `clang` via `xx-clang` wrapper. Clang is natively a cross-compiler, but in order to use it, you also need a linker, compiler-rt or libgcc, and a C library(musl or glibc). All these are available as packages in Alpine and Debian based distros. Clang and linker are binaries and should be installed for your build architecture, while libgcc and C library should be installed for your target architecture.
@@ -138,12 +164,12 @@ Alias commands include:
Alias commands can be called directly and always build the configuration specified by their name, even if `TARGETPLATFORM` value has changed.
#### Building on Alpine
### Building on Alpine
On Alpine, there is no special package for `libgcc` so you need to install `gcc` package with `xx-apk` even though the build happens through clang. To use compiler-rt instead of `libgcc` `--rtlib` needs to be passed manually. We will probably add default detection/loading for compiler-rt in the future to simplify this part. Default libc used in Alpine is [Musl](https://www.musl-libc.org/) that can be installed with `musl-dev` package.
```
...
```dockerfile
# ...
RUN apk add clang lld
# copy source
ARG TARGETPLATFORM
@@ -154,33 +180,33 @@ RUN xx-clang -o hello hello.c && \
Clang binary can also be called directly with `--target` flag if you want to avoid `xx-` prefixes. `--print-target-triple` is a built-in flag in clang that can be used to query to correct default value.
```
...
```dockerfile
# ...
RUN xx-apk add g++
RUN clang++ --target=$(xx-clang --print-target-triple) -o hello hello.cc
```
On the first invocation, aliases with `triple-` prefix are set up so the following also works:
```
...
```dockerfile
# ...
RUN $(xx-clang --print-target-triple)-clang -o hello hello.c
```
If you prefer aliases to be created as a separate step on a separate layer, you can use `--setup-target-triple`.
```
...
```dockerfile
# ...
RUN xx-clang --setup-target-triple
RUN $(xx-info)-clang -o hello hello.c
```
#### Building on Debian
### Building on Debian
Building on Debian/Ubuntu is very similar. The only required dependency that needs to be installed with `xx-apt` is `libc6-dev` or `libstdc++-N-dev` for C++.
```
...
```dockerfile
# ...
RUN apt-get update && apt-get instal -y clang lld
# copy source
ARG TARGETPLATFORM
@@ -192,15 +218,15 @@ Refer to the previous section for other variants.
If you wish to build with GCC instead of Clang you need to install `gcc` and `binutils` packages additionally with `xx-apt-get`. `xx-apt-get` will automatically install the packages that generate binaries for the current target architecture. You can then call GCC directly with the correct target triple. Note that Debian currently only provides GCC cross-compilation packages if your native platform is amd64 or arm64.
```
...
```dockerfile
# ...
# copy source
ARG TARGETPLATFORM
RUN xx-apt-get install -y binutils gcc libc6-dev
RUN $(xx-info)-gcc -o hello hello.c
```
#### Wrapping as default
### Wrapping as default
Special flags `xx-clang --wrap` and `xx-clang --unwarp` can be used to override the default behavior of `clang` with `xx-clang` in the extreme cases where your build scripts have no way to point to alternative compiler names.
@@ -219,40 +245,38 @@ x86_64-alpine-linux-musl
aarch64-alpine-linux-musl
```
### Autotools
## Autotools
Autotools has [built-in support](https://www.gnu.org/software/automake/manual/html_node/Cross_002dCompilation.html) for cross-compilation that works by passing `--host`, `--build`, and `--target` flags to the configure script. `--host` defines the target architecture of the build result, `--build` defines compilers native architecture(used for compiling helper tools etc.), and `--target` defines an architecture that the binary returns if it is running as a compiler of other binaries. Usually, only `--host` is needed.
```
...
```dockerfile
# ...
ARG TARGETPLATFORM
RUN ./configure --host=$(xx-clang --print-target-triple) && make
```
If you need to pass `--build`, you can temporarily reset the `TARGETPLATFORM` variable to get the system value.
```
```dockerfile
ARG TARGETPLATFORM
RUN ./configure --host=$(xx-clang --print-target-triple) --build=$(TARGETPLATFORM= xx-clang --print-target-triple) && make
```
Sometimes `configure` scripts misbehave and don't work correctly unless the name of the C compiler is passed directly. In these cases, you can use overrides like:
```
```dockerfile
RUN CC=xx-clang ./configure ...
```
```
```dockerfile
RUN ./configure --with-cc=xx-clang ...
```
```
```dockerfile
RUN ./configure --with-cc=$(xx-clang --print-target-triple)-clang ...
```
### CMake
## CMake
In order to make cross-compiling with CMake easier, `xx-clang` has a special flag `xx-clang --print-cmake-defines`. Running that command returns the following Cmake definitions:
@@ -268,7 +292,7 @@ In order to make cross-compiling with CMake easier, `xx-clang` has a special fla
Usually, this should be enough to pick up the correct configuration.
```
```dockerfile
RUN apk add cmake clang lld
ARG TARGETPLATFORM
RUN xx-apk musl-dev gcc
@@ -276,23 +300,23 @@ RUN mkdir build && cd build && \
cmake $(xx-clang --print-cmake-defines) ..
```
### Go / Cgo
## Go / Cgo
Building Go can be achieved with the `xx-go` wrapper that automatically sets up values for `GOOS`, `GOARCH`, `GOARM` etc. It also sets up `pkg-config` and C compiler if building with CGo. Note that by default, CGo is enabled in Go when compiling for native architecture and disabled when cross-compiling. This can easily produce unexpected results; therefore, you should always define either `CGO_ENABLED=1` or `CGO_ENABLED=0` depending on if you expect your compilation to use CGo or not.
```
```dockerfile
FROM --platform=$BUILDPLATFORM golang:alpine
...
# ...
ARG TARGETPLATFORM
ENV CGO_ENABLED=0
RUN xx-go build -o hello ./hello.go && \
xx-verify hello
```
```
```dockerfile
FROM --platform=$BUILDPLATFORM golang:alpine
RUN apk add clang lld
...
# ...
ARG TARGETPLATFORM
RUN xx-apk add musl-dev gcc
ENV CGO_ENABLED=1
@@ -302,22 +326,136 @@ RUN xx-go build -o hello ./hello.go && \
If you want to make `go` compiler cross-compile by default, you can use `xx-go --wrap` and `xx-go --unwrap`
```
...
```dockerfile
# ...
RUN xx-go --wrap
RUN go build -o hello hello.go && \
xx-verify hello
```
### External SDK support
## Rust
Building Rust can be achieved with the `xx-cargo` wrapper that automatically
sets up the target triple and also `pkg-config` and C compiler.
The wrapper supports rust installed via [`rustup`](https://rustup.rs/)
(alpine/debian), distribution packages (alpine/debian) and the [official `rust` image](https://hub.docker.com/_/rust).
### Building on Alpine
```dockerfile
# syntax=docker/dockerfile:1
# official rust image
FROM --platform=$BUILDPLATFORM rust:alpine
RUN apk add clang lld
# ...
RUN --mount=type=cache,target=/usr/local/cargo/git/db \
--mount=type=cache,target=/usr/local/cargo/registry/cache \
--mount=type=cache,target=/usr/local/cargo/registry/index \
cargo fetch
ARG TARGETPLATFORM
RUN xx-cargo build --release --target-dir ./build && \
xx-verify ./build/$(xx-cargo --print-target)/release/hello_cargo
```
```dockerfile
# syntax=docker/dockerfile:1
# rustup
FROM --platform=$BUILDPLATFORM alpine AS rustup
RUN apk add curl
RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain stable --no-modify-path --profile minimal
ENV PATH="/root/.cargo/bin:$PATH"
FROM rustup
RUN apk add clang lld
# ...
RUN --mount=type=cache,target=/root/.cargo/git/db \
--mount=type=cache,target=/root/.cargo/registry/cache \
--mount=type=cache,target=/root/.cargo/registry/index \
cargo fetch
ARG TARGETPLATFORM
RUN xx-cargo build --release --target-dir ./build && \
xx-verify ./build/$(xx-cargo --print-target)/release/hello_cargo
```
```dockerfile
# syntax=docker/dockerfile:1
# packages
FROM --platform=$BUILDPLATFORM alpine
RUN apk add clang lld rust cargo
# ...
RUN --mount=type=cache,target=/root/.cargo/git/db \
--mount=type=cache,target=/root/.cargo/registry/cache \
--mount=type=cache,target=/root/.cargo/registry/index \
cargo fetch
ARG TARGETPLATFORM
RUN xx-apk add xx-c-essentials
RUN xx-cargo build --release --target-dir ./build && \
xx-verify ./build/$(xx-cargo --print-target)/release/hello_cargo
```
### Building on Debian
```dockerfile
# syntax=docker/dockerfile:1
# official rust image
FROM --platform=$BUILDPLATFORM rust:bullseye
RUN apt-get update && apt-get install -y clang lld
# ...
RUN --mount=type=cache,target=/usr/local/cargo/git/db \
--mount=type=cache,target=/usr/local/cargo/registry/cache \
--mount=type=cache,target=/usr/local/cargo/registry/index \
cargo fetch
ARG TARGETPLATFORM
RUN xx-cargo build --release --target-dir ./build && \
xx-verify ./build/$(xx-cargo --print-target)/release/hello_cargo
```
```dockerfile
# syntax=docker/dockerfile:1
# rustup
FROM --platform=$BUILDPLATFORM debian:bullseye AS rustup
RUN apt-get update && apt-get install -y curl ca-certificates
RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain stable --no-modify-path --profile minimal
ENV PATH="/root/.cargo/bin:$PATH"
FROM rustup
RUN apt-get update && apt-get install -y clang lld
# ...
RUN --mount=type=cache,target=/root/.cargo/git/db \
--mount=type=cache,target=/root/.cargo/registry/cache \
--mount=type=cache,target=/root/.cargo/registry/index \
cargo fetch
ARG TARGETPLATFORM
RUN xx-cargo build --release --target-dir ./build && \
xx-verify ./build/$(xx-cargo --print-target)/release/hello_cargo
```
```dockerfile
# syntax=docker/dockerfile:1
# packages
FROM --platform=$BUILDPLATFORM debian:bullseye
RUN apt-get update && apt-get install -y clang lld cargo
# ...
RUN --mount=type=cache,target=/root/.cargo/git/db \
--mount=type=cache,target=/root/.cargo/registry/cache \
--mount=type=cache,target=/root/.cargo/registry/index \
cargo fetch
ARG TARGETPLATFORM
RUN xx-apt-get install xx-c-essentials
RUN xx-cargo build --release --target-dir ./build && \
xx-verify ./build/$(xx-cargo --print-target)/release/hello_cargo
```
## External SDK support
In addition to Linux targets, `xx` can also build binaries for MacOS and Windows. When building MacOS binaries from C, external MacOS SDK is needed in `/xx-sdk` directory. Such SDK can be built, for example, with [gen_sdk_package script in osxcross project](https://github.com/tpoechtrager/osxcross/blob/master/tools/gen_sdk_package.sh). Please consult XCode license terms when making such an image. `RUN --mount` syntax can be used in Dockerfile in order to avoid copying SDK files. No special tooling such as `ld64` linker is required in the image itself.
Building Windows binaries from C/CGo is currently a work in progress and not functional.
```
#syntax=docker/dockerfile:1.2
...
```dockerfile
# syntax=docker/dockerfile:1.2
# ...
RUN apk add clang lld
ARG TARGETPLATFORM
RUN --mount=from=my/sdk-image,target=/xx-sdk,src=/xx-sdk \
@@ -328,14 +466,13 @@ FROM scratch
COPY --from=build /hello /
```
```
```console
docker buildx build --platform=darwin/amd64,darwin/arm64 -o bin .
```
`-o/--output` flag can be used to export binaries out from the builder without creating a container image.
### Used by
## Used by
These projects, as well as [xx Dockerfile](https://github.com/tonistiigi/xx/blob/41f7f39551857836e691da81580296ba5acf6ac3/base/Dockerfile) can be used for reference.
@@ -345,6 +482,6 @@ These projects, as well as [xx Dockerfile](https://github.com/tonistiigi/xx/blob
- [Docker Buildx](https://github.com/docker/buildx/blob/4fec647b9d8f34f8569141124d8462c912858144/Dockerfile)
- [Containerd](https://github.com/containerd/containerd/blob/9e7910ebdcbf3bf10ebd0a282ab9996572e38749/.github/workflows/release/Dockerfile)
### Issues
## Issues
`xx` project welcomes contributions if you notice any issues or want to extend the capabilities with new features. We are also interested in cases where a popular project does not compile easily with `xx` so it can be improved, and tests can be added that try building these projects when `xx` gets updated. If you want to add support for a new architecture or language, please open an issue first to verify that the proposal matches the scope or `xx`.

View File

@@ -75,6 +75,8 @@ RUN --mount=type=cache,target=/pkg-cache \
RUN --mount=type=cache,target=/pkg-cache \
--mount=target=/root/.cache,type=cache \
[ "${TEST_CMDS:-golang}" = "${TEST_CMDS#*golang}" ] && exit 0; ./test-go.bats
RUN --mount=type=cache,target=/pkg-cache \
[ "${TEST_CMDS:-cargo}" = "${TEST_CMDS#*cargo}" ] && exit 0; ./test-cargo.bats
FROM --platform=${BUILDPLATFORM} alpine AS libtapi-base
RUN apk add --no-cache git clang lld cmake make python3 bash

View File

@@ -0,0 +1,8 @@
[package]
name = "hello_cargo"
version = "0.1.0"
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View File

@@ -0,0 +1,3 @@
fn main() {
println!("hello cargo");
}

144
base/test-cargo.bats Executable file
View File

@@ -0,0 +1,144 @@
#!/usr/bin/env bats
load 'assert'
load 'test_helper'
cleanPackages() {
for p in linux/amd64 linux/arm64 linux/ppc64le linux/s390x linux/386 linux/arm/v7 linux/arm/v6; do
TARGETPLATFORM=$p xxdel xx-c-essentials
root=/$(TARGETPLATFORM=$p xx-info triple)
if [ -d "$root" ] && [ "$root" != "/" ]; then
rm -rf "$root"
fi
done
del cargo rust
del pkgconfig || del pkg-config
rm -rf "$HOME/.cargo" /.xx-cargo* || true
}
@test "nocargo" {
cleanPackages
add clang
run xx-cargo --version
assert_failure
assert_output --partial "cargo: not found"
}
testHelloCargo() {
rm -f "/.xx-cargo.$(xx-info arch)"
run xxadd xx-c-essentials
assert_success
run xx-cargo build --verbose --color=never --manifest-path=./fixtures/hello_cargo/Cargo.toml --release --target-dir /tmp/cargobuild
assert_success
xx-verify /tmp/cargobuild/$(xx-cargo --print-target)/release/hello_cargo
if ! xx-info is-cross; then
run /tmp/cargobuild/$(xx-cargo --print-target)/release/hello_cargo
assert_success
assert_output "hello cargo"
fi
rm -rf /tmp/cargobuild
}
testHelloCargoRustup() {
export PATH="$HOME/.cargo/bin:$PATH"
testHelloCargo
}
@test "install-rustup" {
add clang lld curl ca-certificates
assert_success
run sh -c "curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain stable --no-modify-path --profile minimal"
assert_success
}
@test "amd64-hellocargo-rustup" {
export TARGETARCH=amd64
testHelloCargoRustup
}
@test "arm64-hellocargo-rustup" {
export TARGETARCH=arm64
testHelloCargoRustup
}
@test "arm-hellocargo-rustup" {
export TARGETARCH=arm
testHelloCargoRustup
}
@test "ppc64le-hellocargo-rustup" {
if [ -f /etc/alpine-release ]; then
skip "rust stdlib not yet available for powerpc64le-unknown-linux-musl"
fi
export TARGETARCH=ppc64le
testHelloCargoRustup
}
@test "riscv64-hellocargo-rustup" {
if ! supportRiscVCGo; then
skip "RISC-V not supported" # rust stdlib package not available
fi
export TARGETARCH=riscv64
testHelloCargoRustup
}
@test "386-hellocargo-rustup" {
export TARGETARCH=386
testHelloCargoRustup
}
@test "uninstall-rustup" {
export PATH="$HOME/.cargo/bin:$PATH"
rustup self uninstall -y
}
@test "install-rustpkg" {
cleanPackages
add clang lld
case "$(xx-info vendor)" in
alpine)
add cargo rust
;;
debian | ubuntu)
add cargo
;;
esac
}
@test "amd64-hellocargo-rustpkg" {
export TARGETARCH=amd64
testHelloCargo
}
@test "arm64-hellocargo-rustpkg" {
export TARGETARCH=arm64
testHelloCargo
}
@test "arm-hellocargo-rustpkg" {
export TARGETARCH=arm
testHelloCargo
}
@test "ppc64le-hellocargo-rustpkg" {
export TARGETARCH=ppc64le
testHelloCargo
}
@test "riscv64-hellocargo-rustpkg" {
if ! supportRiscVCGo; then
skip "RISC-V not supported" # rust stdlib package not available
fi
export TARGETARCH=riscv64
export RISCV64_TARGET_ARCH=riscv64
testHelloCargo
}
@test "386-hellocargo-rustpkg" {
export TARGETARCH=386
testHelloCargo
}
@test "clean-packages" {
cleanPackages
}

View File

@@ -33,6 +33,10 @@ load 'assert'
assert_equal "armv7-alpine-linux-musleabihf" "$(TARGETPLATFORM=linux/arm xx-info triple)"
assert_equal "armv7" "$(TARGETPLATFORM=linux/arm xx-info pkg-arch)"
assert_equal "v7" "$(TARGETPLATFORM=linux/arm/v7 xx-info variant)"
assert_equal "arm-alpine-linux-musleabihf" "$(TARGETPLATFORM=linux/arm ARM_TARGET_ARCH=arm xx-info triple)"
assert_equal "armv7" "$(TARGETPLATFORM=linux/arm ARM_TARGET_ARCH=arm xx-info pkg-arch)" # does not change
assert_equal "v7" "$(TARGETPLATFORM=linux/arm/v7 ARM_TARGET_ARCH=arm xx-info variant)" # does not change
}
@test "armv6" {

View File

@@ -35,6 +35,10 @@ fi
assert_equal "arm-linux-gnueabihf" "$(TARGETPLATFORM=linux/arm xx-info triple)"
assert_equal "armhf" "$(TARGETPLATFORM=linux/arm xx-info pkg-arch)"
assert_equal "v7" "$(TARGETPLATFORM=linux/arm xx-info variant)"
assert_equal "armv7-linux-gnueabihf" "$(TARGETPLATFORM=linux/arm ARM_TARGET_ARCH=armv7 xx-info triple)"
assert_equal "armhf" "$(TARGETPLATFORM=linux/arm ARM_TARGET_ARCH=armv7 xx-info pkg-arch)" # does not change
assert_equal "armv7-unknown-linux-gnueabihf" "$(TARGETPLATFORM=linux/arm ARM_TARGET_ARCH=armv7 XX_VENDOR=unknown xx-info triple)"
}
@test "armv6" {

View File

@@ -2,6 +2,13 @@
set -e
execSilent() {
if ! cmdout=$("$@" 2>&1); then
echo "$cmdout" >&2
exit 1
fi
}
if [ -z "$XX_CARGO_NOLOCK" ]; then
lock="/var/lock/xx-cargo"
exec 9>$lock
@@ -33,13 +40,19 @@ done
done_file="/.xx-cargo.$(xx-info arch)"
export RISCV64_TARGET_ARCH=riscv64gc
if [ -z "$RISCV64_TARGET_ARCH" ]; then
export RISCV64_TARGET_ARCH=riscv64gc
fi
if [ -z "$ARM_TARGET_ARCH" ]; then
export ARM_TARGET_ARCH=armv7
fi
rustup=
if which rustup >/dev/null 2>&1; then
rustup=1
fi
vendor=$XX_VENDOR
if [ -n "$rustup" ] || [ ! -f /etc/alpine-release ]; then
export XX_VENDOR="unknown"
fi
@@ -48,11 +61,13 @@ if [ ! -f "$done_file" ]; then
xx-clang --setup-target-triple
if [ ! -d "$(rustc --print sysroot)/lib/rustlib/$(xx-info)" ]; then
if [ -n "$rustup" ]; then
rustup target add "$(xx-info)" 2>/dev/null >/dev/null
execSilent rustup target add "$(xx-info)"
elif [ -f /etc/alpine-release ]; then
xx-apk add rust-stdlib 2>/dev/null >/dev/null
# XX_VENDOR overrided to match the distrib one to install packages
XX_VENDOR=$vendor execSilent xx-apk add rust-stdlib
else
xx-apt install -y libstd-rust-dev 2>/dev/null >/dev/null
# XX_VENDOR overrided to match the distrib one to install packages
XX_VENDOR=$vendor execSilent xx-apt-get install -y libstd-rust-dev
fi
fi
touch "$done_file"
@@ -64,12 +79,12 @@ if [ -n "$XX_RUSTFLAGS" ]; then
fi
export "CC_$(xx-info | tr - _)=$(xx-info)-clang"
if which "qemu-$(RISCV64_TARGET_ARCH='' xx-info march)" >/dev/null 2>&1; then
export "CARGO_TARGET_$(xx-info | tr '[:lower:]' '[:upper:]' | tr - _)_RUNNER=qemu-$(RISCV64_TARGET_ARCH='' xx-info march)"
if which "qemu-$(RISCV64_TARGET_ARCH='' ARM_TARGET_ARCH='' xx-info march)" >/dev/null 2>&1; then
export "CARGO_TARGET_$(xx-info | tr '[:lower:]' '[:upper:]' | tr - _)_RUNNER=qemu-$(RISCV64_TARGET_ARCH='' ARM_TARGET_ARCH='' xx-info march)"
if [ -f /etc/alpine-release ]; then
export "QEMU_LD_PREFIX=/$(RISCV64_TARGET_ARCH='' xx-info)/"
export "QEMU_LD_PREFIX=/$(RISCV64_TARGET_ARCH='' ARM_TARGET_ARCH='' xx-info)/"
else
export "QEMU_LD_PREFIX=/lib/$(RISCV64_TARGET_ARCH='' XX_VENDOR='' xx-info)/"
export "QEMU_LD_PREFIX=/lib/$(RISCV64_TARGET_ARCH='' ARM_TARGET_ARCH='' XX_VENDOR='' xx-info)/"
fi
fi
@@ -79,5 +94,5 @@ if [ -n "$printtarget" ]; then
fi
if [ -z "$setuponly" ]; then
cargo "$@" --target="$(xx-info)"
exec cargo "$@" --target="$(xx-info)"
fi

View File

@@ -239,10 +239,13 @@ case "$TARGETARCH" in
XX_DEBIAN_ARCH="armhf"
XX_ALPINE_ARCH="armv7"
XX_RHEL_ARCH="armv7hl"
XX_TRIPLE="arm${vendor}-linux-${XX_LIBC}eabihf"
if [ "$XX_VENDOR" = "alpine" ]; then
XX_TRIPLE="armv7${vendor}-linux-${XX_LIBC}eabihf"
triplearch="arm"
if [ -n "$ARM_TARGET_ARCH" ]; then
triplearch="${ARM_TARGET_ARCH}"
elif [ "$XX_VENDOR" = "alpine" ]; then
triplearch="armv7"
fi
XX_TRIPLE="${triplearch}${vendor}-linux-${XX_LIBC}eabihf"
if [ "$TARGETVARIANT" = "v6" ]; then
XX_MARCH="armv6l"
XX_DEBIAN_ARCH="armel"