name: build

on: [push, pull_request]

permissions: read-all

env:
  LIBBPF_VERSION: v1.4.6
  OPENSSL1_VERSION: 1_1_1w+quic
  OPENSSL3_VERSION: 3.1.7+quic
  BORINGSSL_VERSION: 76968bb3d53982560bcf08bcd0ba3e1865fe15cd
  AWSLC_VERSION: v1.36.1
  NGHTTP3_VERSION: v1.6.0
  NGTCP2_VERSION: v1.8.1
  WOLFSSL_VERSION: v5.7.2-stable

jobs:
  build-cache:
    strategy:
      matrix:
        os: [ubuntu-24.04, macos-13, macos-14]

    runs-on: ${{ matrix.os }}

    steps:
    - name: Checkout
      uses: actions/checkout@v4
    - name: Restore libbpf cache
      id: cache-libbpf
      uses: actions/cache@v4
      if: runner.os == 'Linux'
      with:
        path: libbpf/build
        key: ${{ matrix.os }}-libbpf-${{ env.LIBBPF_VERSION }}
    - name: Restore OpenSSL v1.1.1 cache
      id: cache-openssl1
      uses: actions/cache@v4
      with:
        path: openssl1/build
        key: ${{ matrix.os }}-openssl-${{ env.OPENSSL1_VERSION }}
    - name: Restore OpenSSL v3.x cache
      id: cache-openssl3
      uses: actions/cache@v4
      with:
        path: openssl3/build
        key: ${{ matrix.os }}-openssl-${{ env.OPENSSL3_VERSION }}
    - name: Restore BoringSSL cache
      id: cache-boringssl
      uses: actions/cache@v4
      with:
        path: |
          boringssl/build/crypto/libcrypto.a
          boringssl/build/ssl/libssl.a
          boringssl/include
        key: ${{ matrix.os }}-boringssl-${{ env.BORINGSSL_VERSION }}
    - name: Restore aws-lc cache
      id: cache-awslc
      uses: actions/cache@v4
      with:
        path: |
          aws-lc/build/crypto/libcrypto.a
          aws-lc/build/ssl/libssl.a
          aws-lc/include
        key: ${{ matrix.os }}-awslc-${{ env.AWSLC_VERSION }}
    - name: Restore wolfSSL cache
      id: cache-wolfssl
      uses: actions/cache@v4
      with:
        path: wolfssl/build
        key: ${{ matrix.os }}-wolfssl-${{ env.WOLFSSL_VERSION }}
    - name: Restore nghttp3 cache
      id: cache-nghttp3
      uses: actions/cache@v4
      with:
        path: nghttp3/build
        key: ${{ matrix.os }}-nghttp3-${{ env.NGHTTP3_VERSION }}
    - name: Restore ngtcp2 + quictls/openssl v1.1.1 cache
      id: cache-ngtcp2-openssl1
      uses: actions/cache@v4
      with:
        path: ngtcp2-openssl1/build
        key: ${{ matrix.os }}-ngtcp2-${{ env.NGTCP2_VERSION }}-openssl-${{ env.OPENSSL1_VERSION }}
    - name: Restore ngtcp2 + quictls/openssl v3.x cache
      id: cache-ngtcp2-openssl3
      uses: actions/cache@v4
      with:
        path: ngtcp2-openssl3/build
        key: ${{ matrix.os }}-ngtcp2-${{ env.NGTCP2_VERSION }}-openssl-${{ env.OPENSSL3_VERSION }}
    - id: settings
      if: |
        (steps.cache-libbpf.outputs.cache-hit != 'true' && runner.os == 'Linux') ||
        steps.cache-openssl1.outputs.cache-hit != 'true' ||
        steps.cache-openssl3.outputs.cache-hit != 'true' ||
        steps.cache-boringssl.outputs.cache-hit != 'true' ||
        steps.cache-awslc.outputs.cache-hit != 'true' ||
        steps.cache-wolfssl.outputs.cache-hit != 'true' ||
        steps.cache-nghttp3.outputs.cache-hit != 'true' ||
        steps.cache-ngtcp2-openssl1.outputs.cache-hit != 'true' ||
        steps.cache-ngtcp2-openssl3.outputs.cache-hit != 'true'
      run: |
        echo 'needs-build=true' >> $GITHUB_OUTPUT
    - name: Linux setup
      if: runner.os == 'Linux' && steps.settings.outputs.needs-build == 'true'
      run: |
        sudo apt-get update
        sudo apt-get install \
          autoconf \
          automake \
          autotools-dev \
          libtool \
          pkg-config \
          libelf-dev \
          cmake \
          cmake-data
    - name: MacOS setup
      if: runner.os == 'macOS' && steps.settings.outputs.needs-build == 'true'
      run: |
        brew install \
          autoconf \
          automake \
          pkg-config \
          libtool
    - name: Build libbpf
      if: steps.cache-libbpf.outputs.cache-hit != 'true' && runner.os == 'Linux'
      run: |
        git clone --recursive --shallow-submodules -b ${{ env.LIBBPF_VERSION }} https://github.com/libbpf/libbpf
        cd libbpf
        make -C src install PREFIX=$PWD/build
    - name: Build quictls/openssl v1.1.1
      if: steps.cache-openssl1.outputs.cache-hit != 'true'
      run: |
        git clone --recursive --shallow-submodules --depth 1 -b OpenSSL_${{ env.OPENSSL1_VERSION }} https://github.com/quictls/openssl openssl1
        cd openssl1
        ./config --prefix=$PWD/build
        make -j"$(nproc 2> /dev/null || sysctl -n hw.ncpu)"
        make install_sw
    - name: Build quictls/openssl v3.x
      if: steps.cache-openssl3.outputs.cache-hit != 'true'
      run: |
        git clone --recursive --shallow-submodules --depth 1 -b openssl-${{ env.OPENSSL3_VERSION }} https://github.com/quictls/openssl openssl3
        cd openssl3
        ./config enable-ktls --prefix=$PWD/build --libdir=$PWD/build/lib
        make -j"$(nproc 2> /dev/null || sysctl -n hw.ncpu)"
        make install_sw
    - name: Build BoringSSL
      if: steps.cache-boringssl.outputs.cache-hit != 'true'
      run: |
        mkdir boringssl
        cd boringssl
        git init
        git remote add origin https://boringssl.googlesource.com/boringssl
        git fetch origin --depth 1 ${{ env.BORINGSSL_VERSION }}
        git checkout ${{ env.BORINGSSL_VERSION }}
        mkdir build
        cd build
        cmake -DCMAKE_POSITION_INDEPENDENT_CODE=ON ..
        make -j"$(nproc 2> /dev/null || sysctl -n hw.ncpu)"
    - name: Build aws-lc
      if: steps.cache-awslc.outputs.cache-hit != 'true'
      run: |
        git clone --recursive --shallow-submodules --depth 1 -b "${AWSLC_VERSION}" https://github.com/aws/aws-lc
        cd aws-lc
        cmake -B build -DDISABLE_GO=ON
        make -j"$(nproc 2> /dev/null || sysctl -n hw.ncpu)" -C build
    - name: Build wolfSSL
      if: steps.cache-wolfssl.outputs.cache-hit != 'true'
      run: |
        git clone --depth 1 -b ${{ env.WOLFSSL_VERSION }} https://github.com/wolfSSL/wolfssl
        cd wolfssl
        autoreconf -i
        ./configure --disable-dependency-tracking --prefix=$PWD/build \
          --enable-all --enable-harden --disable-ech
        make -j"$(nproc 2> /dev/null || sysctl -n hw.ncpu)"
        make install
    - name: Build nghttp3
      if: steps.cache-nghttp3.outputs.cache-hit != 'true'
      run: |
        git clone --recursive --shallow-submodules --depth 1 -b ${{ env.NGHTTP3_VERSION}} https://github.com/ngtcp2/nghttp3
        cd nghttp3
        autoreconf -i
        ./configure --disable-dependency-tracking --prefix=$PWD/build \
          --enable-lib-only
        make -j"$(nproc 2> /dev/null || sysctl -n hw.ncpu)" check
        make install
    - name: Build ngtcp2 + quictls/openssl v1.1.1 + BoringSSL
      if: steps.cache-ngtcp2-openssl1.outputs.cache-hit != 'true'
      run: |
        git clone --recursive --shallow-submodules --depth 1 -b ${{ env.NGTCP2_VERSION }} https://github.com/ngtcp2/ngtcp2 ngtcp2-openssl1
        cd ngtcp2-openssl1
        autoreconf -i
        ./configure --prefix=$PWD/build --enable-lib-only \
          PKG_CONFIG_PATH="../openssl1/build/lib/pkgconfig:../wolfssl/build/lib/pkgconfig" \
          BORINGSSL_CFLAGS="-I$PWD/../boringssl/include/" \
          BORINGSSL_LIBS="-L$PWD/../boringssl/build/ssl -lssl -L$PWD/../boringssl/build/crypto -lcrypto" \
          --disable-dependency-tracking \
          --with-boringssl \
          --with-wolfssl
        make -j"$(nproc 2> /dev/null || sysctl -n hw.ncpu)" check
        make install
    - name: Build ngtcp2 + quictls/openssl v3.x + aws-lc
      if: steps.cache-ngtcp2-openssl3.outputs.cache-hit != 'true'
      run: |
        git clone --recursive --shallow-submodules --depth 1 -b ${{ env.NGTCP2_VERSION }} https://github.com/ngtcp2/ngtcp2 ngtcp2-openssl3
        cd ngtcp2-openssl3
        autoreconf -i
        ./configure --prefix=$PWD/build --enable-lib-only \
          PKG_CONFIG_PATH="../openssl3/build/lib/pkgconfig" \
          BORINGSSL_CFLAGS="-I$PWD/../aws-lc/include/" \
          BORINGSSL_LIBS="-L$PWD/../aws-lc/build/ssl -lssl -L$PWD/../aws-lc/build/crypto -lcrypto" \
          --disable-dependency-tracking \
          --with-boringssl
        make -j"$(nproc 2> /dev/null || sysctl -n hw.ncpu)" check
        make install

  build:
    needs:
    - build-cache

    strategy:
      matrix:
        os: [ubuntu-24.04, macos-13, macos-14]
        compiler: [gcc, clang]
        buildtool: [autotools, cmake]
        http3: [http3, no-http3]
        openssl: [openssl1, openssl3, boringssl, awslc, wolfssl]
        exclude:
        - os: macos-13
          openssl: openssl3
        - os: macos-14
          openssl: openssl3
        - http3: no-http3
          openssl: openssl3
        - os: macos-13
          compiler: gcc
        - os: macos-14
          compiler: gcc
        - # disable macos cmake because of include path issue
          os: macos-13
          buildtool: cmake
        - # disable macos cmake because of include path issue
          os: macos-14
          buildtool: cmake
        - os: macos-13
          openssl: boringssl
        - os: macos-14
          openssl: boringssl
        - openssl: boringssl
          buildtool: cmake
        - openssl: boringssl
          compiler: gcc
        - os: macos-13
          openssl: awslc
        - os: macos-14
          openssl: awslc
        - openssl: awslc
          buildtool: cmake
        - openssl: awslc
          compiler: gcc
        include:
        - os: ubuntu-24.04
          compiler: clang
          buildtool: distcheck
          http3: http3
          openssl: awslc

    runs-on: ${{ matrix.os }}

    steps:
    - name: Checkout
      uses: actions/checkout@v4
      with:
        submodules: recursive
    - name: Linux setup
      if: runner.os == 'Linux'
      run: |
        sudo apt-get update
        sudo apt-get install \
          g++-14 \
          clang-18 \
          autoconf \
          automake \
          autotools-dev \
          libtool \
          pkg-config \
          zlib1g-dev \
          libssl-dev \
          libxml2-dev \
          libev-dev \
          libevent-dev \
          libjansson-dev \
          libjemalloc-dev \
          libc-ares-dev \
          libelf-dev \
          libbrotli-dev \
          cmake \
          cmake-data
        echo 'CPPFLAGS=-fsanitize=address,undefined -fno-sanitize-recover=undefined -g' >> $GITHUB_ENV
        echo 'LDFLAGS=-fsanitize=address,undefined -fno-sanitize-recover=undefined' >> $GITHUB_ENV

        # https://github.com/actions/runner-images/issues/9491#issuecomment-1989718917
        # Asan in llvm 14 provided in ubuntu 22.04 is incompatible with
        # high-entropy ASLR in much newer kernels that GitHub runners are
        # using leading to random crashes: https://reviews.llvm.org/D148280
        sudo sysctl vm.mmap_rnd_bits=28
    - name: MacOS setup
      if: runner.os == 'macOS'
      run: |
        brew install \
          libev \
          libressl \
          autoconf \
          automake \
          libtool
        echo 'PKG_CONFIG_PATH=/usr/local/opt/libressl/lib/pkgconfig:/usr/local/opt/libxml2/lib/pkgconfig' >> $GITHUB_ENV
    - name: Setup clang (Linux)
      if: runner.os == 'Linux' && matrix.compiler == 'clang'
      run: |
        echo 'CC=clang-18' >> $GITHUB_ENV
        echo 'CXX=clang++-18' >> $GITHUB_ENV
    - name: Setup clang (MacOS)
      if: runner.os == 'macOS' && matrix.compiler == 'clang'
      run: |
        echo 'CC=clang' >> $GITHUB_ENV
        echo 'CXX=clang++' >> $GITHUB_ENV
    - name: Setup gcc (Linux)
      if: runner.os == 'Linux' && matrix.compiler == 'gcc'
      run: |
        echo 'CC=gcc-14' >> $GITHUB_ENV
        echo 'CXX=g++-14' >> $GITHUB_ENV
        # g++-12 is known to produce false positive warnings.
        echo 'CXXFLAGS=-Wno-restrict' >> $GITHUB_ENV
    - name: Setup gcc (MacOS)
      if: runner.os == 'macOS' && matrix.compiler == 'gcc'
      run: |
        echo 'CC=gcc' >> $GITHUB_ENV
        echo 'CXX=g++' >> $GITHUB_ENV
    - name: Restore libbpf cache
      uses: actions/cache/restore@v4
      if: matrix.http3 == 'http3' && matrix.compiler == 'clang' && runner.os == 'Linux'
      with:
        path: libbpf/build
        key: ${{ matrix.os }}-libbpf-${{ env.LIBBPF_VERSION }}
        fail-on-cache-miss: true
    - name: Set libbpf variables
      if: matrix.http3 == 'http3' && matrix.compiler == 'clang' && runner.os == 'Linux'
      run: |
        cd libbpf

        EXTRA_AUTOTOOLS_OPTS="$EXTRA_AUTOTOOLS_OPTS --with-libbpf"
        EXTRA_CMAKE_OPTS="$EXTRA_CMAKE_OPTS -DWITH_LIBBPF=1"

        echo 'EXTRA_AUTOTOOLS_OPTS='"$EXTRA_AUTOTOOLS_OPTS" >> $GITHUB_ENV
        echo 'EXTRA_CMAKE_OPTS='"$EXTRA_CMAKE_OPTS" >> $GITHUB_ENV
    - name: Setup libev variables
      if: matrix.os == 'macos-14'
      run: |
        LIBEV_CFLAGS="-I/opt/homebrew/Cellar/libev/4.33/include"
        LIBEV_LIBS="-L/opt/homebrew/Cellar/libev/4.33/lib -lev"

        echo 'LIBEV_CFLAGS='"$LIBEV_CFLAGS" >> $GITHUB_ENV
        echo 'LIBEV_LIBS='"$LIBEV_LIBS" >> $GITHUB_ENV
    - name: Restore quictls/openssl v1.1.1 cache
      uses: actions/cache/restore@v4
      if: matrix.openssl == 'openssl1'
      with:
        path: openssl1/build
        key: ${{ matrix.os }}-openssl-${{ env.OPENSSL1_VERSION }}
        fail-on-cache-miss: true
    - name: Restore quictls/openssl v3.x cache
      uses: actions/cache/restore@v4
      if: matrix.openssl == 'openssl3'
      with:
        path: openssl3/build
        key: ${{ matrix.os }}-openssl-${{ env.OPENSSL3_VERSION }}
        fail-on-cache-miss: true
    - name: Restore BoringSSL cache
      uses: actions/cache/restore@v4
      if: matrix.openssl == 'boringssl'
      with:
        path: |
          boringssl/build/crypto/libcrypto.a
          boringssl/build/ssl/libssl.a
          boringssl/include
        key: ${{ matrix.os }}-boringssl-${{ env.BORINGSSL_VERSION }}
        fail-on-cache-miss: true
    - name: Restore aws-lc cache
      uses: actions/cache/restore@v4
      if: matrix.openssl == 'awslc'
      with:
        path: |
          aws-lc/build/crypto/libcrypto.a
          aws-lc/build/ssl/libssl.a
          aws-lc/include
        key: ${{ matrix.os }}-awslc-${{ env.AWSLC_VERSION }}
        fail-on-cache-miss: true
    - name: Set BoringSSL variables
      if: matrix.openssl == 'boringssl'
      run: |
        cd boringssl

        OPENSSL_CFLAGS="-I$PWD/include/"
        OPENSSL_LIBS="-L$PWD/build/ssl -lssl -L$PWD/build/crypto -lcrypto -pthread"
        EXTRA_AUTOTOOLS_OPTS="$EXTRA_AUTOTOOLS_OPTS --without-neverbleed --without-jemalloc --disable-examples"

        echo 'OPENSSL_CFLAGS='"$OPENSSL_CFLAGS" >> $GITHUB_ENV
        echo 'OPENSSL_LIBS='"$OPENSSL_LIBS" >> $GITHUB_ENV
        echo 'BORINGSSL_CFLAGS='"$OPENSSL_CFLAGS" >> $GITHUB_ENV
        echo 'BORINGSSL_LIBS='"$OPENSSL_LIBS" >> $GITHUB_ENV
        echo 'EXTRA_AUTOTOOLS_OPTS='"$EXTRA_AUTOTOOLS_OPTS" >> $GITHUB_ENV
    - name: Set aws-lc variables
      if: matrix.openssl == 'awslc'
      run: |
        cd aws-lc

        OPENSSL_CFLAGS="-I$PWD/include/"
        OPENSSL_LIBS="-L$PWD/build/ssl -lssl -L$PWD/build/crypto -lcrypto -pthread"
        EXTRA_AUTOTOOLS_OPTS="$EXTRA_AUTOTOOLS_OPTS --without-neverbleed --without-jemalloc"

        echo 'OPENSSL_CFLAGS='"$OPENSSL_CFLAGS" >> $GITHUB_ENV
        echo 'OPENSSL_LIBS='"$OPENSSL_LIBS" >> $GITHUB_ENV
        echo 'BORINGSSL_CFLAGS='"$OPENSSL_CFLAGS" >> $GITHUB_ENV
        echo 'BORINGSSL_LIBS='"$OPENSSL_LIBS" >> $GITHUB_ENV
        echo 'EXTRA_AUTOTOOLS_OPTS='"$EXTRA_AUTOTOOLS_OPTS" >> $GITHUB_ENV
    - name: Restore wolfSSL cache
      uses: actions/cache/restore@v4
      if: matrix.openssl == 'wolfssl'
      with:
        path: wolfssl/build
        key: ${{ matrix.os }}-wolfssl-${{ env.WOLFSSL_VERSION }}
        fail-on-cache-miss: true
    - name: Set wolfSSL variables
      if: matrix.openssl == 'wolfssl'
      run: |
        EXTRA_AUTOTOOLS_OPTS="$EXTRA_AUTOTOOLS_OPTS --with-wolfssl --without-neverbleed"
        EXTRA_CMAKE_OPTS="$EXTRA_CMAKE_OPTS -DWITH_WOLFSSL=1 -DWITH_NEVERBLEED=0 -DENABLE_EXAMPLES=0"

        echo 'EXTRA_AUTOTOOLS_OPTS='"$EXTRA_AUTOTOOLS_OPTS" >> $GITHUB_ENV
        echo 'EXTRA_CMAKE_OPTS='"$EXTRA_CMAKE_OPTS" >> $GITHUB_ENV
    - name: Restore nghttp3 cache
      uses: actions/cache/restore@v4
      if: matrix.http3 == 'http3'
      with:
        path: nghttp3/build
        key: ${{ matrix.os }}-nghttp3-${{ env.NGHTTP3_VERSION }}
        fail-on-cache-miss: true
    - name: Restore ngtcp2 + quictls/openssl v1.1.1 cache + BoringSSL
      uses: actions/cache/restore@v4
      if: matrix.http3 == 'http3' && (matrix.openssl == 'openssl1' || matrix.openssl == 'boringssl' || matrix.openssl == 'wolfssl')
      with:
        path: ngtcp2-openssl1/build
        key: ${{ matrix.os }}-ngtcp2-${{ env.NGTCP2_VERSION }}-openssl-${{ env.OPENSSL1_VERSION }}
        fail-on-cache-miss: true
    - name: Restore ngtcp2 + quictls/openssl v3.x cache + aws-lc
      uses: actions/cache/restore@v4
      if: matrix.http3 == 'http3' && (matrix.openssl == 'openssl3' || matrix.openssl == 'awslc')
      with:
        path: ngtcp2-openssl3/build
        key: ${{ matrix.os }}-ngtcp2-${{ env.NGTCP2_VERSION }}-openssl-${{ env.OPENSSL3_VERSION }}
        fail-on-cache-miss: true
    - name: Setup extra environment variables
      if: matrix.http3 == 'no-http3'
      run: |
        PKG_CONFIG_PATH="$PWD/openssl1/build/lib/pkgconfig:$PWD/openssl3/build/lib/pkgconfig:$PWD/wolfssl/build/lib/pkgconfig:$PKG_CONFIG_PATH"
        LDFLAGS="$LDFLAGS -Wl,-rpath,$PWD/openssl1/build/lib -Wl,-rpath,$PWD/openssl3/build/lib"

        echo 'PKG_CONFIG_PATH='"$PKG_CONFIG_PATH" >> $GITHUB_ENV
        echo 'LDFLAGS='"$LDFLAGS" >> $GITHUB_ENV
    - name: Setup extra environment variables for HTTP/3
      if: matrix.http3 == 'http3'
      run: |
        PKG_CONFIG_PATH="$PWD/openssl1/build/lib/pkgconfig:$PWD/openssl3/build/lib/pkgconfig:$PWD/wolfssl/build/lib/pkgconfig:$PWD/nghttp3/build/lib/pkgconfig:$PWD/ngtcp2-openssl1/build/lib/pkgconfig:$PWD/ngtcp2-openssl3/build/lib/pkgconfig:$PWD/libbpf/build/lib64/pkgconfig:$PKG_CONFIG_PATH"
        LDFLAGS="$LDFLAGS -Wl,-rpath,$PWD/openssl1/build/lib -Wl,-rpath,$PWD/openssl3/build/lib -Wl,-rpath,$PWD/libbpf/build/lib64"
        EXTRA_AUTOTOOLS_OPTS="$EXTRA_AUTOTOOLS_OPTS --enable-http3"
        EXTRA_CMAKE_OPTS="$EXTRA_CMAKE_OPTS -DENABLE_HTTP3=1"

        echo 'PKG_CONFIG_PATH='"$PKG_CONFIG_PATH" >> $GITHUB_ENV
        echo 'LDFLAGS='"$LDFLAGS" >> $GITHUB_ENV
        echo 'EXTRA_AUTOTOOLS_OPTS='"$EXTRA_AUTOTOOLS_OPTS" >> $GITHUB_ENV
        echo 'EXTRA_CMAKE_OPTS='"$EXTRA_CMAKE_OPTS" >> $GITHUB_ENV
    - name: Configure autotools
      run: |
        autoreconf -i
        ./configure --disable-dependency-tracking
    - name: Make distribution and unpack
      if: matrix.buildtool != 'distcheck'
      run: |
        make dist
        VERSION=$(grep PACKAGE_VERSION config.h | cut -d' ' -f3 | tr -d '"')
        tar xf nghttp2-$VERSION.tar.gz
        cd nghttp2-$VERSION
        echo 'NGHTTP2_BUILD_DIR='"$PWD" >> $GITHUB_ENV
    - name: Configure cmake (Linux)
      if: matrix.buildtool == 'cmake' && runner.os == 'Linux'
      run: |
        cd $NGHTTP2_BUILD_DIR

        cmake -DENABLE_WERROR=1 -DWITH_MRUBY=1 -DWITH_NEVERBLEED=1 -DENABLE_APP=1 $EXTRA_CMAKE_OPTS -DCPPFLAGS="$CPPFLAGS" -DLDFLAGS="$LDFLAGS" -DBUILD_STATIC_LIBS=ON -DBUILD_TESTING=ON .
    - name: Configure cmake (MacOS)
      if: matrix.buildtool == 'cmake' && runner.os == 'macOS'
      run: |
        # This fixes infamous 'stdio.h not found' error.
        echo 'SDKROOT='"$(xcrun --sdk macosx --show-sdk-path)" >> $GITHUB_ENV

        cd $NGHTTP2_BUILD_DIR

        cmake -DENABLE_WERROR=1 -DWITH_MRUBY=1 -DENABLE_APP=1 $EXTRA_CMAKE_OPTS -DCPPFLAGS="$CPPFLAGS" -DLDFLAGS="$LDFLAGS" -DBUILD_STATIC_LIBS=ON -DBUILD_TESTING=ON .
    - name: Build nghttp2 with autotools (Linux)
      if: matrix.buildtool == 'autotools' && runner.os == 'Linux'
      run: |
        cd $NGHTTP2_BUILD_DIR

        ./configure --disable-dependency-tracking --with-mruby --with-neverbleed --with-libev --with-libbrotlienc --with-libbrotlidec --enable-werror $EXTRA_AUTOTOOLS_OPTS
        make -j"$(nproc)" check
    - name: Build nghttp2 with autotools (MacOS)
      if: matrix.buildtool == 'autotools' && runner.os == 'macOS'
      run: |
        cd $NGHTTP2_BUILD_DIR

        ./configure --disable-dependency-tracking --with-mruby --with-libev --with-libbrotlienc --with-libbrotlidec --enable-werror $EXTRA_AUTOTOOLS_OPTS
        make -j"$(sysctl -n hw.ncpu)" check
    - name: Build nghttp2 with autotools (distcheck)
      if: matrix.buildtool == 'distcheck'
      run: |
        make -j"$(nproc)" distcheck \
          DISTCHECK_CONFIGURE_FLAGS="--with-mruby --with-neverbleed --with-libev --with-libbrotlienc --with-libbrotlidec --enable-werror $EXTRA_AUTOTOOLS_OPTS CPPFLAGS=\"$CPPFLAGS\" LDFLAGS=\"$LDFLAGS\""
    - name: Build nghttp2 with cmake
      if: matrix.buildtool == 'cmake'
      run: |
        cd $NGHTTP2_BUILD_DIR
        make -j"$(nproc 2> /dev/null || sysctl -n hw.ncpu)"
        make -j"$(nproc 2> /dev/null || sysctl -n hw.ncpu)" check
    - uses: actions/setup-go@v5
      if: matrix.buildtool != 'distcheck'
      with:
        go-version: "1.22"
    - name: Integration test
      # Integration tests for nghttpx; autotools erases build
      # artifacts.
      if: matrix.buildtool != 'distcheck'
      run: |
        cd $NGHTTP2_BUILD_DIR/integration-tests
        make it

  build-cross:
    strategy:
      matrix:
        host: [x86_64-w64-mingw32, i686-w64-mingw32]

    runs-on: ubuntu-24.04

    env:
      HOST: ${{ matrix.host }}

    steps:
    - name: Checkout
      uses: actions/checkout@v4
      with:
        submodules: recursive
    - name: Prepare for i386
      if: matrix.host == 'i686-w64-mingw32'
      run: |
        sudo dpkg --add-architecture i386
    - name: Linux setup
      run: |
        sudo apt-get update
        sudo apt-get install \
          gcc-mingw-w64 \
          autoconf \
          automake \
          autotools-dev \
          libtool \
          pkg-config \
          wine
    - name: Configure autotools
      run: |
        autoreconf -i && \
        ./configure --disable-dependency-tracking --enable-werror \
          --enable-lib-only  --host="$HOST" \
          CFLAGS="-g -O2 -D_WIN32_WINNT=0x0600" LIBS="-pthread"
    - name: Build nghttp2
      run: |
        make -j$(nproc)
        make -j$(nproc) check TESTS=""
    - name: Run tests
      run: |
        export WINEPATH="/usr/${{ matrix.host }}/lib;$(winepath -w /usr/lib/x86_64-linux-gnu/wine/x86_64-windows)"
        cd tests
        wine main.exe

  build-windows:
    strategy:
      matrix:
        arch: [x86, x64]
        include:
        - arch: x86
          platform: Win32
        - arch: x64
          platform: x64

    runs-on: windows-latest

    steps:
    - name: Checkout
      uses: actions/checkout@v4
      with:
        submodules: recursive
    - uses: microsoft/setup-msbuild@v2
    - name: Configure cmake
      run: cmake -B build -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake -DCMAKE_GENERATOR_PLATFORM=${{ matrix.platform }} -DVCPKG_TARGET_TRIPLET=${{ matrix.arch}}-windows -DBUILD_STATIC_LIBS=ON -DBUILD_TESTING=ON
    - name: Build nghttp2
      run: |
        cmake --build build
        cmake --build build --target check

  release:
    if: github.ref_type == 'tag'

    needs:
    - build
    - build-cross
    - build-windows

    permissions:
      contents: write

    runs-on: ubuntu-24.04

    steps:
    - uses: actions/checkout@v4
      with:
        fetch-depth: 0
        submodules: recursive
    - name: Make artifacts
      run: |
        ver='${{ github.ref_name }}'

        prev_ver=$(git tag --sort v:refname | grep -v -F "${ver}" | \
                   grep 'v[0-9]\+\.[0-9]\+\.0' | tail -n1)

        echo -n "$GPG_KEY" | gpg --batch --pinentry-mode loopback --import
        ./makerelease.sh "${ver}" "${prev_ver}"
      env:
        GPG_KEY: ${{ secrets.GPG_KEY }}
        GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
    - name: Make release
      uses: actions/github-script@v7
      with:
        script: |
          const fs = require('fs')

          let ver = '${{ github.ref_name }}'

          let {data: release} = await github.rest.repos.createRelease({
            owner: context.repo.owner,
            repo: context.repo.repo,
            tag_name: ver,
            name: `nghttp2 ${ver}`,
            draft: true,
            generate_release_notes: true,
            discussion_category_name: 'Announcements',
          })

          let v = ver.substring(1)

          let files = [
            'checksums.txt',
            `nghttp2-${v}.tar.bz2`,
            `nghttp2-${v}.tar.bz2.asc`,
            `nghttp2-${v}.tar.gz`,
            `nghttp2-${v}.tar.gz.asc`,
            `nghttp2-${v}.tar.xz`,
            `nghttp2-${v}.tar.xz.asc`,
          ]

          await Promise.all(files.map(elem =>
            github.rest.repos.uploadReleaseAsset({
              owner: context.repo.owner,
              repo: context.repo.repo,
              release_id: release.id,
              name: elem,
              data: fs.readFileSync(elem),
            })
          ))
