# This file defines pre-commit CI for libc++, libc++abi, and libunwind (on Github).
#
# We split the configurations in multiple stages with the intent of saving compute time
# when a job fails early in the pipeline. This is why the jobs are marked as `continue-on-error: false`.
# We try to run the CI configurations with the most signal in the first stage.
#
# Stages 1 & 2 are meant to be "smoke tests", and are meant to catch most build/test failures quickly and without using
# too many resources.
# Stage 3 is "everything else", and is meant to catch breakages on more niche or unique configurations.
#
# Therefore, we "fail-fast" for any failures during stages 1 & 2, meaning any job failing cancels all other running jobs,
# under the assumption that if the "smoke tests" fail, then the other configurations will likely fail in the same way.
# However, stage 3 does not fail fast, as it's more likely that any one job failing is a flake or a configuration-specific
#
name: Build and Test libc++
on:
  pull_request:
    paths:
      - 'libcxx/**'
      - 'libcxxabi/**'
      - 'libunwind/**'
      - 'runtimes/**'
      - 'cmake/**'
      - '.github/workflows/libcxx-build-and-test.yaml'
  schedule:
    # Run nightly at 08:00 UTC (aka 00:00 Pacific, aka 03:00 Eastern)
    - cron: '0 8 * * *'

permissions:
  contents: read # Default everything to read-only

concurrency:
  group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
  cancel-in-progress: true


env:
  # LLVM POST-BRANCH bump version
  # LLVM POST-BRANCH add compiler test for ToT - 1, e.g. "Clang 17"
  # LLVM RELEASE bump remove compiler ToT - 3, e.g. "Clang 15"
  LLVM_HEAD_VERSION: "19"   # Used compiler, update POST-BRANCH.
  LLVM_PREVIOUS_VERSION: "18"
  LLVM_OLDEST_VERSION: "17"
  GCC_STABLE_VERSION: "13"
  LLVM_SYMBOLIZER_PATH: "/usr/bin/llvm-symbolizer-19"
  CLANG_CRASH_DIAGNOSTICS_DIR: "crash_diagnostics"


jobs:
  stage1:
    if: github.repository_owner == 'llvm'
    runs-on: libcxx-runners-8-set
    continue-on-error: false
    strategy:
      fail-fast: false
      matrix:
        config: [
          'generic-cxx03',
          'generic-cxx26',
          'generic-modules'
        ]
        cc: [  'clang-19' ]
        cxx: [ 'clang++-19' ]
        include:
          - config: 'generic-gcc'
            cc: 'gcc-14'
            cxx: 'g++-14'
    steps:
      - uses: actions/checkout@v4
      - name: ${{ matrix.config }}.${{ matrix.cxx }}
        run: libcxx/utils/ci/run-buildbot ${{ matrix.config }}
        env:
          CC: ${{ matrix.cc }}
          CXX: ${{ matrix.cxx }}
      - uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
        if: always()
        with:
          name: ${{ matrix.config }}-${{ matrix.cxx }}-results
          path: |
            **/test-results.xml
            **/*.abilist
            **/CMakeError.log
            **/CMakeOutput.log
            **/crash_diagnostics/*
  stage2:
    if: github.repository_owner == 'llvm'
    runs-on: libcxx-runners-8-set
    needs: [ stage1 ]
    continue-on-error: false
    strategy:
      fail-fast: false
      matrix:
        config: [
          'generic-cxx11',
          'generic-cxx14',
          'generic-cxx17',
          'generic-cxx20',
          'generic-cxx23'
        ]
        cc: [ 'clang-19' ]
        cxx: [ 'clang++-19' ]
        include:
          - config: 'generic-gcc-cxx11'
            cc: 'gcc-14'
            cxx: 'g++-14'
          - config: 'generic-cxx23'
            cc: 'clang-17'
            cxx: 'clang++-17'
          - config: 'generic-cxx26'
            cc: 'clang-18'
            cxx: 'clang++-18'
    steps:
      - uses: actions/checkout@v4
      - name: ${{ matrix.config }}
        run: libcxx/utils/ci/run-buildbot ${{ matrix.config }}
        env:
          CC: ${{ matrix.cc }}
          CXX: ${{ matrix.cxx }}
      - uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
        if: always()  # Upload artifacts even if the build or test suite fails
        with:
          name: ${{ matrix.config }}-${{ matrix.cxx }}-results
          path: |
            **/test-results.xml
            **/*.abilist
            **/CMakeError.log
            **/CMakeOutput.log
            **/crash_diagnostics/*
  stage3:
    if: github.repository_owner == 'llvm'
    needs: [ stage1, stage2 ]
    continue-on-error: false
    strategy:
      fail-fast: false
      max-parallel: 8
      matrix:
        config: [
          'generic-abi-unstable',
          'generic-hardening-mode-debug',
          'generic-hardening-mode-extensive',
          'generic-hardening-mode-fast',
          'generic-hardening-mode-fast-with-abi-breaks',
          'generic-merged',
          'generic-modules-lsv',
          'generic-no-exceptions',
          'generic-no-experimental',
          'generic-no-filesystem',
          'generic-no-localization',
          'generic-no-random_device',
          'generic-no-threads',
          'generic-no-tzdb',
          'generic-no-unicode',
          'generic-no-wide-characters',
          'generic-no-rtti',
          'generic-optimized-speed',
          'generic-static',
          # TODO Find a better place for the benchmark and bootstrapping builds to live. They're either very expensive
          # or don't provide much value since the benchmark run results are too noise on the bots.
          'benchmarks',
          'bootstrapping-build'
        ]
        machine: [ 'libcxx-runners-8-set' ]
        include:
        - config: 'generic-cxx26'
          machine: libcxx-runners-8-set
        - config: 'generic-asan'
          machine: libcxx-runners-8-set
        - config: 'generic-tsan'
          machine: libcxx-runners-8-set
        - config: 'generic-ubsan'
          machine: libcxx-runners-8-set
        # Use a larger machine for MSAN to avoid timeout and memory allocation issues.
        - config: 'generic-msan'
          machine: libcxx-runners-8-set
    runs-on: ${{ matrix.machine }}
    steps:
      - uses: actions/checkout@v4
      - name: ${{ matrix.config }}
        run: libcxx/utils/ci/run-buildbot ${{ matrix.config }}
        env:
          CC: clang-19
          CXX: clang++-19
      - uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
        if: always()
        with:
          name: ${{ matrix.config }}-results
          path: |
            **/test-results.xml
            **/*.abilist
            **/CMakeError.log
            **/CMakeOutput.log
            **/crash_diagnostics/*
  windows:
    runs-on: windows-2022
    needs: [ stage1 ]
    strategy:
      fail-fast: false
      matrix:
        include:
        - { config: clang-cl-dll, mingw: false }
        - { config: clang-cl-static, mingw: false }
        - { config: clang-cl-no-vcruntime, mingw: false }
        - { config: clang-cl-debug, mingw: false }
        - { config: clang-cl-static-crt, mingw: false }
        - { config: mingw-dll, mingw: true }
        - { config: mingw-static, mingw: true }
        - { config: mingw-dll-i686, mingw: true }
    steps:
      - uses: actions/checkout@v4
      - name: Install dependencies
        run: |
          choco install -y ninja
          pip install psutil
      - name: Install a current LLVM
        if: ${{ matrix.mingw != true }}
        run: |
          choco install -y llvm --version=18.1.6 --allow-downgrade
      - name: Install llvm-mingw
        if: ${{ matrix.mingw == true }}
        run: |
          curl -LO https://github.com/mstorsjo/llvm-mingw/releases/download/20240606/llvm-mingw-20240606-ucrt-x86_64.zip
          powershell Expand-Archive llvm-mingw*.zip -DestinationPath .
          del llvm-mingw*.zip
          mv llvm-mingw* c:\llvm-mingw
          echo "c:\llvm-mingw\bin" | Out-File -FilePath $Env:GITHUB_PATH -Encoding utf8 -Append
      - name: Add Git Bash to the path
        run: |
          echo "c:\Program Files\Git\usr\bin" | Out-File -FilePath $Env:GITHUB_PATH -Encoding utf8 -Append
      - name: Set up the MSVC dev environment
        if: ${{ matrix.mingw != true }}
        uses: ilammy/msvc-dev-cmd@v1
      - name: Build and test
        run: |
          bash libcxx/utils/ci/run-buildbot ${{ matrix.config }}
