name: Build

on: [push, pull_request]

jobs:
  appimage:
    name: AppImage
    runs-on: ubuntu-latest
    steps:
      - name: Install base dependencies
        run: |
          sudo apt-get update -qq
          sudo apt-get install -y --no-install-recommends \
            libopengl0 \
            libegl1

      - name: Install conda dependencies
        id: setup-micromamba
        uses: mamba-org/setup-micromamba@v1
        with:
          environment-name: gqrx
          create-args: >-
            c-compiler
            cxx-compiler
            cmake
            make
            pkg-config
            gnuradio-core
            gnuradio-osmosdr
            libboost-headers
            mesa-libgl-devel-cos6-x86_64
            pybind11
            pulseaudio
            qt6-gtk-platformtheme
            qt6-main
            soapysdr-module-lms7
            soapysdr-module-plutosdr
            soapysdr-module-remote
            volk
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Configure
        shell: bash -el {0}
        run: |
          git config --global --add safe.directory $GITHUB_WORKSPACE
          mkdir build
          cd build
          cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=$CONDA_PREFIX ..
      - name: Compile
        shell: bash -el {0}
        working-directory: build
        run: |
          make -j4
          make install
      - name: Build AppImage
        shell: bash -el {0}
        env:
          APPIMAGE_EXTRACT_AND_RUN: "1"
          PREFIX: ${{ steps.setup-micromamba.outputs.environment-path }}
        run: ./appimage.sh
      - name: Save artifact
        uses: actions/upload-artifact@v4
        with:
          name: gqrx-appimage-${{ github.run_id }}
          path: Gqrx-*.AppImage
  macos:
    name: MacOS
    strategy:
      matrix:
        arch: [x86_64, arm64]
    # NOTE: in the free tier, `macos-13` is x86_64 only, while `macos-14` is arm64 only.
    # when we increase the baseline to 14 eventually, we will be losing x86_64 support,
    # so hopefully all of the macs will be arm64 by then.
    # see https://github.com/actions/runner-images/issues/9741
    runs-on: ${{ matrix.arch == 'x86_64' && 'macos-13' || 'macos-14' }}
    steps:
      - name: Check for Secret availability
        id: secret-check
        run: |
          if [ "${{ secrets.BUILD_CERTIFICATE_BASE64 }}" != '' ]; then
            echo "available=true" >> $GITHUB_OUTPUT;
          else
            echo "available=false" >> $GITHUB_OUTPUT;
          fi
      - name: Install dependencies
        run: |
          uname -a
          # for https://github.com/actions/runner-images/issues/9272
          sudo chown -R runner:admin /usr/local/
          brew update
          brew install --HEAD librtlsdr
          brew install airspy airspyhf boost dylibbundler gnuradio hackrf libbladerf libserialport portaudio pybind11 six soapyremote uhd qt@6 || true

          cd /tmp
          git clone https://github.com/analogdevicesinc/libiio.git
          cd libiio
          git checkout v0.23
          mkdir build
          cd build
          cmake -DCMAKE_BUILD_TYPE=Release ..
          make -j4
          sudo make install

          cd /tmp
          git clone https://github.com/analogdevicesinc/libad9361-iio.git
          cd libad9361-iio
          mkdir build
          cd build
          cmake -DCMAKE_BUILD_TYPE=Release ..
          make -j4
          sudo make install

          cd /tmp
          git clone https://github.com/pothosware/SoapyPlutoSDR.git
          cd SoapyPlutoSDR
          mkdir build
          cd build
          cmake -DCMAKE_BUILD_TYPE=Release ..
          make -j4
          sudo make install

          cd /tmp
          sudo cp /Library/Frameworks/iio.framework/iio /usr/local/lib/libiio.dylib
          sudo install_name_tool -id "/usr/local/lib/libiio.dylib" /usr/local/lib/libiio.dylib
          sudo cp /Library/Frameworks/ad9361.framework/ad9361 /usr/local/lib/libad9361.dylib
          sudo install_name_tool -id "/usr/local/lib/libad9361.dylib" /usr/local/lib/libad9361.dylib
          sudo install_name_tool -delete_rpath /Library/Frameworks /usr/local/lib/libad9361.dylib
          sudo install_name_tool -change @rpath/iio.framework/Versions/0.23/iio /usr/local/lib/libiio.dylib /usr/local/lib/libad9361.dylib
          sudo install_name_tool -change @rpath/iio.framework/Versions/0.23/iio /usr/local/lib/libiio.dylib /usr/local/lib/SoapySDR/modules0.*/libPlutoSDRSupport.so
          sudo install_name_tool -change @rpath/ad9361.framework/Versions/0.2/ad9361 /usr/local/lib/libad9361.dylib /usr/local/lib/SoapySDR/modules0.*/libPlutoSDRSupport.so

          cd /tmp
          git clone https://gitea.osmocom.org/sdr/gr-iqbal.git
          cd gr-iqbal
          git submodule update --init --recursive
          mkdir build
          cd build
          cmake -DCMAKE_BUILD_TYPE=Release ..
          make -j4
          sudo make install

          cd /tmp
          git clone https://gitea.osmocom.org/sdr/gr-osmosdr.git
          cd gr-osmosdr
          mkdir build
          cd build
          cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS=-Wno-register ..
          LIBRARY_PATH=/usr/local/opt/icu4c/lib make -j4
          sudo make install
      - name: Install Apple certificate
        if: ${{ steps.secret-check.outputs.available == 'true' }}
        env:
          BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }}
          P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
          KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
        run: |
          CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
          KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db

          echo -n "$BUILD_CERTIFICATE_BASE64" | base64 -d -o $CERTIFICATE_PATH

          security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
          security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
          security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH

          security import $CERTIFICATE_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
          security list-keychain -d user -s $KEYCHAIN_PATH
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Configure
        run: mkdir build && cd build && cmake -DCMAKE_BUILD_TYPE=Release ..
      - name: Compile
        working-directory: build
        run: make -j4
      - name: Build app bundle
        run: ./macos_bundle.sh ${{ steps.secret-check.outputs.available }}
      - name: Notarize app bundle
        if: ${{ steps.secret-check.outputs.available == 'true' }}
        env:
          NOTARIZE_USERNAME: ${{ secrets.NOTARIZE_USERNAME }}
          NOTARIZE_TEAM_ID: ${{ secrets.NOTARIZE_TEAM_ID }}
          NOTARIZE_PASSWORD: ${{ secrets.NOTARIZE_PASSWORD }}
        run: |
          ditto -c -k --keepParent Gqrx.app Gqrx.zip
          xcrun notarytool submit Gqrx.zip --apple-id "$NOTARIZE_USERNAME" --team-id "$NOTARIZE_TEAM_ID" --password "$NOTARIZE_PASSWORD" --wait
      - name: Staple app bundle
        if: ${{ steps.secret-check.outputs.available == 'true' }}
        run: xcrun stapler staple --verbose Gqrx.app
      - name: Create DMG
        run: |
          GQRX_VERSION=$(<build/version.txt)
          hdiutil create Gqrx.dmg -srcfolder Gqrx.app -format UDZO -fs HFS+ -volname "Gqrx $GQRX_VERSION"
      - name: Notarize DMG
        if: ${{ steps.secret-check.outputs.available == 'true' }}
        env:
          NOTARIZE_USERNAME: ${{ secrets.NOTARIZE_USERNAME }}
          NOTARIZE_TEAM_ID: ${{ secrets.NOTARIZE_TEAM_ID }}
          NOTARIZE_PASSWORD: ${{ secrets.NOTARIZE_PASSWORD }}
        run: |
          xcrun notarytool submit Gqrx.dmg --apple-id "$NOTARIZE_USERNAME" --team-id "$NOTARIZE_TEAM_ID" --password "$NOTARIZE_PASSWORD" --wait
      - name: Staple DMG
        if: ${{ steps.secret-check.outputs.available == 'true' }}
        run: xcrun stapler staple --verbose Gqrx.dmg
      - name: Rename DMG
        run: |
          GQRX_VERSION=$(<build/version.txt)
          mv Gqrx.dmg Gqrx-$GQRX_VERSION.dmg
      - name: Save artifact
        uses: actions/upload-artifact@v4
        with:
          name: gqrx-macos-${{ matrix.arch }}-${{ github.run_id }}
          path: Gqrx-*.dmg
  windows:
    runs-on: windows-latest
    name: Windows
    defaults:
      run:
        shell: msys2 {0}
    steps:
    - name: Setup MSYS2
      uses: msys2/setup-msys2@v2
      with:
        msystem: MINGW64
        update: true
        install: >-
          git
          make
        pacboy: >-
          toolchain:p
          cmake:p
          ninja:p
          libusb:p
          boost:p
          qt6-base:p
          qt6-svg:p
          spdlog:p
          volk:p
          libsndfile:p
          soapysdr:p
          fftw:p
    - name: Clone and build GNU Radio
      working-directory: ${{ runner.temp }}
      run: |
        git clone --branch v3.10.11.0 --depth 1 https://github.com/gnuradio/gnuradio.git
        cd gnuradio
        cmake -S . -B build \
          -DCMAKE_INSTALL_PREFIX=${RUNNER_TEMP}/msys64/mingw64 \
          -DCMAKE_BUILD_TYPE=Release \
          -DENABLE_DEFAULT=OFF \
          -DENABLE_COMMON_PCH=ON \
          -DENABLE_GNURADIO_RUNTIME=ON \
          -DENABLE_GR_ANALOG=ON \
          -DENABLE_GR_AUDIO=ON \
          -DENABLE_GR_BLOCKS=ON \
          -DENABLE_GR_DIGITAL=ON \
          -DENABLE_GR_FFT=ON \
          -DENABLE_GR_FILTER=ON \
          -DENABLE_GR_NETWORK=ON
        cmake --build build
        cmake --install build
    - name: Clone and build rtl-sdr
      working-directory: ${{ runner.temp }}
      run: |
        git clone https://gitea.osmocom.org/sdr/rtl-sdr.git
        cd rtl-sdr
        cmake -S . -B build \
          -DCMAKE_INSTALL_PREFIX=${RUNNER_TEMP}/msys64/mingw64 \
          -DCMAKE_BUILD_TYPE=Release \
          -DDETACH_KERNEL_DRIVER=OFF \
          -DENABLE_ZEROCOPY=OFF \
          -DINSTALL_UDEV_RULES=OFF
        cmake --build build
        cmake --install build
    - name: Clone and build airspyone_host
      working-directory: ${{ runner.temp }}
      run: |
        git clone https://github.com/airspy/airspyone_host.git
        cd airspyone_host
        cmake -S . -B build \
          -G "MinGW Makefiles" \
          -DCMAKE_INSTALL_PREFIX=${RUNNER_TEMP}/msys64/mingw64
        cmake --build build
        cmake --install build
    - name: Clone and build airspyhf
      working-directory: ${{ runner.temp }}
      run: |
        git clone https://github.com/airspy/airspyhf.git
        cd airspyhf
        cmake -S . -B build \
          -G "MSYS Makefiles" \
          -DCMAKE_INSTALL_PREFIX=${RUNNER_TEMP}/msys64/mingw64 \
          -DTHREADS_PTHREADS_INCLUDE_DIR=${RUNNER_TEMP}/msys64/mingw64/include \
          -DTHREADS_PTHREADS_WIN32_LIBRARY=${RUNNER_TEMP}/msys64/mingw64/lib/libpthread.a
        cmake --build build
        cmake --install build
    - name: Clone and build gr-osmosdr
      working-directory: ${{ runner.temp }}
      run: |
        git clone https://gitea.osmocom.org/sdr/gr-osmosdr.git
        cd gr-osmosdr
        cmake -S . -B build \
          -DCMAKE_INSTALL_PREFIX=${RUNNER_TEMP}/msys64/mingw64 \
          -DCMAKE_BUILD_TYPE=Release \
          -DENABLE_DEFAULT=OFF \
          -DENABLE_AIRSPY=ON \
          -DENABLE_AIRSPYHF=ON \
          -DENABLE_FILE=ON \
          -DENABLE_REDPITAYA=ON \
          -DENABLE_RTL=ON \
          -DENABLE_RTL_TCP=ON \
          -DENABLE_SOAPY=ON
        cmake --build build
        cmake --install build
    - name: Configure git
      run: git config --global core.autocrlf input
    - name: Checkout code
      uses: actions/checkout@v4
      with:
        fetch-depth: 0
    - name: Configure, compile & install
      run: |
        cmake -S . -B build \
          -DCMAKE_INSTALL_PREFIX=C:/gqrx \
          -DCMAKE_BUILD_TYPE=Release
        cmake --build build
        cmake --install build
    - name: Deploy Qt application
      working-directory: ${{ runner.temp }}/msys64/mingw64/bin
      run: |
        windeployqt6 C:/gqrx/bin/gqrx.exe
        cp \
          libairspy.dll \
          libairspyhf.dll \
          libb2-1.dll \
          libboost_program_options-mt.dll \
          libboost_thread-mt.dll \
          libbrotlicommon.dll \
          libbrotlidec.dll \
          libbz2-1.dll \
          libdouble-conversion.dll \
          libfftw3f-3.dll \
          libfftw3f_threads-3.dll \
          libFLAC.dll \
          libfmt-11.dll \
          libfreetype-6.dll \
          libgcc_s_seh-1.dll \
          libglib-2.0-0.dll \
          libgmp-10.dll \
          libgnuradio-*.dll \
          libgraphite2.dll \
          libharfbuzz-0.dll \
          libiconv-2.dll \
          libicudt75.dll \
          libicuin75.dll \
          libicuuc75.dll \
          libintl-8.dll \
          libmd4c.dll \
          libmp3lame-0.dll \
          libmpg123-0.dll \
          libogg-0.dll \
          libopus-0.dll \
          liborc-0.4-0.dll \
          libpcre2-16-0.dll \
          libpcre2-8-0.dll \
          libpng16-16.dll \
          librtlsdr.dll \
          libsndfile-1.dll \
          libSoapySDR.dll \
          libspdlog.dll \
          libstdc++-6.dll \
          libusb-1.0.dll \
          libvolk.dll \
          libvorbis-0.dll \
          libvorbisenc-2.dll \
          libwinpthread-1.dll \
          libzstd.dll \
          zlib1.dll \
          C:/gqrx/bin/
    - name: Save artifact
      uses: actions/upload-artifact@v4
      with:
        name: gqrx-windows-${{ github.run_id }}
        path: C:/gqrx/bin
