bugs #9
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: build-siboot | |
| # Cross-compiles `ish-bootstrap/` to a static i686-unknown-linux-musl binary and | |
| # attaches it to a release as `siboot-i686` — the file the install instructions | |
| # tell people to curl onto their phone. | |
| # | |
| # Why a container rather than `cross`: siboot depends on | |
| # `rust-core/vendor/idevice` by path, which sits outside its own cargo | |
| # workspace. `cross` mounts the workspace root and would leave that path | |
| # unmounted; a container checks the whole repository out, so the path resolves | |
| # the way it does locally. | |
| # | |
| # The image supplies the one thing ubuntu-latest cannot: an i686-linux-musl C | |
| # toolchain. Two dependencies compile C — `ring` (its 32-bit x86 assembly, all | |
| # pregenerated, so no Perl is needed) and `liblzma-sys` (reached through | |
| # apple-codesign's xar support, which nothing here calls but which is not | |
| # feature-gated upstream). Its bindings are pregenerated too, so no libclang. | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| attach_to_release: | |
| description: "Upload siboot-i686 to the latest release" | |
| required: false | |
| type: boolean | |
| default: false | |
| push: | |
| paths: | |
| - "ish-bootstrap/**" | |
| - ".github/workflows/build-siboot.yml" | |
| release: | |
| types: [published] | |
| permissions: | |
| contents: write # attach the binary to the release | |
| jobs: | |
| build: | |
| runs-on: ubuntu-latest | |
| container: | |
| image: messense/rust-musl-cross:i686-musl | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v7 | |
| - name: Check the toolchain is new enough | |
| # `idevice` and `isideload` are both edition 2024, which needs 1.85 or | |
| # newer. Checked rather than updated: this image ships a damaged | |
| # component manifest, and `rustup update stable` dies trying to remove | |
| # the old clippy — | |
| # error: failure removing component 'clippy-preview-...', | |
| # directory does not exist: 'share/doc/clippy/README.md' | |
| # — then rolls the whole update back. Adding a target does not touch | |
| # components, so it stays safe. | |
| run: | | |
| set -eu | |
| rustc --version | |
| MIN_MINOR=85 | |
| have=$(rustc --version | sed -n 's/^rustc 1\.\([0-9][0-9]*\).*/\1/p') | |
| if [ -z "$have" ] || [ "$have" -lt "$MIN_MINOR" ]; then | |
| echo "::warning::rustc is older than 1.$MIN_MINOR; replacing the toolchain" | |
| # Uninstall-then-install rather than update: removing the whole | |
| # toolchain directory avoids the per-component path the bug is in. | |
| rustup toolchain uninstall stable || true | |
| rustup toolchain install stable --profile minimal | |
| rustup default stable | |
| fi | |
| if ! rustup target list --installed | grep -qx i686-unknown-linux-musl; then | |
| rustup target add i686-unknown-linux-musl | |
| fi | |
| rustc --version | |
| cargo --version | |
| rustup target list --installed | |
| - name: Cache cargo registry and build | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.cargo/registry | |
| ~/.cargo/git | |
| ish-bootstrap/target | |
| key: siboot-${{ runner.os }}-${{ hashFiles('ish-bootstrap/Cargo.toml', 'ish-bootstrap/Cargo.lock') }} | |
| restore-keys: siboot-${{ runner.os }}- | |
| - name: Build siboot | |
| working-directory: ish-bootstrap | |
| run: cargo build --release --target i686-unknown-linux-musl | |
| - name: Verify the binary | |
| working-directory: ish-bootstrap | |
| run: | | |
| BIN=target/i686-unknown-linux-musl/release/siboot | |
| file "$BIN" | |
| ls -lh "$BIN" | |
| # Everything below is a hard requirement of running inside iSH, so a | |
| # regression should fail the build rather than reach a phone. | |
| file "$BIN" | grep -q "ELF 32-bit LSB" || { echo "::error::not a 32-bit ELF"; exit 1; } | |
| file "$BIN" | grep -q "Intel 80386" || { echo "::error::not an i386 binary"; exit 1; } | |
| file "$BIN" | grep -q "statically linked" || { echo "::error::not statically linked"; exit 1; } | |
| # A dynamic loader entry would mean iSH's Alpine has to supply a | |
| # matching libc, which is exactly what static linking avoids. | |
| READELF=$(command -v readelf || command -v i686-linux-musl-readelf || true) | |
| if [ -n "$READELF" ]; then | |
| if "$READELF" -l "$BIN" | grep -q "Requesting program interpreter"; then | |
| echo "::error::binary requests a dynamic loader"; exit 1 | |
| fi | |
| else | |
| echo "::warning::no readelf available; skipped the dynamic-loader check" | |
| fi | |
| echo "size=$(stat -c %s "$BIN") bytes" >> "$GITHUB_STEP_SUMMARY" | |
| - name: Stage as siboot-i686 | |
| working-directory: ish-bootstrap | |
| run: cp target/i686-unknown-linux-musl/release/siboot siboot-i686 | |
| - name: Upload build artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: siboot-i686 | |
| path: ish-bootstrap/siboot-i686 | |
| if-no-files-found: error | |
| - name: Resolve the release tag | |
| # A push to the default branch attaches too, not just a published | |
| # release. The install instructions hardcode | |
| # `releases/latest/download/siboot-i686`, so that asset *is* the | |
| # distribution — leaving it to a manual tick means every change ships | |
| # only if someone remembers to tick it. Branch pushes and pull requests | |
| # still build without touching any release. | |
| id: tag | |
| if: >- | |
| github.event_name == 'release' || | |
| inputs.attach_to_release || | |
| (github.event_name == 'push' && | |
| github.ref == format('refs/heads/{0}', github.event.repository.default_branch)) | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| TAG="${{ github.event.release.tag_name }}" | |
| if [ -z "$TAG" ]; then | |
| # Manual run: aim at the latest published release, the same one the | |
| # install instructions point at. | |
| TAG=$(curl -fsSL -H "Authorization: Bearer $GITHUB_TOKEN" \ | |
| "https://api.github.com/repos/${{ github.repository }}/releases/latest" \ | |
| | sed -n 's/.*"tag_name": *"\([^"]*\)".*/\1/p' | head -1) | |
| fi | |
| if [ -z "$TAG" ]; then | |
| echo "::error::no release to attach to"; exit 1 | |
| fi | |
| echo "tag=$TAG" >> "$GITHUB_OUTPUT" | |
| echo "attaching to $TAG" >> "$GITHUB_STEP_SUMMARY" | |
| - name: Attach to release | |
| if: steps.tag.outputs.tag != '' | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| files: ish-bootstrap/siboot-i686 | |
| tag_name: ${{ steps.tag.outputs.tag }} | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |