name: CI
on: [push, pull_request]

env:
  ubuntu_image: "ubuntu:22.04"

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@v3

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

      - 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
            make
            make stream'

  macOS-latest:
    runs-on: macOS-latest

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

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

      - name: Build
        run: |
          make
          make stream

  freeBSD-latest:
    runs-on: macos-12

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

      - name: Build
        uses: cross-platform-actions/action@v0.15.0
        with:
          operating_system: freebsd
          version: '13.2'
          run: |
            sudo pkg update
            sudo pkg install -y gmake sdl2
            gmake
            gmake stream

  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@v3

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

      - 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]

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

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

      - 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@v3

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

      - 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'

  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@v3

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

      - 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@v3
        with:
          name: ${{ matrix.jnaPath }}_whisper.dll
          path: build/bin/${{ matrix.build }}/whisper.dll

      - name: Upload binaries
        if: matrix.sdl2 == 'ON'
        uses: actions/upload-artifact@v1
        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
            obzip: https://github.com/OpenMathLib/OpenBLAS/releases/download/v0.3.25/OpenBLAS-0.3.25-x86.zip
            s2arc: x86
            clblast: OFF
          - arch: x64
            obzip: https://github.com/OpenMathLib/OpenBLAS/releases/download/v0.3.25/OpenBLAS-0.3.25-x64.zip
            s2arc: x64
            clblast: ON
            clver: 1.6.1
          - sdl2: ON
            s2ver: 2.28.5

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

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

      - name: Fetch OpenBLAS
        if: matrix.blas == 'ON'
        run: |
          C:/msys64/usr/bin/wget.exe -qO blas.zip ${{ matrix.obzip }}
          7z x blas.zip -oblas -y
          copy blas/include/cblas.h .
          copy blas/include/openblas_config.h .
          echo "OPENBLAS_PATH=$env:GITHUB_WORKSPACE/blas" >> $env:GITHUB_ENV

      - 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: Install OpenCL
        if: matrix.clblast == 'ON'
        run: vcpkg.exe --triplet=${{ matrix.arch }}-windows install opencl

      - name: Fetch CLBlast and set CLBlast_DIR
        if: matrix.clblast == 'ON'
        run: |
          C:/msys64/usr/bin/wget.exe -qO clblast.zip https://github.com/CNugteren/CLBlast/releases/download/${{ matrix.clver }}/CLBlast-${{ matrix.clver }}-windows-x64.zip
          7z x clblast.zip
          7z x CLBlast-${{ matrix.clver }}-windows-x64.7z
          echo "CLBlast_DIR=$env:GITHUB_WORKSPACE/CLBlast-${{ matrix.clver }}-windows-x64/lib/cmake/CLBlast" >> $env:GITHUB_ENV

      - name: Configure
        run: >
          cmake -S . -B ./build -A ${{ matrix.arch }}
          -DCMAKE_BUILD_TYPE=${{ matrix.build }}
          -DWHISPER_OPENBLAS=${{ matrix.blas }}
          -DCMAKE_LIBRARY_PATH="$env:OPENBLAS_PATH/lib"
          -DWHISPER_SDL2=${{ matrix.sdl2 }}
          -DWHISPER_CLBLAST=${{ matrix.clblast }}

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

      - name: Copy libopenblas.dll
        if: matrix.blas == 'ON'
        run: copy "$env:OPENBLAS_PATH/bin/libopenblas.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: Copy clblast.dll
        if: matrix.clblast == 'ON'
        run: copy "$env:CLBlast_DIR/../../clblast.dll" build/bin/${{ matrix.build }}

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

  windows-cublas:
    runs-on: windows-latest

    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@v3

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

      - name: Install CUDA Toolkit
        id: cuda-toolkit
        uses: Jimver/cuda-toolkit@v0.2.11
        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 }}
          -DWHISPER_CUBLAS=${{ 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@v1
        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@v3

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

      - name: Verify
        run: emcc -v

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

  ios:
    runs-on: macos-latest

    strategy:
      matrix:
        build: [Release]

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

      - 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 objc example
        run: xcodebuild -project examples/whisper.objc/whisper.objc.xcodeproj -scheme whisper.objc -configuration ${{ matrix.build }} -sdk iphonesimulator build

      - name: Build swiftui example
        run: xcodebuild -project examples/whisper.swiftui/whisper.swiftui.xcodeproj -scheme WhisperCppDemo -configuration ${{ matrix.build }} -sdk iphonesimulator build

  android:
    runs-on: ubuntu-latest

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

      - name: Install Java
        uses: actions/setup-java@v3
        with:
          distribution: zulu
          java-version: 17

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

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

  android_java:
    runs-on: ubuntu-latest

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

      - name: set up JDK 11
        uses: actions/setup-java@v3
        with:
          java-version: '11'
          distribution: 'temurin'
          cache: gradle

      - name: Setup Android SDK
        uses: android-actions/setup-android@v2
        with:
          api-level: 30
          build-tools-version: 30.0.3

      - name: Build
        run: |
          cd examples/whisper.android.java
          chmod +x ./gradlew 
          ./gradlew assembleRelease

  java:
    needs: [ 'windows' ]
    runs-on: windows-latest
    steps:
      - uses: actions/checkout@v3

      - name: Install Java
        uses: actions/setup-java@v1
        with:
          java-version: 17

      - name: Download Windows lib
        uses: actions/download-artifact@v3
        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@v3
        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@v3

      - name: Test quantize
        run: |
          ./models/download-ggml-model.sh tiny.en
          make quantize
          ./quantize models/ggml-tiny.en.bin models/ggml-tiny.en-q4_0.bin q4_0
