Files
actions-rust-cross/action.yml
Dave Rolsky 52839d91bd Fix bug where we would try to use cross on ARM hosts for all targets
If the target is ARM and the host is ARM, this should work with just `cargo`. I'm not sure if this
works for all ARM host/target combos, or if the CPU architecture must be an exact match.

But it doesn't really matter too much, since at least for now there's no ARM builds for
`cross` (https://github.com/cross-rs/cross/issues/1612). So even if cross-compilation doesn't work
natively, we couldn't use `cross` in this case either.

I also rewrote the `set-cross-compile.sh` in Python. By "I", I mean I had Claude do it and then I
tweaked it.
2025-01-20 20:47:52 -06:00

197 lines
8.5 KiB
YAML

name: "Build Rust Projects with Cross"
author: "Dave Rolsky <autarch@urth.org>"
branding:
icon: home
color: gray-dark
description: |
Cross compile your Rust projects with cross (https://github.com/cross-rs/cross).
inputs:
target:
description: The target platform
required: true
command:
description: |
The commands to run. This must be one of "build", "test", "both" (build and test), or "bench".
default: build
toolchain:
description: |
The target toolchain to use (one of "stable", "beta", or "nightly").
default: stable
working-directory:
description: The working directory for each step
default: "."
GITHUB_TOKEN:
description: |
A GitHub token, available in the secrets.GITHUB_TOKEN working-directory variable.
default: ${{ github.token }}
args:
description: |
The arguments to be passed to cross or cargo when building, as a
space-separated string.
default: ""
strip:
description: Strip the compiled binary
default: false
cross-version:
description: |
The version of cross to use. If not specified, then the latest version
will be used.
cache-cross-binary:
description: |
Cache the cross binary if one is installed. This is primarily for use in
tests of this action.
default: true
use-rust-cache:
description: |
Use `Swatinem/rust-cache@v2`. Defaults to true.
default: true
rust-cache-parameters:
description: |
A JSON string containing parameters to pass to `Swatinem/rust-cache@v2`. You can use the
`toJSON()` function in your action to make passing this easier.
default: "{}"
runs:
using: composite
steps:
- name: Show inputs
shell: bash
run: |
echo '${{ toJSON(inputs) }}'
- name: Add this action's path to PATH
shell: bash
run: echo "${{ github.action_path }}" >> $GITHUB_PATH
- name: Validate inputs
shell: bash
run: |
"${{ github.action_path }}"/validate-inputs.py "${{ github.workspace }}"
env:
INPUTS_target: ${{ inputs.target }}
INPUTS_command: ${{ inputs.command }}
INPUTS_toolchain: ${{ inputs.toolchain }}
INPUTS_working_directory: ${{ inputs.working-directory }}
INPUTS_strip: ${{ inputs.strip }}
INPUTS_cache_cross_binary: ${{ inputs.cache-cross-binary }}
INPUTS_use_rust_cache: ${{ inputs.use-rust-cache }}
INPUTS_rust_cache_parameters: ${{ inputs.rust-cache-parameters }}
- name: Determine whether we need to cross-compile
id: determine-cross-compile
shell: bash
run: set-cross-compile.py ${{ inputs.target }}
- name: Install toolchain
uses: dtolnay/rust-toolchain@master
with:
targets: ${{ inputs.target }}
toolchain: ${{ inputs.toolchain }}
- name: Determine cross version
id: determine-cross-version
shell: bash
run: determine-cross-version.sh "${{ inputs.cross-version }}"
env:
GITHUB_TOKEN: ${{ inputs.GITHUB_TOKEN }}
if: steps.determine-cross-compile.outputs.needs-cross == 'true'
# We need to access this in both this YAML config and shell scripts. It
# doesn't seem like using ${{ env.RUNNER_TEMP }} works in the YAML config.
- name: Set directory for installing cross
id: set-cross-dir
shell: bash
run: set-cross-dir.sh
if: steps.determine-cross-compile.outputs.needs-cross == 'true'
- name: Cache cross
id: cache-cross
uses: actions/cache@v4
with:
path: ${{ steps.set-cross-dir.outputs.cross-dir }}/cross
key: ${{ runner.os }}-${{ steps.determine-cross-version.outputs.cross-version }}
if: steps.determine-cross-compile.outputs.needs-cross == 'true' && inputs.cache-cross-binary == 'true'
- name: Install cross if cross-compiling (*nix)
shell: bash
run: install-cross-nix.sh ${{ steps.set-cross-dir.outputs.cross-dir }} ${{ steps.determine-cross-version.outputs.cross-version }}
if: steps.determine-cross-compile.outputs.needs-cross == 'true' && steps.cache-cross.outputs.cache-hit != 'true'
env:
GITHUB_TOKEN: ${{ inputs.GITHUB_TOKEN }}
- name: Install musl-tools on Linux if target includes "musl"
shell: bash
run: |
if dpkg -l musl-tools | grep -q "^ii\s*musl-tools"; then
exit 0
fi
sudo apt-get update --yes && \
sudo apt-get install --yes musl-tools
if: steps.determine-cross-compile.outputs.needs-cross != 'true' && contains(inputs.target, 'musl')
- name: Set build command
id: set-build-command
shell: bash
run: set-build-command.sh ${{ steps.set-cross-dir.outputs.cross-dir }}
- name: Determine which cargo commands to run
id: determine-cargo-commands
shell: bash
run: determine-cargo-commands.sh ${{ inputs.command }}
- name: Parse `rust-cache-parameters` and set inputs for `Swatinem/rust-cache@v2`
id: parse-rust-cache-parameters
shell: bash
run: |
set -e
set -x
set -o pipefail
OS_VERSION=""
if [ -x /usr/bin/lsb_release ]; then
# This will be something like "Ubuntu 22.04.5 LTS"
OS_VERSION="$( lsb_release --short --description )"
fi
# This will get the inputs JSON from the `RUST_CACHE_PARAMETERS` env var. This avoids
# any string interpolation issues, since the inputs will contain quotes.
parse-and-set-rust-cache-parameters.py "${{ inputs.target }}" "${{ steps.set-build-command.outputs.build-command }}" "$OS_VERSION"
env:
RUST_CACHE_PARAMETERS: ${{ inputs.rust-cache-parameters }}
if: inputs.use-rust-cache == 'true'
- name: Cache cargo & target directories
uses: Swatinem/rust-cache@v2
with: ${{ steps.parse-rust-cache-parameters.outputs }}
if: inputs.use-rust-cache == 'true'
- name: Run tests (*nix)
working-directory: ${{ inputs.working-directory }}
shell: bash
run: |
${{ steps.set-build-command.outputs.build-command }} +${{inputs.toolchain}} test --target ${{ inputs.target }} ${{ inputs.args }}
if: steps.determine-cargo-commands.outputs.test == 'true' && runner.os != 'Windows'
# We want to run in Powershell on Windows to make sure we compile in a
# native Windows environment. Some things won't compile properly under
# msys, notably OpenSSL, which is compiled locally when using the
# `openssl` crate with the `vendored` feature.
- name: Run tests (Windows)
working-directory: ${{ inputs.working-directory }}
shell: powershell
run: |
& ${{ steps.set-build-command.outputs.build-command }} +${{inputs.toolchain}} test --target ${{ inputs.target }} ${{ inputs.args }}
if: steps.determine-cargo-commands.outputs.test == 'true' && runner.os == 'Windows'
- name: Run benchmarks (*nix)
working-directory: ${{ inputs.working-directory }}
shell: bash
run: |
${{ steps.set-build-command.outputs.build-command }} +${{inputs.toolchain}} bench --target ${{ inputs.target }} ${{ inputs.args }}
if: steps.determine-cargo-commands.outputs.bench == 'true' && runner.os != 'Windows'
- name: Run benchmarks (Windows)
working-directory: ${{ inputs.working-directory }}
shell: powershell
run: |
& ${{ steps.set-build-command.outputs.build-command }} +${{inputs.toolchain}} bench --target ${{ inputs.target }} ${{ inputs.args }}
if: steps.determine-cargo-commands.outputs.bench == 'true' && runner.os == 'Windows'
- name: Build binary (*nix)
working-directory: ${{ inputs.working-directory }}
shell: bash
run: |
${{ steps.set-build-command.outputs.build-command }} +${{inputs.toolchain}} build ${{ inputs.args }} --target ${{ inputs.target }}
if: steps.determine-cargo-commands.outputs.build == 'true' && runner.os != 'Windows'
- name: Build binary (Windows)
working-directory: ${{ inputs.working-directory }}
shell: powershell
run: |
& ${{ steps.set-build-command.outputs.build-command }} +${{inputs.toolchain}} build ${{ inputs.args }} --target ${{ inputs.target }}
if: steps.determine-cargo-commands.outputs.build == 'true' && runner.os == 'Windows'
- name: Strip binary
working-directory: ${{ inputs.working-directory }}
shell: bash
run: strip-binary.sh ${{ inputs.target }}
# strip doesn't work with cross-arch binaries on Linux or Windows.
if: inputs.command != 'test' && inputs.strip == 'true' && steps.determine-cross-compile.outputs.needs-cross == 'false' && inputs.target != 'aarch64-pc-windows-msvc'