name: Build on: push: branches: - '4.**' - '5.**' - 'trunk' pull_request: # Restrict the GITHUB_TOKEN permissions: {} env: # List of test directories for the debug-s4096 and linux-O0 jobs. These # directories are selected because of their tendencies to reach corner cases # in the runtime system. PARALLEL_TESTS: parallel callback gc-roots weak-ephe-final # Fully print commands executed by Make # MAKEFLAGS: V=1 # https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#concurrency # Concurrent workflows are grouped by the PR or branch that triggered them # (github.ref) and the name of the workflow (github.workflow). The # 'cancel-in-progress' option then make sure that only one workflow is running # at a time. This doesn't prevent new jobs from running, rather it cancels # already running jobs before scheduling new jobs. concurrency: group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name == 'pull_request' || github.sha }} cancel-in-progress: true jobs: # This job will do the initial build of the compiler (on linux), with flambda on. # We then upload the compiler tree as a build artifact to enable re-use in # subsequent jobs. build: runs-on: ubuntu-latest outputs: manual_changed: ${{ steps.manual.outputs.manual_changed }} steps: - name: Checkout uses: actions/checkout@v4 with: persist-credentials: false - name: Check for manual changes id: manual run: >- tools/ci/actions/check-manual-modified.sh '${{ github.ref }}' '${{ github.event_name }}' '${{ github.event.pull_request.base.ref }}' '${{ github.event.pull_request.base.sha }}' '${{ github.event.pull_request.head.ref }}' '${{ github.event.pull_request.head.sha }}' '${{ github.event.ref }}' '${{ github.event.before }}' '${{ github.event.ref }}' '${{ github.event.after }}' '${{ github.event.repository.full_name }}' - name: Configure tree run: | MAKE_ARG=-j CONFIG_ARG='--enable-flambda --enable-cmm-invariants --enable-codegen-invariants --enable-dependency-generation --enable-native-toplevel' OCAMLRUNPARAM=b,v=0 bash -xe tools/ci/actions/runner.sh configure - name: Build run: | MAKE_ARG=-j bash -xe tools/ci/actions/runner.sh build - name: Prepare Artifact run: tar --zstd -cf /tmp/sources.tar.zstd . - name: Upload Artifact uses: actions/upload-artifact@v4 with: name: compiler path: /tmp/sources.tar.zstd retention-days: 1 # Full testsuite run, and other sanity checks # "extra" testsuite runs, reusing the previously built compiler tree. # debug: running the full testsuite with the # debug runtime and minor heap verification. # debug-s4096: select testsuite run with the debug runtime and a small # minor heap. normal: name: ${{ matrix.name }} needs: [build, config] runs-on: ubuntu-latest strategy: matrix: include: - id: normal name: normal dependencies: texlive-latex-extra texlive-fonts-recommended texlive-luatex hevea sass gdb lldb - id: debug name: extra (debug) - id: debug-s4096 name: extra (debug-s4096) steps: - name: Download Artifact uses: actions/download-artifact@v4 with: name: compiler - name: Unpack Artifact run: | tar --zstd -xf sources.tar.zstd rm -f sources.tar.zstd - name: Packages if: matrix.dependencies != '' run: | sudo apt-get update -y sudo apt-get install -y ${{ matrix.dependencies }} - name: Run the testsuite if: ${{ matrix.id == 'normal' && needs.config.outputs.skip-testsuite != 'true' }} run: | MAKE_ARG=-j OCAMLRUNPARAM=b,v=0 bash -xe tools/ci/actions/runner.sh test - name: Run the testsuite (debug runtime) if: ${{ matrix.id == 'debug' && needs.config.outputs.skip-testsuite != 'true' }} env: OCAMLRUNPARAM: v=0,V=1 USE_RUNTIME: d run: | bash -cxe "SHOW_TIMINGS=1 tools/ci/actions/runner.sh test" - name: Run the testsuite (s=4096, debug runtime) if: ${{ matrix.id == 'debug-s4096' && needs.config.outputs.skip-testsuite != 'true' }} env: OCAMLRUNPARAM: s=4096,v=0 USE_RUNTIME: d run: | for dir in $PARALLEL_TESTS; do \ bash -cxe "SHOW_TIMINGS=1 tools/ci/actions/runner.sh test_prefix $dir"; \ done - name: Build API Documentation if: matrix.id == 'normal' run: | MAKE_ARG=-j OCAMLRUNPARAM=b,v=0 bash -xe tools/ci/actions/runner.sh api-docs - name: Install if: matrix.id == 'normal' run: | MAKE_ARG=-j OCAMLRUNPARAM=b,v=0 bash -xe tools/ci/actions/runner.sh install - name: Test in prefix if: matrix.id == 'normal' run: | MAKE_ARG=-j OCAMLRUNPARAM=b,v=0 bash -xe tools/ci/actions/runner.sh test-in-prefix - name: Build the manual if: matrix.id == 'normal' && needs.build.outputs.manual_changed == 'true' run: | MAKE_ARG=-j OCAMLRUNPARAM=b,v=0 bash -xe tools/ci/actions/runner.sh manual - name: Other checks if: matrix.id == 'normal' run: | MAKE_ARG=-j OCAMLRUNPARAM=b,v=0 bash -xe tools/ci/actions/runner.sh other-checks # macOS build+testsuite run, and other Linux configurations (-O0, etc.) config: runs-on: ubuntu-latest outputs: jobs: ${{ steps.jobs.outputs.result }} skip-testsuite: ${{ steps.skip.outputs.result }} steps: - name: Compute matrix for the "others" job id: jobs uses: actions/github-script@v7 with: script: | // # Default jobs: Linux -O0, Linux arm64 & macOS let jobs = [ {name: 'linux-O0', os: 'ubuntu-latest', config_arg: "CFLAGS='-O0'"}, {name: 'linux-arm64', os: 'ubuntu-24.04-arm', 'test-in-prefix': true}, {name: 'macos-x86_64', os: 'macos-13', 'test-in-prefix': true}, {name: 'macos-arm64', os: 'macos-15', 'test-in-prefix': true}]; // # If this is a pull request, see if the PR has the // # 'CI: Full matrix' label. This is done using an API request, // # rather than from context.payload.pull_request.labels, since we // # want the _current_ list of labels. This allows the labelling to // # be changed, and then forcing a re-run of the workflow, rather // # than having labelling triggering a fresh workflow event (which // # is wasteful). if (context.payload.pull_request) { const { data: labels } = await github.rest.issues.listLabelsOnIssue({...context.repo, issue_number: context.payload.pull_request.number}); if (labels.some(label => label.name === 'CI: Full matrix')) { console.log('Full matrix requested'); // # Add "static" and "minimal" jobs jobs = jobs.concat([ {name: 'static', os: 'ubuntu-latest', config_arg: '--disable-native-toplevel --disable-shared', 'test-in-prefix': true}, {name: 'minimal', os: 'ubuntu-latest', config_arg: '--disable-native-toplevel --disable-native-compiler --disable-shared --disable-debug-runtime --disable-instrumented-runtime --disable-systhreads --disable-str-lib --disable-unix-lib --disable-ocamldoc'}]); } } return jobs; - name: Determine if the testsuite should be skipped id: skip uses: actions/github-script@v7 with: script: | let skip_testsuite = false; if (context.payload.pull_request) { const { data: labels } = await github.rest.issues.listLabelsOnIssue({...context.repo, issue_number: context.payload.pull_request.number}); skip_testsuite = labels.some(label => label.name === 'CI: Skip testsuite'); } console.log('Skip testsuite: ' + skip_testsuite); return skip_testsuite; others: name: ${{ matrix.name }} needs: config runs-on: ${{ matrix.os }} strategy: matrix: include: ${{ fromJSON(needs.config.outputs.jobs) }} steps: - name: Checkout uses: actions/checkout@v4 with: persist-credentials: false - name: macOS Dependencies if: startsWith(matrix.os, 'macos-') run: | brew install parallel # Allows starting up lldb from a remote terminal # Note: in order to start lldb, the user must also be in # one of these groups: "admin" or "_developer". sudo DevToolsSecurity --enable spctl developer-mode enable-terminal # Select latest supported version sudo xcode-select -s /Applications/Xcode_${{ matrix.os == 'macos-13' && '15.2' || '16.3' }}.app/Contents/Developer lldb --version - name: configure tree run: | CONFIG_ARG='--enable-codegen-invariants ${{ matrix.config_arg }}' MAKE_ARG=-j bash -xe tools/ci/actions/runner.sh configure - name: Build run: | MAKE_ARG=-j bash -xe tools/ci/actions/runner.sh build - name: Run the testsuite if: ${{ matrix.name != 'linux-O0' && needs.config.outputs.skip-testsuite != 'true' }} run: | bash -c 'SHOW_TIMINGS=1 tools/ci/actions/runner.sh test' - name: Run the testsuite (linux-O0) if: ${{ matrix.name == 'linux-O0' && needs.config.outputs.skip-testsuite != 'true' }} env: OCAMLRUNPARAM: v=0,V=1 USE_RUNTIME: d run: | for dir in $PARALLEL_TESTS; do \ bash -cxe "SHOW_TIMINGS=1 tools/ci/actions/runner.sh test_prefix $dir"; \ done - name: Install if: ${{ matrix.test-in-prefix }} run: | MAKE_ARG=-j OCAMLRUNPARAM=b,v=0 bash -xe tools/ci/actions/runner.sh install - name: Test in prefix if: ${{ matrix.test-in-prefix }} run: | MAKE_ARG=-j OCAMLRUNPARAM=b,v=0 bash -xe tools/ci/actions/runner.sh test-in-prefix i386: runs-on: ubuntu-latest needs: config container: image: debian:12 options: --platform linux/i386 --user root steps: - name: OS Dependencies run: | apt-get update -y apt-get install -y git gcc make parallel adduser --disabled-password --gecos '' ocaml - name: Checkout # See https://github.com/actions/checkout/issues/334 uses: actions/checkout@v1 - name: configure tree run: | chown -R ocaml:ocaml . MAKE_ARG=-j CONFIG_ARG='--disable-native-toplevel' su ocaml -c "bash -xe tools/ci/actions/runner.sh configure" - name: Build run: | MAKE_ARG=-j su ocaml -c "bash -xe tools/ci/actions/runner.sh build" - name: Run the testsuite if: ${{ needs.config.outputs.skip-testsuite != 'true' }} run: | su ocaml -c "bash -xe tools/ci/actions/runner.sh test" - name: Install run: | su ocaml -c "bash -xe tools/ci/actions/runner.sh install" - name: Test in prefix run: | su ocaml -c "bash -xe tools/ci/actions/runner.sh test-in-prefix"