name: Build with MSVC concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true on: push: branches: - '4.**' - '5.**' - 'trunk' pull_request: # env: # Fully print commands executed by Make # MAKEFLAGS: V=1 defaults: run: shell: bash -eo pipefail -o igncr {0} jobs: config: runs-on: ubuntu-latest outputs: matrix: ${{ steps.matrix.outputs.result}} skip-testsuite: ${{ steps.skip.outputs.result }} steps: - name: Compute matrix for the "build" job id: matrix uses: actions/github-script@v7 with: script: | // # Always test cl and clang-cl let compilers = ['cl', 'clang-cl']; // # Also test i686 MSVC let include = [ {cc: 'cl', arch: 'i686'}]; // # 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'); // # Test Cygwin as well compilers.push('gcc'); // # Test bytecode-only Cygwin include.push({cc: 'gcc', arch: 'x86_64', config_arg: '--disable-native-compiler'}); } } return {config_arg: [''], arch: ['x86_64'], cc: compilers, include: include}; - 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; build: permissions: {} runs-on: windows-latest needs: config timeout-minutes: ${{ matrix.cc == 'gcc' && 90 || 60 }} name: ${{ matrix.cc == 'cl' && 'MSVC' || matrix.cc == 'gcc' && 'Cygwin' || 'clang-cl' }} ${{ matrix.arch }} ${{ matrix.config_arg != '' && format('({0})', matrix.config_arg) || '' }} strategy: matrix: ${{ fromJSON(needs.config.outputs.matrix) }} steps: - name: Fetch OCaml uses: actions/checkout@v4 with: submodules: true - name: Restore Cygwin cache uses: actions/cache/restore@v4 with: path: | C:\cygwin-packages key: cygwin-packages - name: Install Cygwin uses: cygwin/cygwin-install-action@v3 with: packages: make,${{ matrix.cc != 'gcc' && 'mingw64-x86_64-' || 'gcc-fortran,' }}gcc-core install-dir: 'D:\cygwin' - name: Save Cygwin cache uses: actions/cache/save@v4 with: path: | C:\cygwin-packages key: cygwin-packages - name: Set up MSVC uses: ilammy/msvc-dev-cmd@v1 with: arch: ${{ matrix.arch == 'x86_64' && 'x64' || 'x86' }} if: matrix.cc != 'gcc' - name: Compute a key to cache configure results id: autoconf-cache-key env: HOST: ${{ format('{0}-pc-{1}', matrix.arch, (matrix.cc == 'gcc' && 'cygwin' || 'windows')) }} run: | echo "key=${{ env.HOST }}-${{ matrix.cc }}-${{ hashFiles('configure') }}" >> $GITHUB_OUTPUT - name: Restore Autoconf cache uses: actions/cache/restore@v4 with: path: | config.cache key: ${{ steps.autoconf-cache-key.outputs.key }} - name: Configure tree env: CONFIG_ARGS: >- --cache-file=config.cache --prefix "${{ matrix.cc != 'gcc' && '$PROGRAMFILES/Бактріан🐫' || '$(cygpath "$PROGRAMFILES/Бактріан🐫")'}}" ${{ matrix.cc != 'gcc' && format('--host={0}-pc-windows', matrix.arch) || '' }} ${{ matrix.cc != 'gcc' && format('CC={0}', matrix.cc) || '' }} ${{ matrix.config_arg }} run: | eval $(tools/msvs-promote-path) if ! ./configure ${{ env.CONFIG_ARGS }} ; then rm -rf config.cache failed=0 ./configure ${{ env.CONFIG_ARGS }} || failed=$? if ((failed)) ; then echo echo "::group::config.log content ($(wc -l config.log) lines)" cat config.log echo '::endgroup::' exit $failed fi fi - name: Save Autoconf cache uses: actions/cache/save@v4 with: path: | config.cache key: ${{ steps.autoconf-cache-key.outputs.key }} - name: Build OCaml run: | eval $(tools/msvs-promote-path) make -j || failed=$? if ((failed)) ; then make -j1 V=1 ; exit $failed ; fi test -e runtime/libcamlrun.lib || tools/check-symbol-names runtime/*.a otherlibs/*/lib*.a runtime/ocamlrun ocamlc -config - name: Assemble backend with mingw-w64 GASM and compare run: | x86_64-w64-mingw32-gcc -c -I./runtime -I ./flexdll -D__USE_MINGW_ANSI_STDIO=0 -DUNICODE -D_UNICODE -DWINDOWS_UNICODE=1 -DCAMLDLLIMPORT= -DIN_CAML_RUNTIME -DNATIVE_CODE -DTARGET_amd64 -DMODEL_default -DSYS_mingw64 -o runtime/amd64.o runtime/amd64.S dumpbin /disasm:nobytes runtime/amd64nt.obj > runtime/amd64nt.dump awk -f tools/ci/actions/canonicalize-dumpbin.awk runtime/amd64nt.dump runtime/amd64nt.dump > runtime/amd64nt.canonical dumpbin /disasm:nobytes runtime/amd64.o > runtime/amd64.dump awk -f tools/ci/actions/canonicalize-dumpbin.awk runtime/amd64.dump runtime/amd64.dump > runtime/amd64.canonical git diff --no-index -- runtime/amd64*.canonical wc -l runtime/amd64*.dump runtime/amd64*.canonical # ^ The final wc is there to make sure that the canonical files are # reasonable cleaned-up versions of the raw dumpbins and not simply # empty if: endsWith(matrix.arch, '64') && matrix.cc != 'gcc' - name: Run the test suite if: ${{ needs.config.outputs.skip-testsuite != 'true' }} run: | eval $(tools/msvs-promote-path) make tests - name: Install the compiler run: make install