name: Reusable Build on: workflow_call: inputs: is_release: description: "Whether this is a release build" required: true type: boolean retention_days: description: "Artifact retention days" required: false type: number default: 1 outputs: resolc-x86_64-unknown-linux-musl_url: value: ${{ jobs.build.outputs.resolc-x86_64-unknown-linux-musl_url }} resolc-x86_64-unknown-linux-musl_sha: value: ${{ jobs.build.outputs.resolc-x86_64-unknown-linux-musl_sha }} resolc-aarch64-apple-darwin_url: value: ${{ jobs.build.outputs.resolc-aarch64-apple-darwin_url }} resolc-aarch64-apple-darwin_sha: value: ${{ jobs.build.outputs.resolc-aarch64-apple-darwin_sha }} resolc-x86_64-apple-darwin_url: value: ${{ jobs.build.outputs.resolc-x86_64-apple-darwin_url }} resolc-x86_64-apple-darwin_sha: value: ${{ jobs.build.outputs.resolc-x86_64-apple-darwin_sha }} resolc-universal-apple-darwin_url: value: ${{ jobs.create-macos-universal.outputs.resolc-universal-apple-darwin_url }} resolc-universal-apple-darwin_sha: value: ${{ jobs.create-macos-universal.outputs.resolc-universal-apple-darwin_sha }} resolc-x86_64-pc-windows-msvc_url: value: ${{ jobs.build.outputs.resolc-x86_64-pc-windows-msvc_url }} resolc-x86_64-pc-windows-msvc_sha: value: ${{ jobs.build.outputs.resolc-x86_64-pc-windows-msvc_sha }} resolc-web_js_url: value: ${{ jobs.build-wasm.outputs.resolc_web_js_url }} resolc-web_js_sha: value: ${{ jobs.build-wasm.outputs.resolc_web_js_sha }} env: CARGO_TERM_COLOR: always RUST_MUSL_CROSS_IMAGE: messense/rust-musl-cross@sha256:2a8837c43bf12e246f1ebd05191de9ee27fcd22f9ca81511ccd4cf75dc16d71c # An empty string is interpreted as the latest published release (default behavior). # To test a specific draft release, use the full name (e.g. "llvm-21.1.8-revive.5789e11"). LLVM_VERSION: "" jobs: build: # github actions matrix jobs don't support multiple outputs # ugly workaround from https://github.com/orgs/community/discussions/17245#discussioncomment-11222880 outputs: resolc-x86_64-unknown-linux-musl_url: ${{ steps.set-output.outputs.resolc-x86_64-unknown-linux-musl_url }} resolc-x86_64-unknown-linux-musl_sha: ${{ steps.set-output.outputs.resolc-x86_64-unknown-linux-musl_sha }} resolc-aarch64-apple-darwin_url: ${{ steps.set-output.outputs.resolc-aarch64-apple-darwin_url }} resolc-aarch64-apple-darwin_sha: ${{ steps.set-output.outputs.resolc-aarch64-apple-darwin_sha }} resolc-x86_64-apple-darwin_url: ${{ steps.set-output.outputs.resolc-x86_64-apple-darwin_url }} resolc-x86_64-apple-darwin_sha: ${{ steps.set-output.outputs.resolc-x86_64-apple-darwin_sha }} resolc-x86_64-pc-windows-msvc_url: ${{ steps.set-output.outputs.resolc-x86_64-pc-windows-msvc_url }} resolc-x86_64-pc-windows-msvc_sha: ${{ steps.set-output.outputs.resolc-x86_64-pc-windows-msvc_sha }} # Queue jobs for the same target and commit instead of running in parallel or cancelling # the first job. This allows the second workflow to use cached builds from the first if # it is triggered by the same commit. # # Example: Workflow A and Workflow B both call this workflow for the same commit: # # Time | Workflow A | Workflow B # -----|---------------------------|--------------------------- # T1 | Job starts, cache miss | # T2 | Building... | Job queued (same group) # T3 | Build done, cache saved | Job queued # T4 | Job finishes | Job starts, cache hit # T5 | | Skips build, job finishes concurrency: # Use `reusable-build` and not `${{ github.workflow }}` here so that callers share the same concurrency group. group: reusable-build-${{ matrix.target }}-${{ github.sha }} cancel-in-progress: false strategy: matrix: target: [ x86_64-unknown-linux-musl, aarch64-apple-darwin, x86_64-apple-darwin, x86_64-pc-windows-msvc, ] include: - target: x86_64-unknown-linux-musl type: musl runner: ubuntu-24.04 - target: aarch64-apple-darwin type: native runner: macos-15 - target: x86_64-apple-darwin type: native # `macos-15-intel` will be the last x86_64 `macos` image supported by GHA. # It will be available until Aug. 2027 (see https://github.com/actions/runner-images/issues/13045). runner: macos-15-intel - target: x86_64-pc-windows-msvc type: native runner: windows-2022 runs-on: ${{ matrix.runner }} steps: - name: Enable long paths (Windows) if: runner.os == 'Windows' run: git config --system core.longpaths true - uses: actions/checkout@v4 # Cache build artifacts by target and commit (restores if available, saves on cache miss). - name: Check Build Cache id: cache uses: actions/cache@v5 with: # Use glob to match binaries with and without extensions. path: resolc-${{ matrix.target }}* key: build-${{ matrix.target }}-${{ github.sha }} - uses: actions-rust-lang/setup-rust-toolchain@v1 if: ${{ steps.cache.outputs.cache-hit != 'true' }} with: rustflags: "" cache-key: ${{ matrix.target }} - name: Download LLVM if: ${{ steps.cache.outputs.cache-hit != 'true' }} uses: ./.github/actions/get-llvm with: target: ${{ matrix.target }} version: ${{ env.LLVM_VERSION }} - name: Build (Native) if: ${{ steps.cache.outputs.cache-hit != 'true' && matrix.type == 'native' }} shell: bash run: | export LLVM_SYS_221_PREFIX=$PWD/llvm-${{ matrix.target }} make install-bin mv target/release/resolc resolc-${{ matrix.target }} || mv target/release/resolc.exe resolc-${{ matrix.target }}.exe - name: Build (MUSL) if: ${{ steps.cache.outputs.cache-hit != 'true' && matrix.type == 'musl' }} run: | docker run -v $PWD:/opt/revive $RUST_MUSL_CROSS_IMAGE /bin/bash -c " cd /opt/revive chown -R root:root . apt update && apt upgrade -y && apt install -y pkg-config export LLVM_SYS_221_PREFIX=/opt/revive/llvm-${{ matrix.target }} make install-bin mv target/${{ matrix.target }}/release/resolc resolc-${{ matrix.target }} " sudo chown -R $(id -u):$(id -g) . - name: Install Solc uses: ./.github/actions/get-solc - name: Basic Sanity Check shell: bash run: | result=$(./resolc-${{ matrix.target }} --bin crates/integration/contracts/flipper.sol) echo $result if [[ $result == *'50564d'* ]]; then exit 0; else exit 1; fi - uses: actions/upload-artifact@v4 id: artifact-upload-step with: name: resolc-${{ matrix.target }} path: resolc-${{ matrix.target }}* retention-days: ${{ inputs.retention_days }} - name: Set output variables if: ${{ !inputs.is_release }} id: set-output shell: bash run: | echo "resolc-${{ matrix.target }}_url=${{ steps.artifact-upload-step.outputs.artifact-url }}" >> "$GITHUB_OUTPUT" echo "resolc-${{ matrix.target }}_sha=${{ steps.artifact-upload-step.outputs.artifact-digest }}" >> "$GITHUB_OUTPUT" create-macos-universal: needs: build runs-on: macos-15 concurrency: # Use `reusable-build` and not `${{ github.workflow }}` here so that callers share the same concurrency group. group: reusable-build-universal-apple-darwin-${{ github.sha }} cancel-in-progress: false outputs: resolc-universal-apple-darwin_url: ${{ steps.set-output.outputs.resolc-universal-apple-darwin_url }} resolc-universal-apple-darwin_sha: ${{ steps.set-output.outputs.resolc-universal-apple-darwin_sha }} steps: - name: Check Build Cache id: cache uses: actions/cache@v5 with: path: resolc-universal-apple-darwin key: build-universal-apple-darwin-${{ github.sha }} - name: Download macOS Artifacts if: ${{ steps.cache.outputs.cache-hit != 'true' }} uses: actions/download-artifact@v4 with: pattern: resolc-*-apple-darwin merge-multiple: true - name: Create macOS Fat Binary if: ${{ steps.cache.outputs.cache-hit != 'true' }} run: | lipo resolc-aarch64-apple-darwin resolc-x86_64-apple-darwin -create -output resolc-universal-apple-darwin chmod +x resolc-universal-apple-darwin - name: Upload Universal Binary uses: actions/upload-artifact@v4 id: artifact-upload-step with: name: resolc-universal-apple-darwin path: resolc-universal-apple-darwin retention-days: ${{ inputs.retention_days }} - name: Set output variables if: ${{ !inputs.is_release }} id: set-output run: | echo "resolc-universal-apple-darwin_url=${{ steps.artifact-upload-step.outputs.artifact-url }}" >> "$GITHUB_OUTPUT" echo "resolc-universal-apple-darwin_sha=${{ steps.artifact-upload-step.outputs.artifact-digest }}" >> "$GITHUB_OUTPUT" build-wasm: runs-on: ubuntu-24.04 outputs: resolc_web_js_url: ${{ steps.set-output.outputs.resolc_web_js_url }} resolc_web_js_sha: ${{ steps.set-output.outputs.resolc_web_js_sha }} # Queue jobs for the same target and commit instead of running in parallel or cancelling # the first job. This allows the second workflow to use cached builds from the first if # it is triggered by the same commit. concurrency: # Use `reusable-build` and not `${{ github.workflow }}` here so that callers share the same concurrency group. group: reusable-build-wasm32-unknown-emscripten-${{ github.sha }} cancel-in-progress: false env: RELEASE_RESOLC_WASM_URI: https://github.com/paritytech/revive/releases/download/${{ github.ref_name }}/resolc.wasm steps: - uses: actions/checkout@v4 # Cache build artifacts by commit (restores if available, saves on cache miss). - name: Check Build Cache id: cache uses: actions/cache@v5 with: path: resolc-wasm32-unknown-emscripten key: build-wasm32-unknown-emscripten-${{ github.sha }} # Pin to 1.92.0 until LLVM WASM libraries are rebuilt with -fwasm-exceptions # See: https://github.com/paritytech/revive/issues/XXX - uses: actions-rust-lang/setup-rust-toolchain@v1 if: ${{ steps.cache.outputs.cache-hit != 'true' }} with: toolchain: "1.92.0" target: wasm32-unknown-emscripten rustflags: "" - name: Download Host LLVM if: ${{ steps.cache.outputs.cache-hit != 'true' }} uses: ./.github/actions/get-llvm with: target: x86_64-unknown-linux-gnu version: ${{ env.LLVM_VERSION }} - name: Download Wasm LLVM if: ${{ steps.cache.outputs.cache-hit != 'true' }} uses: ./.github/actions/get-llvm with: target: wasm32-unknown-emscripten version: ${{ env.LLVM_VERSION }} - name: Download EMSDK if: ${{ steps.cache.outputs.cache-hit != 'true' }} uses: ./.github/actions/get-emsdk - name: Build if: ${{ steps.cache.outputs.cache-hit != 'true' }} run: | export LLVM_SYS_221_PREFIX=$PWD/llvm-x86_64-unknown-linux-gnu export REVIVE_LLVM_TARGET_PREFIX=$PWD/llvm-wasm32-unknown-emscripten source emsdk/emsdk_env.sh make install-wasm chmod -x ./target/wasm32-unknown-emscripten/release/resolc.wasm - name: Compress Artifact if: ${{ steps.cache.outputs.cache-hit != 'true' }} run: | mkdir -p resolc-wasm32-unknown-emscripten mv ./target/wasm32-unknown-emscripten/release/resolc.js ./resolc-wasm32-unknown-emscripten/ mv ./target/wasm32-unknown-emscripten/release/resolc.wasm ./resolc-wasm32-unknown-emscripten/ mv ./target/wasm32-unknown-emscripten/release/resolc_web.js ./resolc-wasm32-unknown-emscripten/ - name: Set Up Node.js uses: actions/setup-node@v3 with: node-version: "20" - name: Basic Sanity Check run: | mkdir -p solc curl -sSLo solc/soljson.js https://github.com/argotorg/solidity/releases/download/v0.8.35/soljson.js node -e " // Make sure to require './solc/soljson' and not 'solc/soljson' in order to use // the explicitly downloaded solc, rather than resolving an npm package potentially // installed in prior workflow steps. const soljson = require('./solc/soljson'); const createRevive = require('./resolc-wasm32-unknown-emscripten/resolc.js'); const compiler = createRevive(); compiler.soljson = soljson; const standardJsonInput = { language: 'Solidity', sources: { 'MyContract.sol': { content: 'pragma solidity ^0.8.0; contract MyContract { function greet() public pure returns (string memory) { return \'Hello\'; } }', }, }, settings: { optimizer: { enabled: false }, outputSelection: { '*': { '*': ['evm.bytecode'] } } } }; compiler.writeToStdin(JSON.stringify(standardJsonInput)); compiler.callMain(['--standard-json']); const stdout = compiler.readFromStdout(); const stderr = compiler.readFromStderr(); if (stderr) { console.error(stderr); process.exit(1); } let out = JSON.parse(stdout); let bytecode = out.contracts['MyContract.sol']['MyContract'].evm.bytecode.object console.log(bytecode); if(!bytecode.startsWith('50564d')) { process.exit(1); } " - name: Upload artifacts (Release) if: ${{ inputs.is_release }} uses: actions/upload-artifact@v4 with: name: resolc-wasm32-unknown-emscripten path: resolc-wasm32-unknown-emscripten/* retention-days: ${{ inputs.retention_days }} # There is no way to upload several files as several artifacts with a single upload-artifact step # It's needed to have resolc_web.js separately for night builds for resolc-bin repo # https://github.com/actions/upload-artifact/issues/331 - name: Upload artifact resolc.js (Nightly) if: ${{ !inputs.is_release }} uses: actions/upload-artifact@v4 with: name: resolc.js path: resolc-wasm32-unknown-emscripten/resolc.js retention-days: ${{ inputs.retention_days }} - name: Upload artifacts resolc.wasm (Nightly) if: ${{ !inputs.is_release }} uses: actions/upload-artifact@v4 with: name: resolc.wasm path: resolc-wasm32-unknown-emscripten/resolc.wasm retention-days: ${{ inputs.retention_days }} - name: Upload artifacts resolc_web.js (Nightly) if: ${{ !inputs.is_release }} uses: actions/upload-artifact@v4 id: artifact-upload-step with: name: resolc_web.js path: resolc-wasm32-unknown-emscripten/resolc_web.js retention-days: ${{ inputs.retention_days }} - name: Set output variables if: ${{ !inputs.is_release }} id: set-output env: TARGET: resolc_web_js run: | echo "${TARGET}_url=${{ steps.artifact-upload-step.outputs.artifact-url }}" >> "$GITHUB_OUTPUT" echo "${TARGET}_sha=${{ steps.artifact-upload-step.outputs.artifact-digest }}" >> "$GITHUB_OUTPUT"