name: "Build Rust Projects with Cross" author: "Dave Rolsky " 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'