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 '
            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 '
            apt update
            apt install -y build-essential cmake libsdl2-dev
            cmake . -DWHISPER_SUPPORT_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 '
            apt update
            apt install -y build-essential cmake libsdl2-dev
            cmake . -DWHISPER_SUPPORT_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 '
            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.26.0

    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_SUPPORT_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/xianyi/OpenBLAS/releases/download/v0.3.21/OpenBLAS-0.3.21-x86.zip
            s2arc: x86
          - arch: x64
            obzip: https://github.com/xianyi/OpenBLAS/releases/download/v0.3.21/OpenBLAS-0.3.21-x64.zip
            s2arc: x64
          - sdl2: ON
            s2ver: 2.26.0

    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 "blasdir=$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: Configure
        run: >
          cmake -S . -B ./build -A ${{ matrix.arch }}
          -DCMAKE_BUILD_TYPE=${{ matrix.build }}
          -DWHISPER_SUPPORT_OPENBLAS=${{ matrix.blas }}
          -DCMAKE_LIBRARY_PATH="$env:blasdir/lib"
          -DWHISPER_SUPPORT_SDL2=${{ matrix.sdl2 }}

      - 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:blasdir/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: Upload binaries
        if: matrix.blas == 'ON' && matrix.sdl2 == 'ON'
        uses: actions/upload-artifact@v1
        with:
          name: whisper-blas-bin-${{ matrix.arch }}
          path: build/bin/${{ matrix.build }}

  windows-cublas:
    runs-on: windows-latest

    strategy:
      matrix:
        build: [Release]
        arch: [x64]
        cublas: [ON]
        sdl2: [ON]
        include:
          - arch: x64
            s2arc: x64
          - sdl2: ON
            s2ver: 2.26.0

    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.10

      - 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=1

      - 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 binaries
        if: matrix.sdl2 == 'ON'
        uses: actions/upload-artifact@v1
        with:
          name: whisper-cublas-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

  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
