Skip to content

Merge pull request #3124 from GaijinEntertainment/bbatkin/jit-paralle… #1176

Merge pull request #3124 from GaijinEntertainment/bbatkin/jit-paralle…

Merge pull request #3124 from GaijinEntertainment/bbatkin/jit-paralle… #1176

Workflow file for this run

name: build
on:
push:
branches: [master]
pull_request:
workflow_dispatch:
defaults:
run:
shell: bash
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
###########################################################
pre_job:
###########################################################
# continue-on-error: true # Uncomment once integration is finished
runs-on: ubuntu-latest-fat
# Map a step output to a job output
outputs:
should_skip: ${{ steps.skip_check.outputs.should_skip }}
steps:
- id: skip_check
uses: fkirc/skip-duplicate-actions@v5
with:
# All of these options are optional, so you can remove them if you are happy with the defaults
concurrent_skipping: 'same_content'
do_not_skip: '["pull_request", "workflow_dispatch", "release"]'
- name: Cache LLVM
uses: actions/cache@v3
id: llvm-cache
with:
# Cache LLVM.dll, to make CI faster.
path: build/_deps/das_llvm_shared_lib-src
key: ${{ runner.os }}-${{ hashFiles('modules/dasLLVM/CMakeLists.txt') }}
###########################################################
build:
###########################################################
needs: pre_job
if: needs.pre_job.outputs.should_skip != 'true'
runs-on: ${{ matrix.runner }}
# actions: write needed for `gh cache delete` in the sccache refresh step.
permissions:
contents: read
actions: write
env:
das_dll_build: 'NO'
das_llvm_disabled: 'OFF'
strategy:
fail-fast: false
matrix:
target: [linux, linux_arm, darwin15, darwin26, windows]
architecture: [32, 64, arm64]
cmake_preset: [ Debug, Release ]
sanitizers: [none]
include:
- target: linux
release_target: linux
release_arch: x86_64
runner: ubuntu-latest-fat
archive_ext: tar.gz
sanitizers: none
# Sanitizer matrix — Linux + Release + full tests (dastest + test_aot
# + ctest). Release keeps walltime in budget; the previous Debug+ASAN
# was prohibitive for production CI. See issue #2530.
- target: linux
architecture: 64
runner: ubuntu-latest-fat
cmake_preset: Release
sanitizers: asan
build_name: linux_asan
build_system: cmake
cmake_generator: Ninja
- target: linux
architecture: 64
runner: ubuntu-latest-fat
cmake_preset: Release
sanitizers: tsan
build_name: linux_tsan
build_system: cmake
cmake_generator: Ninja
- target: linux
architecture: 64
runner: ubuntu-latest-fat
cmake_preset: Release
sanitizers: ubsan
build_name: linux_ubsan
build_system: cmake
cmake_generator: Ninja
- target: linux_arm
release_target: linux
release_arch: arm64
runner: ubuntu-24.04-arm-fat
archive_ext: tar.gz
- target: darwin15
architecture: arm64
release_target: darwin15
release_arch: arm64
runner: macos-15-xlarge # Apple Silicon arm64, M2
architecture_string: arm64
archive_ext: tar.gz
- target: darwin26
release_target: darwin26
release_arch: arm64
runner: macos-26-xlarge # Apple Silicon arm64, M2
architecture_string: arm64
archive_ext: tar.gz
- target: windows
runner: windows-latest-fat
archive_ext: zip
- target: windows
build_system: cmake
cmake_generator: Ninja
- target: darwin15
build_system: cmake
cmake_generator: Ninja
- target: darwin26
build_system: cmake
cmake_generator: Ninja
- target: linux
build_system: cmake
cmake_generator: Ninja
- target: linux_arm
build_system: cmake
cmake_generator: Ninja
- target: windows
release_target: windows
release_arch: x86
architecture: 32
architecture_string: Win32
- target: windows
release_target: windows
release_arch: x86_64
architecture: 64
architecture_string: x64
# RelWithDebInfo only on Windows x64
# jit_disabled: skip the JIT prewarm + JIT test sweep here. JIT on
# win64-MSVC stays covered by the Release cell below and by the full
# clang JIT sweep in build_windows_mingw — running it on all three
# win64 presets just triples the slowest jobs in the matrix.
- target: windows
architecture: 64
cmake_preset: RelWithDebInfo
sanitizers: none
runner: windows-latest-fat
archive_ext: zip
build_system: cmake
cmake_generator: Ninja
release_target: windows
release_arch: x86_64
architecture_string: x64
jit_disabled: 'ON'
# Debug win64 also skips JIT (same rationale as RelWithDebInfo above).
- target: windows
architecture: 64
cmake_preset: Debug
jit_disabled: 'ON'
exclude:
# macOS Intel (darwin15 x86_64) has no prebuilt LLVM.dll (the
# llvm-release workflow doesn't build one) and Apple no longer makes
# new Intel macOS runners worth gating on. Drop entirely.
- target: darwin15
architecture: 64
- target: darwin15
architecture: 32
- target: darwin26
architecture: 32
- target: darwin26
architecture: 64
- target: linux
architecture: 32
- target: linux
architecture: arm64
- target: linux_arm
architecture: 32
- target: linux_arm
architecture: arm64 # todo
- target: windows
architecture: arm64 # todo https://github.com/actions/partner-runner-images/tree/main?tab=readme-ov-file#available-images
steps:
- name: "SCM Checkout"
uses: actions/checkout@v4
- name: "Exclude workspace from Windows Defender"
if: runner.os == 'Windows'
shell: pwsh
continue-on-error: true
# Real-time Defender scans every .obj/.exe/.dll the build writes and every
# test process/DLL load; excluding the workspace cuts Windows CI wall-time.
# continue-on-error: a managed-Defender runner must not fail the job.
run: |
Add-MpPreference -ExclusionPath "${{ github.workspace }}"
Add-MpPreference -ExclusionProcess "daslang.exe"
Add-MpPreference -ExclusionProcess "test_aot.exe"
- name: "Install CMake and Ninja"
uses: lukka/get-cmake@latest
- if: runner.os == 'Windows'
uses: ilammy/setup-nasm@v1 # need nasm for openssl
- name: "Set up MSVC environment (Windows)"
if: runner.os == 'Windows'
# cl.exe on PATH so the bash build step drives Ninja with MSVC. arch
# follows the matrix (x86 for the 32-bit job). MUST run BEFORE the vcpkg
# openssl step: msvc-dev-cmd's vcvars sets VCPKG_ROOT to the VS-bundled
# vcpkg, so the openssl step has to write our VCPKG_ROOT last.
uses: ilammy/msvc-dev-cmd@v1
with:
arch: ${{ matrix.architecture == 32 && 'x86' || 'x64' }}
- name: "Cache vcpkg + openssl"
if: runner.os == 'Windows'
uses: actions/cache@v4
with:
# Whole vcpkg/ dir: bootstrapped vcpkg.exe + installed/<triplet>/openssl.
# On hit, install step skips clone + bootstrap + openssl build.
path: vcpkg
key: vcpkg-${{ matrix.architecture == 32 && 'x86' || 'x64' }}-windows-v1
- name: "Install openssl windows"
if: runner.os == 'Windows'
run: |
if [ ! -x vcpkg/vcpkg.exe ] && [ ! -x vcpkg/vcpkg ]; then
git clone https://github.com/microsoft/vcpkg && ./vcpkg/bootstrap-vcpkg.sh
fi
./vcpkg/vcpkg install openssl:${{ matrix.architecture == 32 && 'x86' || 'x64' }}-windows --binarycaching
echo "VCPKG_ROOT=$(pwd)/vcpkg" >> $GITHUB_ENV
echo "CMAKE_TOOLCHAIN_FILE=$(pwd)/vcpkg/scripts/buildsystems/vcpkg.cmake" >> $GITHUB_ENV
- name: "Install: Required Dev Packages"
run: |
set -eux
case "${{ matrix.target }}${{ matrix.architecture }}" in
darwin15arm64|darwin26arm64)
brew install bison
echo 'export PATH="/usr/local/opt/bison/bin:$PATH"' >> ~/.bash_profile
export LDFLAGS="-L/usr/local/opt/bison/lib"
;;
darwin1564|darwin2664)
brew install bison
echo 'export PATH="/opt/homebrew/opt/bison/bin:$PATH"' >> ~/.bash_profile
export LDFLAGS="-L/opt/homebrew/opt/bison/lib"
;;
esac
case "${{ matrix.target }}${{ matrix.architecture }}" in
linux64)
echo "MARCH=64" >> $GITHUB_ENV
sudo apt-get update -y
sudo apt-get install --no-install-recommends -y \
libatomic-ops-dev \
libglu1-mesa-dev \
freeglut3-dev \
mesa-common-dev \
libglfw3-dev \
libfreetype6-dev \
libudev-dev \
libopenal-dev \
libvorbis-dev \
libflac-dev \
libclang-dev \
libx11-dev \
libxrandr-dev \
libxcursor-dev \
libxinerama-dev \
libxi-dev
;;
esac
# sccache with LOCAL-DISK backend, wrapped in ONE actions/cache entry per
# matrix config. The GHA backend writes one cache item per TU (~40k items,
# quota fragmentation, ~74% concurrent-write failures); local disk keeps
# all objects in $SCCACHE_DIR and we persist it as a single tarball.
# Windows is on Ninja now (honors CMAKE_*_COMPILER_LAUNCHER); its MSVC
# compiles are cacheable because daslang builds with /Z7 (CMakeCommon.txt) —
# debug info embedded in the .obj. sccache refuses to cache /Zi (separate
# shared PDB) output.
- uses: mozilla-actions/sccache-action@v0.0.10
- run: |
echo "SCCACHE_DIR=${{ runner.temp }}/sccache" >> $GITHUB_ENV
echo "SCCACHE_GHA_ENABLED=false" >> $GITHUB_ENV
# Non-Windows: export the launcher via env (also wraps the GLFW/libhv
# ExternalProject sub-builds — harmless on gcc/clang). Windows must NOT
# export it: CMake seeds CMAKE_<LANG>_COMPILER_LAUNCHER from the env
# into the sub-cmakes, where sccache + MSVC /Zi (those sub-builds keep
# /Zi) + parallel Ninja collide on the shared glfw.pdb (C1041). Windows
# instead passes the launcher as -D on the MAIN configure only (Build
# step), scoping sccache to daslang's own /Z7 TUs.
if [ "$RUNNER_OS" != "Windows" ]; then
echo "CMAKE_C_COMPILER_LAUNCHER=sccache" >> $GITHUB_ENV
echo "CMAKE_CXX_COMPILER_LAUNCHER=sccache" >> $GITHUB_ENV
fi
# Stable per-config key, one fixed slot. Restore always; on master,
# delete + re-save the same key after Build so the slot is overwritten
# with fresh objects (GHA caches are immutable — plain save under an
# existing key is a no-op, so we delete first). PRs read-only. Bounded
# footprint: N configs × one tarball, no run_id pileup.
- name: "Restore sccache objects"
uses: actions/cache/restore@v4
with:
path: ${{ runner.temp }}/sccache
key: sccache-${{ matrix.target }}-${{ matrix.architecture }}-${{ matrix.cmake_preset }}-${{ matrix.sanitizers }}
- name: "Override das_llvm_disabled for win32"
if: matrix.target == 'windows' && matrix.architecture == 32
shell: bash
run: echo "das_llvm_disabled=ON" >> $GITHUB_ENV
- name: "Build: Daslang"
run: |
set -eux
mkdir build
case "${{ matrix.build_system }}" in
cmake)
case "${{ matrix.target }}${{ matrix.architecture }}" in
linux64)
CC=clang CXX=clang++ cmake --no-warn-unused-cli -B./build -DCMAKE_BUILD_TYPE:STRING=${{ matrix.cmake_preset }} -G \
"${{ matrix.cmake_generator }}" -DDAS_USE_SANITIZER=${{ matrix.sanitizers }} -DDAS_LLVM_DISABLED=${{ env.das_llvm_disabled }}
cd build
ninja
;;
windows32)
export PATH="/c/Strawberry/perl/bin:$PATH" # prepend Strawberry perl to path, so openssl will use it.
# Launcher passed as -D here (not env) so it scopes to daslang's
# own targets and does NOT leak into the GLFW/libhv sub-builds.
# daslang's MSVC debug info is /Z7 (CMakeCommon.txt) so sccache
# can cache it.
cmake --no-warn-unused-cli -B./build -G "${{ matrix.cmake_generator }}" -DCMAKE_BUILD_TYPE:STRING=${{ matrix.cmake_preset }} -DCMAKE_C_COMPILER_LAUNCHER=sccache -DCMAKE_CXX_COMPILER_LAUNCHER=sccache -DCMAKE_TOOLCHAIN_FILE="$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake"
cmake --build ./build --config ${{ matrix.cmake_preset }} --parallel
;;
windows64)
export PATH="/c/Strawberry/perl/bin:$PATH" # prepend Strawberry perl to path, so openssl will use it.
# Launcher passed as -D here (not env) so it scopes to daslang's
# own targets and does NOT leak into the GLFW/libhv sub-builds.
# daslang's MSVC debug info is /Z7 (CMakeCommon.txt) so sccache
# can cache it.
cmake --no-warn-unused-cli -B./build -G "${{ matrix.cmake_generator }}" -DCMAKE_BUILD_TYPE:STRING=${{ matrix.cmake_preset }} -DCMAKE_C_COMPILER_LAUNCHER=sccache -DCMAKE_CXX_COMPILER_LAUNCHER=sccache -DDAS_LLVM_DISABLED=${{ env.das_llvm_disabled }} -DCMAKE_TOOLCHAIN_FILE="$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake"
cmake --build ./build --config ${{ matrix.cmake_preset }} --parallel
;;
linux_arm*)
CC=clang CXX=clang++ cmake --no-warn-unused-cli -B./build -DCMAKE_BUILD_TYPE:STRING=${{ matrix.cmake_preset }} -DDAS_GLFW_DISABLED=ON -DDAS_HV_DISABLED=OFF -DDAS_SQLITE_DISABLED=OFF -DDAS_LLVM_DISABLED=${{ env.das_llvm_disabled }} -G \
"${{ matrix.cmake_generator }}"
cd build
ninja
;;
*)
CC=clang CXX=clang++ cmake --no-warn-unused-cli -B./build -DCMAKE_OSX_ARCHITECTURES="${{ matrix.architecture_string }}" -DCMAKE_BUILD_TYPE:STRING=${{ matrix.cmake_preset }} -DDAS_LLVM_DISABLED=${{ env.das_llvm_disabled }} -G "${{ matrix.cmake_generator }}"
cd build
ninja
;;
esac
;;
esac
- name: "Refresh sccache slot"
if: github.ref == 'refs/heads/master'
env:
GH_TOKEN: ${{ github.token }}
SCKEY: sccache-${{ matrix.target }}-${{ matrix.architecture }}-${{ matrix.cmake_preset }}-${{ matrix.sanitizers }}
run: gh cache delete "$SCKEY" -R ${{ github.repository }} || true
- name: "Save sccache objects"
if: github.ref == 'refs/heads/master'
uses: actions/cache/save@v4
with:
path: ${{ runner.temp }}/sccache
key: sccache-${{ matrix.target }}-${{ matrix.architecture }}-${{ matrix.cmake_preset }}-${{ matrix.sanitizers }}
- name: "Prewarm JIT cache"
if: env.das_llvm_disabled != 'ON' && matrix.jit_disabled != 'ON'
run: |
set -eux
cmake --build ./build --config ${{ matrix.cmake_preset }} --target jit_cache_all_tests
- name: "Test"
run: |
set -eux
# When daslang is sanitizer-instrumented, its JIT-emitted .dll cache
# link cmd needs -fsanitize=<kind> to pull the sanitizer runtime
# (otherwise unresolved __ubsan_*/__asan_*/__tsan_* symbols in lib.so).
JIT_LINKER_STRING=""
case "${{ matrix.sanitizers }}" in
ubsan) JIT_LINKER_STRING="--jit-linker-string=-fsanitize=undefined" ;;
asan) JIT_LINKER_STRING="--jit-linker-string=-fsanitize=address" ;;
tsan) JIT_LINKER_STRING="--jit-linker-string=-fsanitize=thread" ;;
esac
# daslang built with clang on sanitizer matrix — JIT-emitted .dll
# must link with the same compiler (incompatible asan/tsan runtimes
# otherwise). c++ default = g++ on Ubuntu, mismatches.
JIT_PATH_TO_LINKER=""
if [ "${{ matrix.sanitizers }}" != "none" ] && [ -n "${{ matrix.sanitizers }}" ]; then
JIT_PATH_TO_LINKER="--jit-path-to-linker=clang++"
fi
# Match JIT codegen opt level to build type: Debug → -O0 (fast codegen),
# Release/RelWithDebInfo → -O3.
case "${{ matrix.cmake_preset }}" in
Debug) JIT_OPT="--jit-opt-level=0" ;;
*) JIT_OPT="--jit-opt-level=3" ;;
esac
case "${{ matrix.target }}${{ matrix.architecture }}" in
linux64)
cd bin
# LSan suppressions: format_error (fmt::throw_format_error allocates
# std::runtime_error whose internal string is reported as leaked
# because the exception object isn't always destroyed); uriParseSingleUriA
# / uriMakeOwner (Uri handle bound to daslang without auto-finalize —
# tracked separately, real fix is in the binding).
printf 'leak:format_error\nleak:uriParseSingleUriA\nleak:uriMakeOwner\n' > suppressions.txt
export LSAN_OPTIONS="suppressions=$(pwd)/suppressions.txt"
# Sanitizer matrix: only run language tests under JIT (full test
# suite under asan/tsan/ubsan adds ~10m wall-clock without proportionate
# coverage value). Non-sanitizer keeps the full sweep.
if [ "${{ matrix.sanitizers }}" != "none" ]; then
TEST_DIR=_dasroot_/tests/language
else
TEST_DIR=_dasroot_/tests
fi
# Use more time to pass UBSAN and disable leaks in JIT mode because we exit using exit(), and do not call destructors.
[ "${{ env.das_llvm_disabled }}" = "ON" ] || ASAN_OPTIONS=detect_leaks=0 ./daslang _dasroot_/dastest/dastest.das -jit -- $JIT_LINKER_STRING $JIT_PATH_TO_LINKER $JIT_OPT --color --failures-only --timeout 900 --test $TEST_DIR || ASAN_OPTIONS=detect_leaks=0 ./daslang _dasroot_/dastest/dastest.das -jit -- $JIT_LINKER_STRING $JIT_PATH_TO_LINKER $JIT_OPT --color --failures-only --isolated-mode --timeout 3600 --test $TEST_DIR
# Interpreter sweep: non-sanitizer only.
if [ "${{ matrix.sanitizers }}" = "none" ]; then
./daslang _dasroot_/dastest/dastest.das -- --color --failures-only --timeout 900 --test _dasroot_/tests || ./daslang _dasroot_/dastest/dastest.das -- --color --failures-only --isolated-mode --timeout 3600 --test _dasroot_/tests
fi
;;
windows32)
cd bin
./daslang _dasroot_/dastest/dastest.das -- --color --failures-only --timeout 900 --test _dasroot_/tests || ./daslang _dasroot_/dastest/dastest.das -- --color --failures-only --isolated-mode --timeout 3600 --test _dasroot_/tests
;;
windows*)
cd bin
[ "${{ env.das_llvm_disabled }}" = "ON" ] || [ "${{ matrix.jit_disabled }}" = "ON" ] || ./daslang _dasroot_/dastest/dastest.das -jit -- $JIT_LINKER_STRING $JIT_PATH_TO_LINKER $JIT_OPT --timeout 900 --color --failures-only --test _dasroot_/tests || ./daslang _dasroot_/dastest/dastest.das -jit -- $JIT_LINKER_STRING $JIT_PATH_TO_LINKER $JIT_OPT --color --failures-only --isolated-mode --timeout 3600 --test _dasroot_/tests
./daslang _dasroot_/dastest/dastest.das -- --color --failures-only --timeout 900 --test _dasroot_/tests || ./daslang _dasroot_/dastest/dastest.das -- --color --failures-only --isolated-mode --timeout 3600 --test _dasroot_/tests
;;
linux_arm64)
cd bin
# Skip JIT tests on the Debug cmake preset — LLVM ARM64 SelectionDAG
# hangs reproducibly mid-suite under Debug (different test each run,
# ~20 min in). Tracked separately. Release of the same matrix still
# runs JIT — keep --failures-only off there so PASS lines print and
# name the test running just before the hang if it reoccurs (see
# RC2 release run #25572466058).
[ "${{ env.das_llvm_disabled }}" = "ON" ] || [ "${{ matrix.cmake_preset }}" = "Debug" ] || ./daslang _dasroot_/dastest/dastest.das -jit -- $JIT_LINKER_STRING $JIT_PATH_TO_LINKER $JIT_OPT --color --timeout 900 --test _dasroot_/tests || ./daslang _dasroot_/dastest/dastest.das -jit -- $JIT_LINKER_STRING $JIT_PATH_TO_LINKER $JIT_OPT --color --failures-only --isolated-mode --timeout 3600 --test _dasroot_/tests
./daslang _dasroot_/dastest/dastest.das -- --color --failures-only --timeout 900 --test _dasroot_/tests || ./daslang _dasroot_/dastest/dastest.das -- --color --failures-only --isolated-mode --timeout 3600 --test _dasroot_/tests
;;
*)
cd bin
[ "${{ env.das_llvm_disabled }}" = "ON" ] || ./daslang _dasroot_/dastest/dastest.das -jit -- $JIT_LINKER_STRING $JIT_PATH_TO_LINKER $JIT_OPT --color --failures-only --timeout 900 --test _dasroot_/tests || ./daslang _dasroot_/dastest/dastest.das -jit -- $JIT_LINKER_STRING $JIT_PATH_TO_LINKER $JIT_OPT --color --failures-only --isolated-mode --timeout 3600 --test _dasroot_/tests
./daslang _dasroot_/dastest/dastest.das -- --color --failures-only --timeout 900 --test _dasroot_/tests || ./daslang _dasroot_/dastest/dastest.das -- --color --failures-only --isolated-mode --timeout 3600 --test _dasroot_/tests
;;
esac
- name: "Small C++ Tests"
run: |
set -eux
# Suppress LSan false-positives from format_error and JIT-mode exit() paths;
# see "Test" step above for the same suppressions.
printf 'leak:format_error\nleak:uriParseSingleUriA\nleak:uriMakeOwner\n' > build/suppressions.txt
export LSAN_OPTIONS="suppressions=$(pwd)/build/suppressions.txt"
cd build
case "${{ matrix.target }}${{ matrix.architecture }}" in
windows*)
ctest --build-config "${{ matrix.cmake_preset }}" -L small --output-on-failure
;;
*)
ctest -L small --output-on-failure
;;
esac
- name: "Slow Release Tests"
if: matrix.cmake_preset == 'Release'
run: |
set -eux
case "${{ matrix.target }}${{ matrix.architecture }}" in
windows32)
echo "Skipping AOT tests on 32-bit Windows"
;;
windows*)
cd bin
./test_aot -use-aot _dasroot_/dastest/dastest.das -- --use-aot --color --failures-only --timeout 900 --test _dasroot_/tests
;;
*)
cd bin
# Same suppressions as the "Test" step — sanitizer matrix entries
# need them here too.
printf 'leak:format_error\nleak:uriParseSingleUriA\nleak:uriMakeOwner\n' > suppressions.txt
export LSAN_OPTIONS="suppressions=$(pwd)/suppressions.txt"
./test_aot -use-aot _dasroot_/dastest/dastest.das -- --use-aot --color --failures-only --timeout 900 --test _dasroot_/tests
;;
esac
###########################################################
bundle_smoke:
###########################################################
# Catches release-bundle install-rule regressions at PR time on the
# platform that produces 95% of such bugs (Linux x86_64). Mirrors the
# release.yml linux64 build path: same module flags via ci/release_modules.txt,
# same install layout (cmake --install --prefix ./daslang_bundle), same
# ci/smoke_test_bundle.sh that release.yml runs. Full-matrix smoke is
# still gated at release-cut time in release.yml.
###########################################################
needs: pre_job
if: needs.pre_job.outputs.should_skip != 'true'
runs-on: ubuntu-latest-fat
steps:
- name: "SCM Checkout"
uses: actions/checkout@v4
- name: "Install CMake and Ninja"
uses: lukka/get-cmake@latest
- name: "Install: Required Dev Packages"
run: |
set -eux
sudo apt-get update -y
sudo apt-get install --no-install-recommends -y \
libatomic-ops-dev \
libglu1-mesa-dev \
freeglut3-dev \
mesa-common-dev \
libglfw3-dev \
libfreetype6-dev \
libudev-dev \
libopenal-dev \
libvorbis-dev \
libflac-dev \
libx11-dev \
libxrandr-dev \
libxcursor-dev \
libxinerama-dev \
libxi-dev
- name: "Build: Daslang with release modules"
run: |
set -eux
mkdir build
ACTIVE_MODULES=$(cat ci/release_modules.txt | grep -v "^#" | cut -d':' -f2 | sed 's|^|-D|' | xargs)
CC=clang CXX=clang++ cmake --no-warn-unused-cli -B./build -DCMAKE_BUILD_TYPE:STRING=Release \
-G Ninja $ACTIVE_MODULES
cmake --build ./build --config Release --parallel
- name: "Install bundle"
run: |
set -eux
mkdir daslang_bundle
cmake --install ./build --prefix ./daslang_bundle --config Release --strip
- name: "Smoke-test installed bundle"
run: bash ci/smoke_test_bundle.sh ./daslang_bundle
###########################################################
build_windows_mingw:
###########################################################
# Catches clang-mingw64 toolchain regressions at PR time. The mingw path
# diverges from MSVC in src/hal/debug_break.cpp, src/hal/project_specific_crash_handler.cpp,
# and src/builtin/module_jit.cpp (PR #2838). Without this job, a Windows-touching
# change that compiles under MSVC but breaks mingw would only surface when a
# maintainer rebuilds locally. Same runner pool as the MSVC matrix
# (windows-latest-fat), separate top-level job so mingw churn doesn't risk
# the much-larger MSVC entries.
#
# dasClangBind is enabled here — find_package(Clang 22.1) matches msys2's
# libclang 22.1.x and POST_BUILD copies the libclang+libLLVM+libc++ chain
# next to daslang.exe so the .shared_module dlopen resolves at runtime.
###########################################################
needs: pre_job
if: needs.pre_job.outputs.should_skip != 'true'
runs-on: windows-latest-fat
defaults:
run:
shell: msys2 {0}
steps:
- name: "SCM Checkout"
uses: actions/checkout@v4
- name: "Install MSYS2 + clang-mingw64 toolchain"
uses: msys2/setup-msys2@v2
with:
msystem: CLANG64
update: true
cache: true
install: >-
mingw-w64-clang-x86_64-toolchain
mingw-w64-clang-x86_64-cmake
mingw-w64-clang-x86_64-ninja
mingw-w64-clang-x86_64-openssl
mingw-w64-clang-x86_64-glfw
bison
git
- name: "Build: Daslang (clang-mingw64)"
run: |
set -eux
mkdir -p build-mingw
cmake --no-warn-unused-cli -B./build-mingw -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_C_COMPILER=clang \
-DCMAKE_CXX_COMPILER=clang++ \
-DDAS_CLANG_BIND_DISABLED=OFF \
-DDAS_LLVM_DISABLED=OFF
cmake --build ./build-mingw --parallel
- name: "Test: interpreter sweep"
run: |
set -eux
cd bin
./daslang _dasroot_/dastest/dastest.das -- --color --failures-only --timeout 900 --test _dasroot_/tests \
|| ./daslang _dasroot_/dastest/dastest.das -- --color --failures-only --isolated-mode --timeout 3600 --test _dasroot_/tests
- name: "Test: JIT sweep"
run: |
set -eux
cd bin
./daslang _dasroot_/dastest/dastest.das -jit -- --color --failures-only --timeout 900 --test _dasroot_/tests \
|| ./daslang _dasroot_/dastest/dastest.das -jit -- --color --failures-only --isolated-mode --timeout 3600 --test _dasroot_/tests
- name: "Small C++ Tests"
run: |
set -eux
cd build-mingw
ctest -L small --output-on-failure
- name: "Slow Release Tests (AOT)"
run: |
set -eux
cd bin
./test_aot -use-aot _dasroot_/dastest/dastest.das -- --use-aot --color --failures-only --timeout 900 --test _dasroot_/tests
# bind_clangbind self-binder lives here (not on linux extended_checks)
# because dasClangBind on linux pulls libclang.so → libLLVM-22.so.1,
# which collides with dasLLVM in the same process (shared pass
# registry, double-init breaks JIT). msys2 clang64 ships libclang as
# a separate SO chain, and the mingw worker doesn't exercise JIT-uses-
# dasClangBind paths, so they coexist cleanly.
#
# TODO: bind_llvm.das self-binder doesn't run on mingw — libclang as
# library doesn't find <cstddef> via msys2's libcxx auto-detection.
# Needs explicit -resource-dir / -isystem injection. Tracked as a
# follow-up; we lose master's previous bind_llvm.das CI coverage in
# the meantime.
- name: "Run self-binder (bind_clangbind.das)"
run: |
set -eux
CLANG_INCLUDE="$(cygpath -w "${MSYSTEM_PREFIX}/include")"
./bin/daslang.exe modules/dasClangBind/bind/bind_clangbind.das -- --clang_path "${CLANG_INCLUDE}/"
git diff --exit-code -- modules/dasClangBind/src/ \
|| (echo "ERROR: dasClangBind generated files are out of date. Run './bin/daslang modules/dasClangBind/bind/bind_clangbind.das -- --clang_path <libclang-include-path>' locally and commit the result." && exit 1)
- name: "Run cbind const-gen regression test"
# Exercises collectActiveDefines (preprocessor-active constant generation);
# main returns non-zero on failure. Lives on the mingw worker because that
# is where libclang/cbind is available (same reason as the self-binder).
run: ./bin/daslang.exe modules/dasClangBind/tests/test_const_preproc.das
build_windows_clangcl:
###########################################################
# Catches clang-cl (Visual Studio "ClangCL" toolset) build regressions. clang-cl
# sets CMake's MSVC=TRUE but uses clang's resource headers, and the toolset puts
# that resource include dir on INCLUDE. dasHV builds OpenSSL from source with plain
# cl, which rejects clang's #include_next <stdint.h> (C1021) — modules/dasHV/
# scrub_clang_include.cmake strips the clang dir from INCLUDE so cl falls back to
# MSVC's stdint.h. Without this job that fix — and clang-cl buildability generally —
# could silently rot. Same runner pool as the MSVC matrix; separate top-level job.
###########################################################
needs: pre_job
if: needs.pre_job.outputs.should_skip != 'true'
runs-on: windows-latest-fat
steps:
- name: "SCM Checkout"
uses: actions/checkout@v4
- name: "Exclude workspace from Defender"
shell: pwsh
continue-on-error: true
run: |
Add-MpPreference -ExclusionPath "${{ github.workspace }}"
Add-MpPreference -ExclusionProcess "daslang.exe"
Add-MpPreference -ExclusionProcess "test_aot.exe"
- name: "Install nasm (OpenSSL asm)"
uses: ilammy/setup-nasm@v1
# dasHV builds OpenSSL from source here (the path the scrub fix targets), and
# nmake is serial — ~7 min. Cache the install so only the first run (or a dasHV
# CMakeLists change) pays it; on a hit find_package(OpenSSL) finds it and the
# from-source ExternalProject is skipped. (sccache — the matrix's compiler cache
# — is not usable here: the VS generator, required for the ClangCL toolset, does
# not support CMAKE_CXX_COMPILER_LAUNCHER.)
- name: "Cache OpenSSL (clang-cl from-source build)"
uses: actions/cache@v4
with:
path: |
build-clangcl/openssl/include
build-clangcl/openssl/lib
build-clangcl/openssl/bin
key: openssl-clangcl-${{ runner.os }}-${{ hashFiles('modules/dasHV/CMakeLists.txt') }}
- name: "Build: Daslang (clang-cl / VS ClangCL toolset)"
shell: pwsh
run: |
cmake -B build-clangcl -G "Visual Studio 17 2022" -A x64 -T ClangCL -DCMAKE_BUILD_TYPE=Release
if ($LASTEXITCODE -ne 0) { exit 1 }
cmake --build build-clangcl --config Release --parallel
if ($LASTEXITCODE -ne 0) { exit 1 }
- name: "Test: interpreter sweep"
shell: pwsh
run: |
bin\Release\daslang.exe dastest\dastest.das -- --color --failures-only --timeout 900 --test tests
if ($LASTEXITCODE -ne 0) { exit 1 }
- name: "Test: AOT sweep"
shell: pwsh
run: |
cmake --build build-clangcl --config Release --target test_aot --parallel
if ($LASTEXITCODE -ne 0) { exit 1 }
bin\Release\test_aot.exe -use-aot dastest\dastest.das -- --use-aot --color --failures-only --timeout 900 --test tests
if ($LASTEXITCODE -ne 0) { exit 1 }
- name: "Small C++ tests"
shell: pwsh
run: |
cd build-clangcl
ctest --build-config Release -L small --output-on-failure
if ($LASTEXITCODE -ne 0) { exit 1 }