# Known critical issues:
# - AVX512 related tests are incomplete.  Because default environment of
#   GitHub Actions doesn't guarantee to support AVX512.
#   As of May 2021, they're using Xeon E5-2673 (which doesn't support
#   AVX512) and Xeon Platinum 8171M (which supports AVX512).
#   See also https://github.com/actions/runner/issues/1069
#
#   In this CI script, it always run `make default` which compiles xxHash
#   with AVX512 intrinsics.  But if test runner doesn't support AVX512,
#   it doesn't run `make check` which tests runtime error/consistency.
#   It means that this test stochastically detects a failure in AVX512
#   code path.
#
# Known issues:
# - This test script ignores exit code of cppcheck which can see under
#   Job:Linux x64 misc tests > cppcheck in the GitHub Actions report.
#   Because xxHash project doesn't 100% follow their recommendation.
#   Also sometimes it reports false positives.
#
# - GitHub Actions doesn't support Visual Studio 2015 and 2013.
#   https://github.com/actions/virtual-environments/issues/387
#
# - Setup procedure for msys2 environment is painfully slow.  It takes
#   3..5 minutes.
#
# Notes:
# - You can investigate various information at the right pane of GitHub
#   Actions report page.
#
#   | Item                      | Section in the right pane             |
#   | ------------------------- | ------------------------------------- |
#   | OS, VM                    | Set up job                            |
#   | git repo, commit hash     | Run actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683               |
#   | gcc, tools                | Environment info                      |
#
# - To fail earlier, order of tests in the same job are roughly sorted by
#   elapsed time.
#
# Todos:
# - [ ] Linux: Add native ARM runner.
# - [ ] Linux: Add native ARM64 runner.
# - [ ] Linux: Add native PPC64LE runner.
# - [ ] Linux: Add native S390X runner.
# - [ ] Windows: Add VS2013.
# - [ ] Windows: Add VS2015.
# - [ ] Windows: Add clang for msys2.
# - [ ] Windows: Add native or emulated ARM runner.
# - [ ] Windows: Add native or emulated ARM64 runner.


# Name of the workflow is also displayed as a SVG badge
name: xxHash CI tests

on: [push, pull_request]

concurrency:
  group: fast-${{ github.ref }}
  cancel-in-progress: true

permissions:
  contents: read

jobs:
  xxhash-c-compilers:
    name: CC=${{ matrix.cc }}, ${{ matrix.os }}
    strategy:
      fail-fast: false  # 'false' means Don't stop matrix workflows even if some matrix entry fails.
      matrix:
        include: [
          # You can access the following values via ${{ matrix.??? }}
          #
          #   pkgs    : apt-get package names.  It can include multiple package names which are delimited by space.
          #   cc      : C compiler executable.
          #   cxx     : C++ compiler executable for `make ctocpptest`.
          #   os      : GitHub Actions YAML workflow label.  See https://github.com/actions/virtual-environments#available-environments

          # cc
          { pkgs: '',                                  cc: cc,        cxx: c++,         os: ubuntu-latest, },

          # gcc
          { pkgs: '',                                  cc: gcc,       cxx: g++,         os: ubuntu-latest, },
          # { pkgs: 'gcc-13  g++-13  lib32gcc-13-dev',   cc: gcc-13,    cxx: g++-13,      os: ubuntu-22.04,  }, # currently failing
          { pkgs: 'gcc-12  g++-12  lib32gcc-12-dev',   cc: gcc-12,    cxx: g++-12,      os: ubuntu-22.04,  },
          { pkgs: 'gcc-11  g++-11  lib32gcc-11-dev',   cc: gcc-11,    cxx: g++-11,      os: ubuntu-22.04,  },
          { pkgs: 'gcc-10  g++-10  lib32gcc-10-dev',   cc: gcc-10,    cxx: g++-10,      os: ubuntu-22.04,  },
          { pkgs: 'gcc-9   g++-9   lib32gcc-9-dev',    cc: gcc-9,     cxx: g++-9,       os: ubuntu-22.04,  },
          { pkgs: 'gcc-8   g++-8   lib32gcc-8-dev',    cc: gcc-8,     cxx: g++-8,       os: ubuntu-20.04,  },
          { pkgs: 'gcc-7   g++-7   lib32gcc-7-dev',    cc: gcc-7,     cxx: g++-7,       os: ubuntu-20.04,  },

          # clang
          { pkgs: '',                                  cc: clang,     cxx: clang++,     os: ubuntu-latest, },
          { pkgs: 'clang-15',                          cc: clang-15,  cxx: clang++-15,  os: ubuntu-22.04,  },
          { pkgs: 'clang-14',                          cc: clang-14,  cxx: clang++-14,  os: ubuntu-22.04,  },
          { pkgs: 'clang-13',                          cc: clang-13,  cxx: clang++-13,  os: ubuntu-22.04,  },
          { pkgs: 'clang-12',                          cc: clang-12,  cxx: clang++-12,  os: ubuntu-22.04,  },
          { pkgs: 'clang-11',                          cc: clang-11,  cxx: clang++-11,  os: ubuntu-22.04,  },
          { pkgs: 'clang-10',                          cc: clang-10,  cxx: clang++-10,  os: ubuntu-20.04,  },
          { pkgs: 'clang-9',                           cc: clang-9,   cxx: clang++-9,   os: ubuntu-20.04,  },
          { pkgs: 'clang-8',                           cc: clang-8,   cxx: clang++-8,   os: ubuntu-20.04,  },
          { pkgs: 'clang-7',                           cc: clang-7,   cxx: clang++-7,   os: ubuntu-20.04,  },
          { pkgs: 'clang-6.0',                         cc: clang-6.0, cxx: clang++-6.0, os: ubuntu-20.04,  },
        ]

    runs-on: ${{ matrix.os }}
    env:                        # Set environment variables
      # We globally set CC and CXX to improve compatibility with .travis.yml
      CC: ${{ matrix.cc }}
      CXX: ${{ matrix.cxx }}
    steps:
    - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

    - name: apt-get install
      run: |
        sudo apt-get update
        sudo apt-get install gcc-multilib
        sudo apt-get install ${{ matrix.pkgs }}

    - name: Environment info
      run: |
        echo && type $CC && which $CC && $CC --version
        echo && type $CXX && which $CXX && $CXX --version
        echo && type make && make -v
        echo && cat /proc/cpuinfo || echo /proc/cpuinfo is not present

    - name: C90 + no-long-long compliance
      if: always()
      run: |
        CFLAGS="-std=c90 -pedantic -Wno-long-long -Werror" make clean xxhsum

    - name: C90 + XXH_NO_LONG_LONG
      if: always()
      run: |
        # strict c90, with no long long support; resulting in no XXH64_* symbol
        make clean c90test

    - name: dispatch
      if: always()
      run: |
        # removing sign conversion warnings due to a bug in gcc-5's definition of some AVX512 intrinsics
        CFLAGS="-Werror" MOREFLAGS="-Wno-sign-conversion" make clean dispatch

    - name: DISPATCH=1
      if: always()
      run: |
        CFLAGS="-Wall -Wextra -Werror" make DISPATCH=1 clean default

    - name: XXH_SIZE_OPT == 2
      if: always()
      run: |
        CFLAGS="-Os -DXXH_SIZE_OPT=2 -Wall -Wextra -Werror" make clean xxhsum

    - name: noxxh3test
      if: always()
      run: |
        # check library can be compiled with XXH_NO_XXH3, resulting in no XXH3_* symbol
        make clean noxxh3test

    - name: nostreamtest
      if: always()
      run: |
        # check library can be compiled with XXH_NO_STREAM, resulting in no streaming symbols
        make clean noxxh3test

    - name: make avx512f
      run: |
        CFLAGS="-O1 -mavx512f -Werror" make clean default

    - name: test-all
      if: always()
      run: |
        make clean test-all


  ubuntu-consistency:
    name: Linux x64 check results consistency
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

    - name: Environment info
      run: |
        echo && gcc --version
        echo && make -v
        echo && cat /proc/cpuinfo || echo /proc/cpuinfo is not present

    - name: Scalar code path
      run: |
        CPPFLAGS=-DXXH_VECTOR=XXH_SCALAR make clean check

    - name: SSE2 code path
      run: |
        CPPFLAGS=-DXXH_VECTOR=XXH_SSE2 make clean check

    - name: AVX2 code path
      run: |
        CPPFLAGS="-mavx2 -DXXH_VECTOR=XXH_AVX2" make clean check

    # As for AVX512, see "Known critical issues" at the top of this file
    - name: AVX512 code path
      run: |
        # Run "make check" if /proc/cpuinfo has flags for avx512.
        grep -q "^flags.*\bavx512\b" /proc/cpuinfo && CPPFLAGS="-mavx512f -DXXH_VECTOR=XXH_AVX512" make clean check || (echo This test runner does not support AVX512. && $(exit 0))

    - name: reroll code path (#240)
      run: |
        CPPFLAGS=-DXXH_REROLL=1 make clean check

    - name: tests/bench
      run: |
        make -C tests/bench


  ubuntu-wasm:
    name: Ubuntu Node ${{ matrix.node-version }} WebAssembly/asm.js tests
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [16.x, 17.x, 18.x]

    env:
      EM_VERSION: 3.1.33 # TODO: more emsdk versions
      EM_CACHE_FOLDER: emsdk-cache-${{ matrix.node-version }}
      CC: emcc

    steps:
    - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

    - name: Setup cache
      id: cache-system-libraries
      uses: actions/cache@v4
      with:
        path: ${{env.EM_CACHE_FOLDER}}
        key: em${{env.EM_VERSION}}-node${{ matrix.node-version }}-${{ runner.os }}

    - name: Setup emsdk
      uses: mymindstorm/setup-emsdk@v14
      with:
        version: ${{env.EM_VERSION}}
        actions-cache-folder: ${{env.EM_CACHE_FOLDER}}

    - name: Use Node.js ${{ matrix.node-version }}
      uses: actions/setup-node@v4
      with:
        node-version: ${{ matrix.node-version }}

    - name: Environment info
      run: |
        echo && node -p '`node version: ${process.versions.node}, v8 version: ${process.versions.v8}`'
        echo && emcc --version
        echo && make -v
        echo && cat /proc/cpuinfo || echo /proc/cpuinfo is not present

    - name: Scalar code path
      run: |
        CPPFLAGS="-DXXH_VECTOR=XXH_SCALAR" RUN_ENV="node" NODE_JS=1 make clean check

    - name: SIMD128 (via NEON SIMDe) code path (XXH_VECTOR=XXH_NEON)
      run: |
        CPPFLAGS="-DXXH_VECTOR=XXH_NEON -msimd128" RUN_ENV="node" NODE_JS=1 make clean check

    - name: Scalar asm.js (-sWASM=0)
      run: |
        CPPFLAGS="-DXXH_VECTOR=XXH_SCALAR" RUN_ENV="node" NODE_JS=1 LDFLAGS="-sWASM=0" make clean check


  ubuntu-misc:
    name: Linux x64 misc tests
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

    - name: apt-get install
      run: |
        sudo apt-get update
        sudo apt-get install valgrind cppcheck

    - name: Environment info
      run: |
        echo && gcc --version
        echo && clang --version
        echo && valgrind --version
        echo && cppcheck --version
        echo && make -v
        echo && cat /proc/cpuinfo || echo /proc/cpuinfo is not present

    - name: cppcheck
      run: |
        # This test script ignores exit code of cppcheck.  See knowin issues
        # at the top of this file.
        make clean cppcheck || echo There are some cppcheck reports

    - name: test-mem (valgrind)
      run: |
        make clean test-mem

    - name: usan
      run: |
        make clean usan

    - name: Lint Unicode in root-dir, cli/, tests/, tests/bench/, tests/collisions/.
      run: |
        make lint-unicode

    - name: test-filename-escape
      # See also issue #695 - https://github.com/Cyan4973/xxHash/issues/695
      run: |
        make clean test-filename-escape

    - name: test-cli-comment-line
      run: |
        make clean test-cli-comment-line

  ubuntu-cmake-unofficial:
    name: Linux x64 cmake unofficial build test
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

    - name: Environment info
      run: |
        echo && gcc --version
        echo && cmake --version
        echo && make -v
        echo && cat /proc/cpuinfo || echo /proc/cpuinfo is not present

    - name: cmake
      run: |
        cd cmake_unofficial
        cmake -Bbuild
        cd build
        CFLAGS=-Werror make
        mkdir -p test_install_dir
        DESTDIR=test_install_dir cmake --install .

    - name: cmake pkgconfig generation
      run: |
        cd cmake_unofficial
        pwd
        ls
        rm -rf build
        cmake -Bbuild -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_INSTALL_INCLUDEDIR=/usr/include -DCMAKE_INSTALL_LIBDIR=/usr/lib
        echo "checking content of libxxhash.pc"
        cat build/libxxhash.pc | grep "libdir=/usr/lib"
        cat build/libxxhash.pc | grep "includedir=/usr/include"

    - name: cmake minimum version v3.10 test
      run: |
        mkdir -p cmake_bins
        cd cmake_bins
        wget https://cmake.org/files/v3.10/cmake-3.10.0-Linux-x86_64.tar.gz
        tar xzf cmake-3.10.0-Linux-x86_64.tar.gz
        cd ../cmake_unofficial
        rm -rf build
        pwd
        ls
        mkdir -p build
        cd build
        ../../cmake_bins/cmake-3.10.0-Linux-x86_64/bin/cmake --version
        ../../cmake_bins/cmake-3.10.0-Linux-x86_64/bin/cmake ..
        ../../cmake_bins/cmake-3.10.0-Linux-x86_64/bin/cmake --build .
        mkdir -p test_install_dir
        DESTDIR=test_install_dir ../../cmake_bins/cmake-3.10.0-Linux-x86_64/bin/cmake --install .
        rm -rf *
        ../../cmake_bins/cmake-3.10.0-Linux-x86_64/bin/cmake -DCMAKE_BUILD_TYPE=Debug ..
        ../../cmake_bins/cmake-3.10.0-Linux-x86_64/bin/cmake --build .



  # Linux, { ARM, ARM64, PPC64LE, PPC64, S390X }
  # All tests are using QEMU and gcc cross compiler.

  qemu-consistency:
    name: QEMU ${{ matrix.name }}
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false  # 'false' means Don't stop matrix workflows even if some matrix failed.
      matrix:
        include: [
          { name: 'ARM',             xcc_pkg: gcc-arm-linux-gnueabi,        xcc: arm-linux-gnueabi-gcc,        xemu_pkg: qemu-system-arm,    xemu: qemu-arm-static,     os: ubuntu-latest, },
          { name: 'AARCH64',         xcc_pkg: gcc-aarch64-linux-gnu,        xcc: aarch64-linux-gnu-gcc,        xemu_pkg: qemu-system-arm,    xemu: qemu-aarch64-static, os: ubuntu-latest, },
          { name: 'PPC64LE',         xcc_pkg: gcc-powerpc64le-linux-gnu,    xcc: powerpc64le-linux-gnu-gcc,    xemu_pkg: qemu-system-ppc,    xemu: qemu-ppc64le-static, os: ubuntu-latest, },
          { name: 'PPC64',           xcc_pkg: gcc-powerpc64-linux-gnu,      xcc: powerpc64-linux-gnu-gcc,      xemu_pkg: qemu-system-ppc,    xemu: qemu-ppc64-static,   os: ubuntu-latest, },
          { name: 'S390X',           xcc_pkg: gcc-s390x-linux-gnu,          xcc: s390x-linux-gnu-gcc,          xemu_pkg: qemu-system-s390x,  xemu: qemu-s390x-static,   os: ubuntu-latest, },
          { name: 'MIPS',            xcc_pkg: gcc-mips-linux-gnu,           xcc: mips-linux-gnu-gcc,           xemu_pkg: qemu-system-mips,   xemu: qemu-mips-static,    os: ubuntu-latest, },
          { name: 'M68K',            xcc_pkg: gcc-m68k-linux-gnu,           xcc: m68k-linux-gnu-gcc,           xemu_pkg: qemu-system-m68k,   xemu: qemu-m68k-static,    os: ubuntu-latest, },
          { name: 'RISC-V',          xcc_pkg: gcc-riscv64-linux-gnu,        xcc: riscv64-linux-gnu-gcc,        xemu_pkg: qemu-system-riscv64,xemu: qemu-riscv64-static, os: ubuntu-latest, },
          # SPARC64 qemu emulation seems broken on Ubuntu-22
          { name: 'SPARC',           xcc_pkg: gcc-sparc64-linux-gnu,        xcc: sparc64-linux-gnu-gcc,        xemu_pkg: qemu-system-sparc,  xemu: qemu-sparc64-static, os: ubuntu-20.04, },
          { name: 'LoongArch',       xcc_pkg: gcc-14-loongarch64-linux-gnu,    xcc: loongarch64-linux-gnu-gcc-14, xemu_pkg: qemu-system-loongarch64, xemu: qemu-loongarch64-static, os: ubuntu-24.04, },

          { name: 'ARM, gcc-10',     xcc_pkg: gcc-10-arm-linux-gnueabi,     xcc: arm-linux-gnueabi-gcc-10,     xemu_pkg: qemu-system-arm,   xemu: qemu-arm-static,     os: ubuntu-20.04, },
          { name: 'AARCH64, gcc-10', xcc_pkg: gcc-10-aarch64-linux-gnu,     xcc: aarch64-linux-gnu-gcc-10,     xemu_pkg: qemu-system-arm,   xemu: qemu-aarch64-static, os: ubuntu-20.04, },
          { name: 'PPC64LE, gcc-10', xcc_pkg: gcc-10-powerpc64le-linux-gnu, xcc: powerpc64le-linux-gnu-gcc-10, xemu_pkg: qemu-system-ppc,   xemu: qemu-ppc64le-static, os: ubuntu-20.04, },
          { name: 'PPC64, gcc-10',   xcc_pkg: gcc-10-powerpc64-linux-gnu,   xcc: powerpc64-linux-gnu-gcc-10,   xemu_pkg: qemu-system-ppc,   xemu: qemu-ppc64-static,   os: ubuntu-20.04, },
          { name: 'S390X, gcc-10',   xcc_pkg: gcc-10-s390x-linux-gnu,       xcc: s390x-linux-gnu-gcc-10,       xemu_pkg: qemu-system-s390x, xemu: qemu-s390x-static,   os: ubuntu-20.04, },
          { name: 'MIPS, gcc-10',    xcc_pkg: gcc-10-mips-linux-gnu,        xcc: mips-linux-gnu-gcc-10,        xemu_pkg: qemu-system-mips,  xemu: qemu-mips-static,    os: ubuntu-20.04, },

          { name: 'ARM, gcc-9',      xcc_pkg: gcc-9-arm-linux-gnueabi,      xcc: arm-linux-gnueabi-gcc-9,      xemu_pkg: qemu-system-arm,   xemu: qemu-arm-static,     os: ubuntu-20.04, },
          # SVE tests require at least gcc-10.1
          # { name: 'AARCH64, gcc-9',  xcc_pkg: gcc-9-aarch64-linux-gnu,      xcc: aarch64-linux-gnu-gcc-9,      xemu_pkg: qemu-system-arm,   xemu: qemu-aarch64-static, os: ubuntu-20.04, },
          { name: 'PPC64LE, gcc-9',  xcc_pkg: gcc-9-powerpc64le-linux-gnu,  xcc: powerpc64le-linux-gnu-gcc-9,  xemu_pkg: qemu-system-ppc,   xemu: qemu-ppc64le-static, os: ubuntu-20.04, },
          { name: 'PPC64, gcc-9',    xcc_pkg: gcc-9-powerpc64-linux-gnu,    xcc: powerpc64-linux-gnu-gcc-9,    xemu_pkg: qemu-system-ppc,   xemu: qemu-ppc64-static,   os: ubuntu-20.04, },
          { name: 'S390X, gcc-9',    xcc_pkg: gcc-9-s390x-linux-gnu,        xcc: s390x-linux-gnu-gcc-9,        xemu_pkg: qemu-system-s390x, xemu: qemu-s390x-static,   os: ubuntu-20.04, },
          { name: 'MIPS, gcc-9',     xcc_pkg: gcc-9-mips-linux-gnu,         xcc: mips-linux-gnu-gcc-9,         xemu_pkg: qemu-system-mips,  xemu: qemu-mips-static,    os: ubuntu-20.04, },

          { name: 'ARM, gcc-8',      xcc_pkg: gcc-8-arm-linux-gnueabi,      xcc: arm-linux-gnueabi-gcc-8,      xemu_pkg: qemu-system-arm,   xemu: qemu-arm-static,     os: ubuntu-20.04, },
          # aarch64-linux-gnu-gcc-8 linker has an issue for LDFLAGS="-static"
          # { name: 'AARCH64, gcc-8',  xcc_pkg: gcc-8-aarch64-linux-gnu,      xcc: aarch64-linux-gnu-gcc-8,      xemu_pkg: qemu-system-arm,   xemu: qemu-aarch64-static, os: ubuntu-20.04, },
          { name: 'PPC64LE, gcc-8',  xcc_pkg: gcc-8-powerpc64le-linux-gnu,  xcc: powerpc64le-linux-gnu-gcc-8,  xemu_pkg: qemu-system-ppc,   xemu: qemu-ppc64le-static, os: ubuntu-20.04, },
          { name: 'PPC64, gcc-8',    xcc_pkg: gcc-8-powerpc64-linux-gnu,    xcc: powerpc64-linux-gnu-gcc-8,    xemu_pkg: qemu-system-ppc,   xemu: qemu-ppc64-static,   os: ubuntu-20.04, },
          { name: 'S390X, gcc-8',    xcc_pkg: gcc-8-s390x-linux-gnu,        xcc: s390x-linux-gnu-gcc-8,        xemu_pkg: qemu-system-s390x, xemu: qemu-s390x-static,   os: ubuntu-20.04, },
          # ubuntu-20.04 fails to retrieve gcc-8-mips-linux-gnu for some reason.
          # { name: 'MIPS, gcc-8',   xcc_pkg: gcc-8-mips-linux-gnu,         xcc: mips-linux-gnu-gcc-8,         xemu_pkg: qemu-system-mips,  xemu: qemu-mips-static,    os: ubuntu-20.04, },
        ]
    env:                        # Set environment variables
      XCC: ${{ matrix.xcc }}
      XEMU: ${{ matrix.xemu }}
      MOREFLAGS: -Werror
    steps:
    - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
    - name: apt update & install (1)
      run: |
        sudo apt-get update
        sudo apt-get install gcc-multilib g++-multilib qemu-utils qemu-user-static

    - name: Environment info (1)
      run: |
        echo && apt-cache search "^gcc-" | grep "linux" | sort

    - name: apt update & install (2)
      run: |
        sudo apt-get install ${{ matrix.xcc_pkg }} ${{ matrix.xemu_pkg }}

    - name: Environment info (2)
      run: |
        echo && which $XCC
        echo && $XCC --version
        echo && $XCC -v  # Show built-in specs
        echo && which $XEMU
        echo && $XEMU --version

    - name: ARM (XXH_VECTOR=[ scalar, NEON ])
      if: ${{ startsWith(matrix.name, 'ARM') }}
      run: |
        CPPFLAGS="-DXXH_VECTOR=XXH_SCALAR" LDFLAGS="-static" CC=$XCC RUN_ENV=$XEMU make clean check
        CPPFLAGS="-DXXH_VECTOR=XXH_NEON" CFLAGS="-O3 -march=armv7-a -fPIC -mfloat-abi=softfp -mfpu=neon-vfpv4" LDFLAGS="-static" CC=$XCC RUN_ENV=$XEMU make clean check
        make -C tests clean
        CPPFLAGS="-DXXH_VECTOR=XXH_SCALAR" LDFLAGS="-static" CC=$XCC RUN_ENV=$XEMU make -C tests sanity_test_vectors.h test_sanity

    - name: AARCH64 (XXH_VECTOR=[ scalar, NEON, SVE ])
      if: ${{ startsWith(matrix.name, 'AARCH64') }}
      run: |
        CPPFLAGS="-DXXH_VECTOR=XXH_SCALAR" LDFLAGS="-static" CC=$XCC RUN_ENV=$XEMU make clean check
        CPPFLAGS="-DXXH_VECTOR=XXH_NEON" LDFLAGS="-static" CC=$XCC RUN_ENV=$XEMU make clean check
        CPPFLAGS="-DXXH_VECTOR=XXH_SVE" LDFLAGS="-static" CC="$XCC -march=armv8.2-a+sve" RUN_ENV="$XEMU -cpu max,sve128=on,sve256=off,sve512=off,sve1024=off,sve2048=off" make clean check
        CPPFLAGS="-DXXH_VECTOR=XXH_SVE" LDFLAGS="-static" CC="$XCC -march=armv8.2-a+sve" RUN_ENV="$XEMU -cpu max,sve128=on,sve256=on,sve512=off,sve1024=off,sve2048=off" make clean check
        CPPFLAGS="-DXXH_VECTOR=XXH_SVE" LDFLAGS="-static" CC="$XCC -march=armv8.2-a+sve" RUN_ENV="$XEMU -cpu max,sve128=on,sve256=on,sve512=on,sve1024=off,sve2048=off" make clean check
        CPPFLAGS="-DXXH_VECTOR=XXH_SVE" LDFLAGS="-static" CC="$XCC -march=armv8.2-a+sve" RUN_ENV="$XEMU -cpu max,sve128=on,sve256=on,sve512=on,sve1024=on,sve2048=off" make clean check
        CPPFLAGS="-DXXH_VECTOR=XXH_SVE" LDFLAGS="-static" CC="$XCC -march=armv8.2-a+sve" RUN_ENV="$XEMU -cpu max,sve128=on,sve256=on,sve512=on,sve1024=on,sve2048=on" make clean check

    - name: PPC64(LE) (XXH_VECTOR=[ scalar, VSX ])
      if: ${{ startsWith(matrix.name, 'PPC64') }}
      run: |
        CPPFLAGS="-DXXH_VECTOR=XXH_SCALAR" LDFLAGS="-static" CC=$XCC RUN_ENV=$XEMU make clean check
        CPPFLAGS="-DXXH_VECTOR=XXH_VSX" CFLAGS="-O3 -maltivec -mvsx -mpower8-vector -mcpu=power8" LDFLAGS="-static" CC=$XCC RUN_ENV=$XEMU make clean check

    - name: S390X (XXH_VECTOR=[ scalar, VSX ])
      if: ${{ startsWith(matrix.name, 'S390X') }}
      run: |
        CPPFLAGS="-DXXH_VECTOR=XXH_SCALAR" LDFLAGS="-static" CC=$XCC RUN_ENV=$XEMU make clean check
        CPPFLAGS=-DXXH_VECTOR=XXH_VSX CFLAGS="-O3 -march=arch11 -mzvector" LDFLAGS="-static" CC=$XCC RUN_ENV=$XEMU make clean check

    - name: MIPS-M68K-RISCV-SPARC (XXH_VECTOR=[ scalar ])
      if: ${{ startsWith(matrix.name, 'MIPS') || startsWith(matrix.name, 'M68K') || startsWith(matrix.name, 'RISC-V') || startsWith(matrix.name, 'SPARC') }}
      run: |
        make clean; LDFLAGS="-static" CC=$XCC RUN_ENV=$XEMU make check

    - name: LoongArch (XXH_VECTOR=[ scalar, LSX ])
      if: ${{ startsWith(matrix.name, 'LoongArch') }}
      run: |
        CPPFLAGS="-DXXH_VECTOR=XXH_SCALAR" LDFLAGS="-static" CC=$XCC RUN_ENV=$XEMU make clean check
        CPPFLAGS=-DXXH_VECTOR=XXH_LSX CFLAGS="-O3 -march=la464 -mlsx" LDFLAGS="-static" CC=$XCC RUN_ENV=$XEMU make clean check

  # macOS

  macos-general:
    name: ${{ matrix.system.os }}
    runs-on: ${{ matrix.system.os }}
    strategy:
      fail-fast: false  # 'false' means Don't stop matrix workflows even if some matrix failed.
      matrix:
        system: [
          { os: macos-13     },
          { os: macos-14     },
          { os: macos-15     },
          { os: macos-latest },
        ]
    steps:
    - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

    - name: Environment info
      run: |
        echo && clang --version
        echo && sysctl -a | grep machdep.cpu   # cpuinfo

    - name: make
      run: |
        CFLAGS="-Werror" make clean default

    - name: make test
      run: |
        # test scenario where "stdout" is not the console
        make clean test MOREFLAGS='-Werror' | tee


  # Windows, { VC++2022, VC++2019 } x { x64, Win32, ARM, ARM64 }
  #
  # - Default shell for Windows environment is PowerShell Core.
  #   https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#using-a-specific-shell
  #
  # - "windows-2022" uses Visual Studio 2022.
  #   https://github.com/actions/virtual-environments/blob/main/images/win/Windows2022-Readme.md#visual-studio-enterprise-2022
  #
  # - "windows-2019" uses Visual Studio 2019.
  #   https://github.com/actions/virtual-environments/blob/main/images/win/Windows2019-Readme.md#visual-studio-enterprise-2019

  windows-visualc-general:
    name: ${{ matrix.system.vc }}, ${{ matrix.arch }}
    runs-on: ${{ matrix.system.os }}   # Runs-on foreach value of strategy.matrix.system.os
    strategy:
      fail-fast: false  # 'false' means: Don't stop matrix workflows even if some matrix failed.
      matrix:
        system: [
          { os: windows-2022, vc: "VC++ 2022", clangcl: 'true', },
          { os: windows-2019, vc: "VC++ 2019", clangcl: 'true', },
        ]
        arch: [ x64, Win32, ARM64 ]

    steps:
    - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

    - name: Build ${{ matrix.system.os }}, ${{ matrix.arch }}
      run: |
        cd cmake_unofficial
        mkdir build
        cd build
        cmake .. -DCMAKE_BUILD_TYPE=Release -A ${{ matrix.arch }} -DCMAKE_C_FLAGS="/W4 /WX"
        cmake --build . --config Release

    - name: Test
      # Run benchmark for testing only if target arch is x64 or Win32.
      if: ${{ matrix.arch == 'x64' || matrix.arch == 'Win32' }}
      run: |
        .\cmake_unofficial\build\Release\xxhsum.exe -bi1

    - name: Build ${{ matrix.system.os }}, ${{ matrix.arch }}, with DISPATCH
      # DISPATCH only if target arch is x64 or Win32.
      if: ${{ ( matrix.arch == 'x64' || matrix.arch == 'Win32' ) }}
      run: |
        cd cmake_unofficial
        mkdir build-visual-dispatch
        cd build-visual-dispatch
        cmake .. -DCMAKE_BUILD_TYPE=Release -DDISPATCH=ON -A x64 -DCMAKE_C_FLAGS="/W4 /WX"
        cmake --build . --config Release

    - name: Runtime Test (DISPATCH)
      # Run benchmark for testing only if target arch is x64 or Win32.
      if: ${{ ( matrix.arch == 'x64' || matrix.arch == 'Win32' ) }}
      run: |
        .\cmake_unofficial\build-visual-dispatch\Release\xxhsum.exe -V | grep autoVec
        .\cmake_unofficial\build-visual-dispatch\Release\xxhsum.exe -bi1


    - name: Build ${{ matrix.system.os }}, clang-cl, ${{ matrix.arch }}
      if: ${{ matrix.system.clangcl == 'true' }}
      run: |
        cd cmake_unofficial
        mkdir build-clang-cl
        cd build-clang-cl
        cmake .. -DCMAKE_BUILD_TYPE=Release -A x64 -DCMAKE_GENERATOR_TOOLSET=ClangCL
        cmake --build . --config Release

    - name: Test (clang-cl)
      # Run benchmark for testing only if target arch is x64 or Win32.
      if: ${{ matrix.system.clangcl == 'true' && ( matrix.arch == 'x64' || matrix.arch == 'Win32' ) }}
      run: |
        .\cmake_unofficial\build-clang-cl\Release\xxhsum.exe -bi1



  # Windows, { mingw64, mingw32 }
  #
  # - Shell for msys2 is sh (msys2).  defaults.run.shell is for this setting.
  #
  # https://github.com/msys2/MINGW-packages/blob/master/.github/workflows/main.yml
  # https://github.com/actions/starter-workflows/issues/95

  windows-msys2-general:
    name: Windows ${{ matrix.msystem }}
    runs-on: windows-latest
    strategy:
      fail-fast: false  # 'false' means Don't stop matrix workflows even if some matrix failed.
      matrix:
        include: [
          { msystem: mingw64, toolchain: mingw-w64-x86_64-toolchain },
          { msystem: mingw32, toolchain: mingw-w64-i686-toolchain },
        ]
    defaults:
      run:
        shell: msys2 {0}
    steps:
      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
      - uses: msys2/setup-msys2@7efe20baefed56359985e327d329042cde2434ff # v2
        with:
          msystem: MSYS
          install: mingw-w64-i686-make ${{ matrix.toolchain }}
          update: true

      - name: Update
        run: |
          pacman --noconfirm -Suuy
          pacman --noconfirm -Suu

      - name: mingw64
        if: ${{ matrix.msystem == 'mingw64' }}
        run: |
          PATH=/mingw64/bin:$PATH /mingw32/bin/mingw32-make clean test gcc-og-test MOREFLAGS=-Werror
          PATH=/mingw64/bin:$PATH /mingw32/bin/mingw32-make -C tests/bench
          # Abort if result of "file ./xxhsum.exe" doesn't contain 'x86-64'.
          # Expected output is "./xxhsum.exe: PE32+ executable (console) x86-64, for MS Windows"
          file ./xxhsum.exe
          file ./xxhsum.exe | grep -q 'x86-64' || $(exit 1)
          ./xxhsum.exe --version

      - name: mingw32
        if: ${{ matrix.msystem == 'mingw32' }}
        run: |
          PATH=/mingw32/bin:$PATH /mingw32/bin/mingw32-make.exe clean test MOREFLAGS=-Werror
          PATH=/mingw32/bin:$PATH /mingw32/bin/mingw32-make.exe -C tests/bench
          # Abort if result of "file ./xxhsum.exe" doesn't contain '80386'.
          # Expected output is "./xxhsum.exe: PE32 executable (console) Intel i386, for MS Windows"
          file ./xxhsum.exe
          file ./xxhsum.exe | grep -q '386' || $(exit 1)
          ./xxhsum.exe --version
