name: CI

on:
  push:
    paths-ignore:
      - 'CHANGES*'
      - 'Doc/**'
      - 'appveyor.yml'
  pull_request:
    branches: master
    paths-ignore:
      - 'CHANGES*'
      - 'Doc/**'
      - 'appveyor.yml'

permissions:
  contents: read

jobs:
  build:

    # When continue-on-error is true for an individual build, that build can fail (it'll show red),
    # but it won't fail the overall build
    continue-on-error: ${{ matrix.continue-on-error || false }}

    runs-on: ${{ matrix.os || 'ubuntu-20.04' }}

    # By default, the name of the build is the language used and SWIG options, but matrix entries
    # can define the additional "desc" field with any additional information to include in the name.
    name: ${{ matrix.SWIGLANG || 'none' }}${{ matrix.PY2 }} ${{ matrix.ENGINE}} ${{ matrix.VER }} ${{ matrix.SWIG_FEATURES }} ${{ (matrix.compiler || 'gcc') }}${{ matrix.GCC }} ${{ matrix.CPPSTD }} ${{ matrix.CSTD }} ${{ matrix.desc }} ${{ matrix.continue-on-error && '(can fail)' }}

    strategy:
      matrix:
        include:
        - SWIGLANG: ""
          CPPFLAGS: "-DDOH_POISON"
        - SWIGLANG: ""
          GCC: 7
        - SWIGLANG: ""
          GCC: 8
        - SWIGLANG: ""
          GCC: 9
        - SWIGLANG: ""
          GCC: 10
        - SWIGLANG: ""
          GCC: 11
        - SWIGLANG: ""
          GCC: 12
          os: ubuntu-22.04
        - SWIGLANG: ""
          compiler: clang
        - SWIGLANG: csharp
        # D support can't be enabled because dmd 2.066 fails to build anything
        # under Ubuntu 18.04 due to its standard library (libphobos2.a) not
        # being compiled with -FPIC, but system gcc using -fpie by default,
        # resulting in linking errors for any output. And later versions, such
        # as 2.086.1, are not supported and result in errors in SWIG test suite.
        #
        # - SWIGLANG: d
        #   VER: '2.066.0'
        #   os: ubuntu-18.04 # This dlang version doesn't work under 20.04.
        - SWIGLANG: go
          VER: '1.6'
          CSTD: gnu11
        - SWIGLANG: go
          VER: '1.8'
        - SWIGLANG: go
          VER: '1.12'
          CSTD: gnu11
        - SWIGLANG: go
          VER: '1.17'
        - SWIGLANG: guile
        - SWIGLANG: guile
          VER: '2.2'
        - SWIGLANG: guile
          VER: '3.0'
        - SWIGLANG: java
        - SWIGLANG: javascript
          ENGINE: node
          VER: '6'
          CPPSTD: c++11
          os: ubuntu-18.04
        - SWIGLANG: javascript
          ENGINE: node
          VER: '8'
          CPPSTD: c++11
          os: ubuntu-18.04
        - SWIGLANG: javascript
          ENGINE: node
          VER: '10'
          CPPSTD: c++11
          os: ubuntu-18.04
        - SWIGLANG: javascript
          ENGINE: node
          VER: '12'
          CPPSTD: c++11
        - SWIGLANG: javascript
          ENGINE: node
          VER: '18'
          CPPSTD: c++14
        - SWIGLANG: javascript
          ENGINE: jsc
          VER: '4.0'
        - SWIGLANG: lua
        - SWIGLANG: lua
          VER: '5.3'
        - SWIGLANG: octave
          CPPSTD: c++11
        - SWIGLANG: perl5
        - SWIGLANG: php
          VER: '7.0'
        - SWIGLANG: php
          VER: '7.1'
        - SWIGLANG: php
          VER: '7.2'
        - SWIGLANG: php
          VER: '7.3'
        - SWIGLANG: php
          VER: '7.4'
        - SWIGLANG: php
          VER: '8.0'
        - SWIGLANG: php
          VER: '8.1'
        - SWIGLANG: php
          VER: '8.2'
        - SWIGLANG: python
          PY2: 2
        - SWIGLANG: python
          VER: '3.3'
          os: ubuntu-18.04 # Python < 3.5 not available for 20.04.
        - SWIGLANG: python
          VER: '3.4'
          os: ubuntu-18.04 # Python < 3.5 not available for 20.04.
        - SWIGLANG: python
          VER: '3.5'
        - SWIGLANG: python
          VER: '3.6'
        - SWIGLANG: python
          VER: '3.7'
        - SWIGLANG: python
          VER: '3.8'
        - SWIGLANG: python
          VER: '3.9'
        - SWIGLANG: python
          VER: '3.10'
        - SWIGLANG: python
          VER: '3.11'
        - SWIGLANG: python
          PY2: 2
          SWIG_FEATURES: -builtin
        - SWIGLANG: python
          PY2: 2
          SWIG_FEATURES: -builtin -O
        - SWIGLANG: python
          SWIG_FEATURES: -builtin
        - SWIGLANG: python
          SWIG_FEATURES: -builtin -O
        - SWIGLANG: r
        - SWIGLANG: ruby
          VER: '1.9'
          os: ubuntu-18.04
        - SWIGLANG: ruby
          VER: '2.0'
          os: ubuntu-18.04
        - SWIGLANG: ruby
          VER: '2.1'
          os: ubuntu-18.04
        - SWIGLANG: ruby
          VER: '2.2'
          os: ubuntu-18.04
        - SWIGLANG: ruby
          VER: '2.3'
          os: ubuntu-18.04
        - SWIGLANG: ruby
          VER: '2.4'
        - SWIGLANG: ruby
          VER: '2.5'
        - SWIGLANG: ruby
          VER: '2.6'
        - SWIGLANG: ruby
          VER: '2.7'
        - SWIGLANG: ruby
          VER: '3.0'
          CPPSTD: c++11
        - SWIGLANG: ruby
          VER: '3.1'
          CPPSTD: c++11
        - SWIGLANG: scilab
          VER: '5.5.2'
        - SWIGLANG: scilab
          os: ubuntu-18.04 # scilab 6.0
        - SWIGLANG: scilab
        - SWIGLANG: tcl
        # c++11 testing
        - SWIGLANG: csharp
          CPPSTD: c++11
        - SWIGLANG: go
          VER: '1.17'
          CPPSTD: c++11
          CSTD: gnu11
        - SWIGLANG: guile
          CPPSTD: c++11
        - SWIGLANG: java
          CPPSTD: c++11
        - SWIGLANG: javascript
          ENGINE: jsc
          VER: '4.1'
          os: ubuntu-22.04
          CPPSTD: c++11
        - SWIGLANG: javascript
          ENGINE: node
          VER: '14'
          CPPSTD: c++11
        - SWIGLANG: lua
          CPPSTD: c++11
        - SWIGLANG: perl5
          CPPSTD: c++11
        - SWIGLANG: php
          CPPSTD: c++11
          CSTD: gnu11
        - SWIGLANG: python
          CPPSTD: c++11
        - SWIGLANG: r
          CPPSTD: c++11
        - SWIGLANG: ruby
          CPPSTD: c++11
        - SWIGLANG: scilab
          CPPSTD: c++11
        - SWIGLANG: tcl
          CPPSTD: c++11
        # c++14 testing
        - SWIGLANG: csharp
          CPPSTD: c++14
        - SWIGLANG: go
          VER: '1.17'
          CPPSTD: c++14
          CSTD: gnu11
        - SWIGLANG: guile
          CPPSTD: c++14
        - SWIGLANG: java
          CPPSTD: c++14
        - SWIGLANG: javascript
          ENGINE: node
          VER: '16'
          CPPSTD: c++14
        - SWIGLANG: lua
          CPPSTD: c++14
        - SWIGLANG: octave
          CPPSTD: c++14
        - SWIGLANG: perl5
          CPPSTD: c++14
        - SWIGLANG: php
          CPPSTD: c++14
          CSTD: gnu11
        - SWIGLANG: python
          CPPSTD: c++14
        - SWIGLANG: r
          CPPSTD: c++14
        - SWIGLANG: ruby
          CPPSTD: c++14
        - SWIGLANG: scilab
          CPPSTD: c++14
        - SWIGLANG: tcl
          CPPSTD: c++14
        # c++17 testing (using gcc11)
        - SWIGLANG: csharp
          CPPSTD: c++17
          GCC: 11
        - SWIGLANG: go
          VER: '1.17'
          CPPSTD: c++17
          GCC: 11
          CSTD: gnu17
        - SWIGLANG: guile
          CPPSTD: c++17
          GCC: 11
        - SWIGLANG: java
          CPPSTD: c++17
          GCC: 11
        - SWIGLANG: javascript
          ENGINE: node
          VER: '18'
          CPPSTD: c++17
          GCC: 11
        - SWIGLANG: lua
          CPPSTD: c++17
          GCC: 11
        - SWIGLANG: octave
          CPPSTD: c++17
          GCC: 11
        - SWIGLANG: perl5
          CPPSTD: c++17
          GCC: 11
        - SWIGLANG: php
          CPPSTD: c++17
          CSTD: gnu17
          GCC: 11
        - SWIGLANG: python
          CPPSTD: c++17
          GCC: 11
        - SWIGLANG: r
          CPPSTD: c++17
          GCC: 11
        - SWIGLANG: ruby
          CPPSTD: c++17
          GCC: 11
        - SWIGLANG: scilab
          CPPSTD: c++17
          GCC: 11
        - SWIGLANG: tcl
          CPPSTD: c++17
          GCC: 11
        # c++20 testing (using gcc12)
        # ubuntu-22.04 is currently experimental on Github Actions, so limit to just one language for now
        - SWIGLANG: python
          CPPSTD: c++20
          GCC: 12
          os: ubuntu-22.04
        # Experimental languages (these are allowed to fail)
        - SWIGLANG: mzscheme
          continue-on-error: true
        - SWIGLANG: ocaml
          CPPSTD: c++17
          GCC: 11
          continue-on-error: true
          os: ubuntu-18.04 # ocaml-4.08 in ubuntu-20.04 not yet working
      # Run all of them, as opposed to aborting when one fails
      fail-fast: false

    env:
      SWIGLANG: ${{ matrix.SWIGLANG }}
      PY2: ${{ matrix.PY2 }}
      VER: ${{ matrix.VER }}
      ENGINE: ${{ matrix.ENGINE }}
      SWIG_FEATURES: ${{ matrix.SWIG_FEATURES }}
      GCC: ${{ matrix.GCC }}
      CSTD: ${{ matrix.CSTD }}
      CPPSTD: ${{ matrix.CPPSTD }}
      CPPFLAGS: ${{ matrix.CPPFLAGS }}

    steps:
    - name: Checkout
      uses: actions/checkout@v2
      with:
        submodules: recursive

    - name: Install CCache
      uses: hendrikmuhs/ccache-action@v1
      with:
        key: ${{ matrix.os || 'ubuntu-20.04' }}-${{ matrix.compiler || 'gcc' }}${{ matrix.GCC }}

# Uncomment to debug via ssh, see https://github.com/mxschmitt/action-tmate
#    - name: Setup tmate session
#      uses: mxschmitt/action-tmate@v3

    - name: Install Dependencies
      run: |
          set -x
          export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
          echo PATH="$PATH" >> $GITHUB_ENV

          source $GITHUB_WORKSPACE/Tools/GHA-linux-install.sh
          echo WITHLANG="$WITHLANG" >> $GITHUB_ENV

          case $(uname) in
              Linux)
                  cpu_count=$(nproc)
                  ;;

              Darwin)
                  cpu_count=$(sysctl -n hw.ncpu)
                  ;;

              *)
                  cpu_count=1
                  ;;
          esac

          if [[ $cpu_count != 1 ]]; then
            echo SWIGJOBS=-j$cpu_count >> $GITHUB_ENV
          fi

          if test '${{ matrix.compiler }}' = 'clang'; then
            CC="clang"
            CXX="clang++"

            CFLAGS="$CFLAGS -fPIE"
            CXXFLAGS="$CXXFLAGS -fPIE"
          elif test -n "$GCC"; then
            CC="gcc-$GCC"
            CXX="g++-$GCC"
          else
            CC="gcc"
            CXX="g++"
          fi

          export CC CXX

          echo CC="$CC" >> $GITHUB_ENV
          echo CXX="$CXX" >> $GITHUB_ENV

          ls -la $(which $CC) $(which $CXX)
          $CC --version
          $CXX --version

    - name: Configure
      run: |
          source $GITHUB_WORKSPACE/Tools/CI-linux-environment.sh
          set -x

          if [[ -z "$CSTD" ]]; then
            case "$CPPSTD" in
              c++11) export CSTD=c11 ;;
              c++14) export CSTD=c11 ;;
              c++17) export CSTD=c17 ;;
              c++20) export CSTD=c17 ;;
            esac
            echo CSTD="$CSTD" >> $GITHUB_ENV
          fi
          if test -z "$CPPSTD"; then CONFIGOPTS+=("--disable-cpp11-testing"); fi
          if test -n "$CPPSTD"; then CONFIGOPTS+=("CXXFLAGS=-std=$CPPSTD $CXXFLAGS"); fi
          if test -n "$CSTD"; then CONFIGOPTS+=("CFLAGS=-std=$CSTD $CFLAGS"); fi
          if test -n "$SWIGLANG"; then CONFIGOPTS+=(--without-alllang --with-$WITHLANG); fi
          echo "${CONFIGOPTS[@]}"
          ./autogen.sh && mkdir -p build/build && cd build/build && ../../configure "${CONFIGOPTS[@]}"

    - name: Build
      working-directory: build/build
      run: |
          set -x
          make -s $SWIGJOBS
          ./swig -version && ./swig -pcreversion

    - name: Test
      working-directory: build/build
      run: |
          source $GITHUB_WORKSPACE/Tools/CI-linux-environment.sh
          set -x

          if test -z "$SWIGLANG"; then
            make $SWIGJOBS check-ccache
            make $SWIGJOBS check-errors-test-suite
          else
            case "$SWIGLANG" in
              javascript)
                case "$ENGINE" in
                  v8 | jsc)
                    # Running tests using v8 or jsc involves creating a custom
                    # interpreter in Tools/javascript, which is currently broken
                    # for parallel builds (we attempt to update this interpreter
                    # while running, resulting in "Text file busy" error).
                    unset SWIGJOBS
                esac
                ;;
            esac

            # Stricter compile flags for examples. Various headers and SWIG generated code prevents full use of -pedantic.
            cflags=$($GITHUB_WORKSPACE/Tools/testflags.py --language $SWIGLANG --cflags --std=$CSTD --compiler=$CC)
            cxxflags=$($GITHUB_WORKSPACE/Tools/testflags.py --language $SWIGLANG --cxxflags --std=$CPPSTD --compiler=$CC)
            make check-$SWIGLANG-version
            make check-$SWIGLANG-enabled
            make $SWIGJOBS check-$SWIGLANG-examples CFLAGS="$cflags" CXXFLAGS="$cxxflags"
            make $SWIGJOBS check-$SWIGLANG-test-suite CFLAGS="$cflags" CXXFLAGS="$cxxflags"
          fi

    - name: Install
      working-directory: build/build
      run: |
          set -x
          if test -z "$SWIGLANG"; then sudo make install && swig -version && ccache-swig -V; fi

    - name: Clean
      working-directory: build/build
      run: |
          set -x
          make check-maintainer-clean && ../../configure
