Skip to content

Fix build

Fix build #23

Workflow file for this run

name: CI
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
permissions:
contents: read
jobs:
build-and-test:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]
build_type: [Debug, Release]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Clone vcpkg
shell: bash
run: git clone --depth 1 https://github.com/microsoft/vcpkg.git "${{ runner.temp }}/vcpkg"
# The SlickQuant dependency libraries (slick-net, hyperliquid-cpp, ...) build
# their Release config with -march=native, so the binaries vcpkg produces are
# tuned to whatever CPU the runner that built them happened to have. Restoring
# such a cache onto a runner with a narrower instruction set makes the tests
# die with SIGILL on an AVX-512 opcode inside the dependency:
#
# Program received signal SIGILL
# => vmovdqu8 %xmm0,0x20(%rbx)
# in slick::net::Websocket<...>::Websocket(...)
# from hyperliquid::WebsocketManager::init(...)
#
# That is why the Linux Release job failed intermittently and passed on
# re-run: it depended on which CPU the cache came from. Key the cache on the
# runner's CPU features so a cache is only ever reused on compatible hardware.
- name: CPU signature for the vcpkg cache key
id: cpusig
shell: bash
run: |
if [ "$RUNNER_OS" = "Linux" ]; then
raw=$(grep -m1 '^flags' /proc/cpuinfo | cut -d: -f2 | tr ' ' '\n' \
| grep -E '^(sse4_[12]|avx|avx2|avx512[a-z0-9_]*|bmi[12]|fma)$' | sort -u | tr '\n' ',')
else
raw=$(wmic cpu get Name /value 2>/dev/null | tr -d '\r' | grep '=' || echo "windows-unknown")
fi
echo "CPU signature source: $raw"
echo "sig=$(printf '%s' "$raw" | sha256sum | cut -c1-16)" >> "$GITHUB_OUTPUT"
# No vcpkg.json manifest is committed in this repo by design (see CLAUDE.md), so
# dependencies are installed explicitly in classic mode below.
- name: Cache vcpkg
uses: actions/cache@v4
with:
path: |
${{ runner.temp }}/vcpkg/installed
${{ runner.temp }}/vcpkg/downloads
${{ runner.temp }}/vcpkg/packages
key: vcpkg-${{ runner.os }}-cpu${{ steps.cpusig.outputs.sig }}-${{ hashFiles('.github/workflows/ci.yml') }}
- name: Bootstrap vcpkg (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
& "${{ runner.temp }}\vcpkg\bootstrap-vcpkg.bat" -disableMetrics
- name: Bootstrap vcpkg (Unix)
if: runner.os != 'Windows'
shell: bash
run: |
"${{ runner.temp }}/vcpkg/bootstrap-vcpkg.sh" -disableMetrics
- name: Install dependencies via vcpkg
shell: bash
run: |
"${{ runner.temp }}/vcpkg/vcpkg" install \
quickfix \
nlohmann-json \
jwt-cpp \
foonathan-memory \
boost-uuid \
gtest \
slick-logger \
slick-socket \
slick-object-pool \
coinbase-advanced-cpp \
slickquant-hyperliquid-cpp \
"uwebsockets[core,ssl,zlib]"
- name: Configure CMake
shell: bash
run: >
cmake -B build
-DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
-DCMAKE_TOOLCHAIN_FILE="${{ runner.temp }}/vcpkg/scripts/buildsystems/vcpkg.cmake"
- name: Build
run: cmake --build build --config ${{ matrix.build_type }} --parallel
- name: Run tests
working-directory: build
run: ctest -C ${{ matrix.build_type }} --output-on-failure
# The Linux Release job intermittently dies with SIGILL inside the tests that
# construct an Exchange or a gateway; ctest only reports "Exception: Illegal"
# with no location. Re-run the failures under gdb to capture where and on
# which thread, since the crash cannot be reproduced on Windows or in Debug.
- name: Capture backtrace on test failure (Linux)
if: failure() && runner.os == 'Linux'
working-directory: build
run: |
sudo apt-get update && sudo apt-get install -y gdb
ulimit -c unlimited
# Ask ctest which tests failed, then run each under gdb.
failed=$(ctest -C ${{ matrix.build_type }} -N --rerun-failed 2>/dev/null \
| sed -n 's/^ *Test *#[0-9]*: //p' | head -5)
if [ -z "$failed" ]; then
echo "ctest reported no rerun-failed list; falling back to the first exchange test"
failed="HyperliquidRestTest.PlaceOrder_BuyLimit_Gtc_ReturnsResting"
fi
for t in $failed; do
echo "::group::gdb backtrace for $t"
gdb -batch -return-child-result \
-ex "run" \
-ex "echo \n===== signal / faulting frame =====\n" \
-ex "bt" \
-ex "echo \n===== all threads =====\n" \
-ex "thread apply all bt" \
-ex "info registers rip" \
-ex "x/8i \$rip" \
--args ./tests/slick_sim_tests --gtest_filter="$t" || true
echo "::endgroup::"
done
# Release-config artifacts are uploaded here so release.yml can reuse this
# exact, already-tested build instead of recompiling from scratch on tag push.
- name: Stage release artifact (Windows)
if: matrix.build_type == 'Release' && runner.os == 'Windows'
shell: pwsh
run: |
New-Item -ItemType Directory -Force -Path release-stage | Out-Null
$exe = Get-ChildItem -Path build -Recurse -Filter slick-sim.exe | Select-Object -First 1
Copy-Item $exe.FullName -Destination release-stage
Copy-Item "${{ runner.temp }}\vcpkg\installed\x64-windows\bin\*.dll" -Destination release-stage -ErrorAction SilentlyContinue
- name: Stage release artifact (Linux)
if: matrix.build_type == 'Release' && runner.os == 'Linux'
shell: bash
run: |
mkdir -p release-stage
find build -type f -name slick-sim -exec cp {} release-stage/ \;
cp "${{ runner.temp }}/vcpkg/installed/x64-linux/lib/"*.so* release-stage/ 2>/dev/null || true
- name: Upload release build artifact
if: matrix.build_type == 'Release'
uses: actions/upload-artifact@v4
with:
name: slick-sim-${{ runner.os }}-release
path: release-stage/*