name: CI
on: [push, pull_request]

env:
  ubuntu_image: "ubuntu:22.04"
  VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite"

jobs:
  ubuntu-latest:
    runs-on: ubuntu-latest

    strategy:
      fail-fast: false
      matrix:
        arch: [linux/amd64, linux/arm64, linux/arm/v7, linux/ppc64le]

    steps:
      - name: Clone
        uses: actions/checkout@v4

      - name: Set up QEMU
        uses: docker/setup-qemu-action@v3

      - name: Build ${{ matrix.arch }}
        run: |
          docker run --platform ${{ matrix.arch }} --rm \
            -v ${{ github.workspace }}:/workspace \
            -w /workspace ${{ env.ubuntu_image }} /bin/sh -c '
            set -e
            apt update
            apt install -y build-essential libsdl2-dev cmake
            cmake -B build
            cmake --build build --config Release -j $(nproc)'

  macOS-latest:
    runs-on: macOS-latest

    steps:
      - name: Clone
        uses: actions/checkout@v4

      - name: Dependencies
        run: |
          brew update
          brew install sdl2 cmake

      - name: Build
        run: |
          cmake -B build
          cmake --build build --config Release

#  freeBSD-latest:
#    runs-on: macos-12
#
#    steps:
#      - name: Clone
#        uses: actions/checkout@v4
#
#      - name: Build
#        uses: cross-platform-actions/action@v0.24.0
#        with:
#          operating_system: freebsd
#          version: '13.3'
#          run: |
#            sudo pkg update
#            sudo pkg install -y gmake sdl2 cmake
#            cmake -B build
#            cmake --build build --config Release

  ubuntu-latest-gcc:
    runs-on: ubuntu-latest

    strategy:
      fail-fast: false
      matrix:
        build: [Debug, Release]
        arch: [linux/amd64, linux/arm64, linux/arm/v7, linux/ppc64le]

    steps:
      - name: Clone
        uses: actions/checkout@v4

      - name: Set up QEMU
        uses: docker/setup-qemu-action@v3

      - name: Build ${{ matrix.arch }}
        run: |
          docker run --platform ${{ matrix.arch }} --rm \
            -v ${{ github.workspace }}:/workspace \
            -w /workspace ${{ env.ubuntu_image }} /bin/sh -c '
            set -e
            apt update
            apt install -y build-essential cmake libsdl2-dev
            cmake . -DWHISPER_SDL2=ON -DCMAKE_BUILD_TYPE=${{ matrix.build }}
            make
            ctest -L gh --output-on-failure'

  ubuntu-latest-clang:
    runs-on: ubuntu-latest

    strategy:
      fail-fast: false
      matrix:
        build: [Debug, Release]
        #arch: [linux/amd64, linux/arm64, linux/arm/v7, linux/ppc64le]
        # TODO: arm/v7 disabled due to clang bug
        #       https://github.com/ggerganov/whisper.cpp/actions/runs/9657764109/job/26637633042?pr=2256#step:4:1990
        arch: [linux/amd64, linux/arm64, linux/ppc64le]

    steps:
      - name: Clone
        uses: actions/checkout@v4

      - name: Set up QEMU
        uses: docker/setup-qemu-action@v3

      - name: Build ${{ matrix.arch }}
        run: |
          docker run --platform ${{ matrix.arch }} --rm \
            -v ${{ github.workspace }}:/workspace \
            -w /workspace ${{ env.ubuntu_image }} /bin/sh -c '
            set -e
            apt update
            apt install -y clang build-essential cmake libsdl2-dev
            cmake . -DWHISPER_SDL2=ON -DCMAKE_BUILD_TYPE=${{ matrix.build }} -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang
            make
            ctest -L gh --output-on-failure'

  ubuntu-latest-gcc-sanitized:
    runs-on: ubuntu-latest

    strategy:
      fail-fast: false
      matrix:
        sanitizer: [ADDRESS, THREAD, UNDEFINED]
        arch: [linux/amd64]

    steps:
      - name: Clone
        uses: actions/checkout@v4

      - name: Set up QEMU
        uses: docker/setup-qemu-action@v3

      - name: Build ${{ matrix.arch }}
        run: |
          docker run --platform ${{ matrix.arch }} --rm \
            -v ${{ github.workspace }}:/workspace \
            -w /workspace ${{ env.ubuntu_image }} /bin/sh -c '
            set -e
            apt update
            apt install -y build-essential cmake
            cmake . -DCMAKE_BUILD_TYPE=Debug -DWHISPER_SANITIZE_${{ matrix.sanitizer }}=ON
            make
            ctest -L gh --output-on-failure'

  ubuntu-22-cmake-sycl:
    runs-on: ubuntu-22.04

    strategy:
      fail-fast: false
      matrix:
        dwhisper_sycl: [ON]
        dcmake_c_compiler: [icx]
        dcmake_cxx_compiler: [icpx]
        arch: [linux/amd64, linux/arm64, linux/arm/v7, linux/ppc64le]

    continue-on-error: true

    steps:
      - name: Clone
        uses: actions/checkout@v4

      - name: add oneAPI to apt
        shell: bash
        run: |
          cd /tmp
          wget https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB
          sudo apt-key add GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB
          rm GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB
          sudo add-apt-repository "deb https://apt.repos.intel.com/oneapi all main"

      - name: install oneAPI dpcpp compiler
        shell: bash
        run: |
          sudo apt update
          sudo apt install intel-oneapi-compiler-dpcpp-cpp

      - name: install oneAPI MKL library
        shell: bash
        run: |
          sudo apt install intel-oneapi-mkl-devel

      - name: Clone
        id: checkout
        uses: actions/checkout@v4

      - name: Build
        id: cmake_build
        run: |
          source /opt/intel/oneapi/setvars.sh
          mkdir build
          cd build
          cmake -DGGML_SYCL=ON -DCMAKE_C_COMPILER=icx -DCMAKE_CXX_COMPILER=icpx ..
          cmake --build . --config Release -j $(nproc)

  ubuntu-22-cmake-sycl-fp16:
    runs-on: ubuntu-22.04

    strategy:
      fail-fast: false
      matrix:
        dwhisper_sycl: [ON]
        dcmake_c_compiler: [icx]
        dcmake_cxx_compiler: [icpx]
        arch: [linux/amd64, linux/arm64, linux/arm/v7, linux/ppc64le]

    continue-on-error: true

    steps:
      - name: Clone
        uses: actions/checkout@v4

      - name: add oneAPI to apt
        shell: bash
        run: |
          cd /tmp
          wget https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB
          sudo apt-key add GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB
          rm GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB
          sudo add-apt-repository "deb https://apt.repos.intel.com/oneapi all main"

      - name: install oneAPI dpcpp compiler
        shell: bash
        run: |
          sudo apt update
          sudo apt install intel-oneapi-compiler-dpcpp-cpp

      - name: install oneAPI MKL library
        shell: bash
        run: |
          sudo apt install intel-oneapi-mkl-devel

      - name: Clone
        id: checkout
        uses: actions/checkout@v4

      - name: Build
        id: cmake_build
        run: |
          source /opt/intel/oneapi/setvars.sh
          mkdir build
          cd build
          cmake -DGGML_SYCL_F16=ON -DCMAKE_C_COMPILER=icx -DCMAKE_CXX_COMPILER=icpx ..
          cmake --build . --config Release -j $(nproc)

  windows-msys2:
    runs-on: windows-latest

    strategy:
      fail-fast: false
      matrix:
        include:
          - { sys: UCRT64,  env: ucrt-x86_64,  build: Release }
          - { sys: CLANG64, env: clang-x86_64, build: Release }

    steps:
      - name: Clone
        uses: actions/checkout@v4

      - name: Setup ${{ matrix.sys }}
        uses: msys2/setup-msys2@v2
        with:
          update: true
          msystem: ${{matrix.sys}}
          install: >-
            base-devel
            mingw-w64-${{matrix.env}}-toolchain
            mingw-w64-${{matrix.env}}-cmake
            mingw-w64-${{matrix.env}}-SDL2
            mingw-w64-${{matrix.env}}-openblas

      - name: Build using CMake
        shell: msys2 {0}
        run: |
            cmake -B build -DWHISPER_SDL2=ON
            cmake --build build --config ${{ matrix.build }} -j $(nproc)

      - name: Clean after building using CMake
        shell: msys2 {0}
        run: |
            rm -rf build

      - name: Build using CMake w/ OpenBLAS
        shell: msys2 {0}
        run: |
            cmake -B build -DGGML_BLAS=ON -DGGML_BLAS_VENDOR=OpenBLAS
            cmake --build build --config ${{ matrix.build }} -j $(nproc)

  windows:
    runs-on: windows-latest

    strategy:
      matrix:
        build: [Release]
        arch: [Win32, x64]
        sdl2: [ON]
        include:
          - arch: Win32
            s2arc: x86
            jnaPath: win32-x86
          - arch: x64
            s2arc: x64
            jnaPath: win32-x86-64
          - sdl2: ON
            s2ver: 2.28.5

    steps:
      - name: Clone
        uses: actions/checkout@v4

      - name: Add msbuild to PATH
        uses: microsoft/setup-msbuild@v2

      - name: Fetch SDL2 and set SDL2_DIR
        if: matrix.sdl2 == 'ON'
        run: |
          C:/msys64/usr/bin/wget.exe -qO sdl2.zip https://github.com/libsdl-org/SDL/releases/download/release-${{ matrix.s2ver }}/SDL2-devel-${{ matrix.s2ver }}-VC.zip
          7z x sdl2.zip
          echo "SDL2_DIR=$env:GITHUB_WORKSPACE/SDL2-${{ matrix.s2ver }}/cmake" >> $env:GITHUB_ENV

      - name: Configure
        run: >
          cmake -S . -B ./build -A ${{ matrix.arch }}
          -DCMAKE_BUILD_TYPE=${{ matrix.build }}
          -DWHISPER_SDL2=${{ matrix.sdl2 }}

      - name: Build
        run: |
          cd ./build
          msbuild ALL_BUILD.vcxproj -t:build -p:configuration=${{ matrix.build }} -p:platform=${{ matrix.arch }}

      - name: Copy SDL2.dll
        if: matrix.sdl2 == 'ON'
        run: copy "$env:SDL2_DIR/../lib/${{ matrix.s2arc }}/SDL2.dll" build/bin/${{ matrix.build }}

      - name: Upload dll
        uses: actions/upload-artifact@v4
        with:
          name: ${{ matrix.jnaPath }}_whisper.dll
          path: build/bin/${{ matrix.build }}/whisper.dll

      - name: Upload binaries
        if: matrix.sdl2 == 'ON'
        uses: actions/upload-artifact@v4
        with:
          name: whisper-bin-${{ matrix.arch }}
          path: build/bin/${{ matrix.build }}

  windows-blas:
    runs-on: windows-latest

    strategy:
      matrix:
        build: [Release]
        arch: [Win32, x64]
        blas: [ON]
        sdl2: [ON]
        include:
          - arch: Win32
            s2arc: x86
          - arch: x64
            s2arc: x64
          - sdl2: ON
            s2ver: 2.28.5

    steps:
      - name: Clone
        uses: actions/checkout@v4

      - name: Export GitHub Actions cache environment variables
        uses: actions/github-script@v7
        with:
          script: |
            core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || '');
            core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || '');

      - name: Add msbuild to PATH
        uses: microsoft/setup-msbuild@v2

      - name: Install OpenBLAS and pkgconfiglite
        if: matrix.blas == 'ON'
        run: |
          vcpkg install --triplet=${{ matrix.s2arc }}-windows openblas
          choco install pkgconfiglite

      - name: Fetch SDL2 and set SDL2_DIR
        if: matrix.sdl2 == 'ON'
        run: |
          C:/msys64/usr/bin/wget.exe -qO sdl2.zip https://github.com/libsdl-org/SDL/releases/download/release-${{ matrix.s2ver }}/SDL2-devel-${{ matrix.s2ver }}-VC.zip
          7z x sdl2.zip
          echo "SDL2_DIR=$env:GITHUB_WORKSPACE/SDL2-${{ matrix.s2ver }}/cmake" >> $env:GITHUB_ENV

      - name: Configure
        run: >
          cmake -S . -B ./build -A ${{ matrix.arch }}
          -DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_INSTALLATION_ROOT/scripts/buildsystems/vcpkg.cmake"
          -DCMAKE_BUILD_TYPE=${{ matrix.build }}
          -DGGML_BLAS=${{ matrix.blas }}
          -DGGML_BLAS_VENDOR=OpenBLAS
          -DWHISPER_SDL2=${{ matrix.sdl2 }}

      - name: Build
        run: |
          cd ./build
          msbuild ALL_BUILD.vcxproj -t:build -p:configuration=${{ matrix.build }} -p:platform=${{ matrix.arch }}

      - name: Copy openblas.dll
        if: matrix.blas == 'ON'
        run: copy "C:/vcpkg/packages/openblas_${{ matrix.s2arc }}-windows/bin/openblas.dll" build/bin/${{ matrix.build }}

      - name: Copy SDL2.dll
        if: matrix.sdl2 == 'ON'
        run: copy "$env:SDL2_DIR/../lib/${{ matrix.s2arc }}/SDL2.dll" build/bin/${{ matrix.build }}

      - name: Upload binaries
        if: matrix.blas == 'ON' && matrix.sdl2 == 'ON'
        uses: actions/upload-artifact@v4
        with:
          name: whisper-blas-bin-${{ matrix.arch }}
          path: build/bin/${{ matrix.build }}

# TODO: fix and re-enable
#  windows-cublas:
#    runs-on: windows-2019
#
#    strategy:
#      matrix:
#        build: [Release]
#        arch: [x64]
#        cublas: [ON]
#        sdl2: [ON]
#        cuda-toolkit: [12.2.0, 11.8.0]
#        include:
#          - arch: x64
#            s2arc: x64
#          - sdl2: ON
#            s2ver: 2.28.5
#
#    steps:
#      - name: Clone
#        uses: actions/checkout@v4
#
#      - name: Add msbuild to PATH
#        uses: microsoft/setup-msbuild@v2
#
#      - name: Install CUDA Toolkit
#        id: cuda-toolkit
#        uses: Jimver/cuda-toolkit@v0.2.15
#        with:
#          cuda: '${{ matrix.cuda-toolkit }}'
#
#      - name: Fetch SDL2 and set SDL2_DIR
#        if: matrix.sdl2 == 'ON'
#        run: |
#          C:/msys64/usr/bin/wget.exe -qO sdl2.zip https://github.com/libsdl-org/SDL/releases/download/release-${{ matrix.s2ver }}/SDL2-devel-${{ matrix.s2ver }}-VC.zip
#          7z x sdl2.zip
#          echo "SDL2_DIR=$env:GITHUB_WORKSPACE/SDL2-${{ matrix.s2ver }}/cmake" >> $env:GITHUB_ENV
#
#      - name: Configure
#        run: >
#          cmake -S . -B ./build -A ${{ matrix.arch }}
#          -DCMAKE_BUILD_TYPE=${{ matrix.build }}
#          -DGGML_CUDA=${{ matrix.cublas }}
#          -DWHISPER_SDL2=${{ matrix.sdl2 }}
#
#      - name: Build ${{ matrix.cuda-toolkit }}
#        run: |
#          cd ./build
#          cmake --build . --config ${{ matrix.build }}
#
#      - name: Copy CUDA DLLs
#        run: >
#          Copy-Item -PassThru
#          -Path "${{ steps.cuda-toolkit.outputs.CUDA_PATH }}/bin/*.dll"
#          -Include cudart64_*,cublas64_*,cublasLt64_*
#          -Destination build/bin/${{ matrix.build }}
#
#      - name: Copy SDL2.dll
#        if: matrix.sdl2 == 'ON'
#        run: copy "$env:SDL2_DIR/../lib/${{ matrix.s2arc }}/SDL2.dll" build/bin/${{ matrix.build }}
#
#      - name: Upload binaries
#        if: matrix.sdl2 == 'ON'
#        uses: actions/upload-artifact@v4
#        with:
#          name: whisper-cublas-${{ matrix.cuda-toolkit }}-bin-${{ matrix.arch }}
#          path: build/bin/${{ matrix.build }}

  emscripten:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        build: [Release]

    steps:
      - name: Clone
        uses: actions/checkout@v4

      - name: Setup emsdk
        uses: mymindstorm/setup-emsdk@v14

      - name: Verify
        run: emcc -v

      - name: Build
        run: |
          emcmake cmake . -DCMAKE_BUILD_TYPE=${{ matrix.build }}
          make

  ios-xcode-build:
    runs-on: macos-latest

    strategy:
      matrix:
        build: [Release]

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Configure
        run: |
          cp models/for-tests-ggml-base.en.bin models/ggml-base.en.bin
          mkdir models/ggml-base.en-encoder.mlmodelc

      - name: Build
        id: cmake_build
        run: |
          sysctl -a
          mkdir build
          cd build
          cmake -G Xcode .. \
            -DGGML_METAL_USE_BF16=ON \
            -DGGML_METAL_EMBED_LIBRARY=ON \
            -DWHISPER_BUILD_EXAMPLES=OFF \
            -DWHISPER_BUILD_TESTS=OFF \
            -DWHISPER_BUILD_SERVER=OFF \
            -DCMAKE_SYSTEM_NAME=iOS \
            -DCMAKE_OSX_DEPLOYMENT_TARGET=14.0 \
            -DCMAKE_XCODE_ATTRIBUTE_DEVELOPMENT_TEAM=ggml
          cmake --build . --config Release -j $(sysctl -n hw.logicalcpu) -- CODE_SIGNING_ALLOWED=NO
          sudo cmake --install . --config Release

      - name: xcodebuild for swift package
        id: xcodebuild
        run: |
          xcodebuild -scheme whisper-Package -destination 'generic/platform=iOS'

#- name: Build objc example
#  run: xcodebuild -project examples/whisper.objc/whisper.objc.xcodeproj -scheme whisper.objc -configuration ${{ matrix.build }} -sdk iphoneos build

      - name: Build swiftui example
        run: xcodebuild -project examples/whisper.swiftui/whisper.swiftui.xcodeproj -scheme WhisperCppDemo -configuration ${{ matrix.build }} -sdk iphoneos CODE_SIGNING_REQUIRED=NO CODE_SIGN_IDENTITY= -destination 'generic/platform=iOS' build

  android:
    runs-on: ubuntu-latest

    steps:
      - name: Clone
        uses: actions/checkout@v4
        with:
          path: whisper

      - name: Install Java
        uses: actions/setup-java@v4
        with:
          distribution: zulu
          java-version: 21

      - name: Setup Android SDK
        uses: android-actions/setup-android@v3

      - name: Build
        run: |
          cd whisper/examples/whisper.android
          ./gradlew assembleRelease --no-daemon

      - name: Build with external ggml
        run: |
          export PATH_TO_GGML=$PWD/ggml
          cd whisper/examples/whisper.android
          ./gradlew assembleRelease --no-daemon

# TODO: disable because of following fail: https://github.com/ggerganov/whisper.cpp/actions/runs/11019444420/job/30627193602
#  android_java:
#    runs-on: ubuntu-latest
#
#    steps:
#      - name: Clone
#        uses: actions/checkout@v4
#
#      - name: set up JDK 11
#        uses: actions/setup-java@v4
#        with:
#          java-version: '11'
#          distribution: 'temurin'
#          cache: gradle
#
#      - name: Setup Android SDK
#        uses: android-actions/setup-android@v3
#        with:
#          cmdline-tools-version: 9.0
#
#      - name: Build
#        run: |
#          cd examples/whisper.android.java
#          chmod +x ./gradlew
#          ./gradlew assembleRelease

# TODO: disabled because of following fail: https://github.com/ggerganov/whisper.cpp/actions/runs/9686220096/job/26735899598
#  java:
#    needs: [ 'windows' ]
#    runs-on: windows-latest
#    steps:
#      - uses: actions/checkout@v4
#
#      - name: Install Java
#        uses: actions/setup-java@v4
#        with:
#          distribution: zulu
#          java-version: 20
#
#      - name: Download Windows lib
#        uses: actions/download-artifact@v4
#        with:
#          name: win32-x86-64_whisper.dll
#          path: bindings/java/build/generated/resources/main/win32-x86-64
#
#      - name: Build
#        run: |
#          models\download-ggml-model.cmd tiny.en
#          cd bindings/java
#          chmod +x ./gradlew
#          ./gradlew build
#
#      - name: Upload jar
#        uses: actions/upload-artifact@v4
#        with:
#          name: whispercpp.jar
#          path: bindings/java/build/libs/whispercpp-*.jar
#
#      - name: Publish package
#        if: ${{ github.ref == 'refs/heads/master' }}
#        uses: gradle/gradle-build-action@v2.4.2
#        with:
#          arguments: publish
#          build-root-directory: bindings/java
#        env:
#          MAVEN_USERNAME: ${{ secrets.JIRA_USER }}
#          MAVEN_PASSWORD: ${{ secrets.JIRA_PASS }}
#          PGP_SECRET: ${{ secrets.GPG_PRIVATE_KEY }}
#          PGP_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}

  quantize:
    runs-on: ubuntu-latest

    steps:
      - name: Clone
        uses: actions/checkout@v4

      - name: Test quantize
        run: |
          ./models/download-ggml-model.sh tiny.en
          cmake -B build
          cmake --build build --config Release
          ./build/bin/quantize models/ggml-tiny.en.bin models/ggml-tiny.en-q4_0.bin q4_0
