Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
335 changes: 245 additions & 90 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,9 @@ jobs:
os: [ubuntu-latest, macos-latest]

steps:
- uses: actions/checkout@v4
with:
# Shallow clone is enough for building. Steps that need history
# (changelog, merge-base) should override with their own fetch.
fetch-depth: 1
- uses: actions/checkout@v4
with:
fetch-depth: 1

# Linux: install toolchain + accelerators
- name: Install dependencies (Linux)
Expand All @@ -50,63 +48,58 @@ jobs:
echo "LLVM_DIR=/usr/lib/llvm-20/lib/cmake/llvm" >> $GITHUB_ENV
echo "Clang_DIR=/usr/lib/llvm-20/lib/cmake/clang" >> $GITHUB_ENV

# macOS: install toolchain
- name: Install dependencies (macOS)
if: runner.os == 'macOS'
run: |
brew install cmake python llvm@20 ninja ccache
echo "LLVM_DIR=$(brew --prefix llvm@20)/lib/cmake/llvm" >> $GITHUB_ENV
echo "Clang_DIR=$(brew --prefix llvm@20)/lib/cmake/clang" >> $GITHUB_ENV
echo "$(brew --prefix llvm@20)/bin" >> $GITHUB_PATH
- name: Install dependencies (macOS)
if: runner.os == 'macOS'
run: |
brew install cmake python llvm@20 ninja ccache
echo "LLVM_DIR=$(brew --prefix llvm@20)/lib/cmake/llvm" >> $GITHUB_ENV
echo "Clang_DIR=$(brew --prefix llvm@20)/lib/cmake/clang" >> $GITHUB_ENV
echo "$(brew --prefix llvm@20)/bin" >> $GITHUB_PATH

# ccache: restore + configure
- name: Restore ccache
uses: actions/cache@v4
with:
path: ${{ env.CCACHE_DIR }}
key: ccache-${{ runner.os }}-${{ github.ref_name }}-${{ hashFiles('CMakeLists.txt', 'src/**', 'include/**') }}
restore-keys: |
ccache-${{ runner.os }}-${{ github.ref_name }}-
ccache-${{ runner.os }}-
- name: Restore ccache
uses: actions/cache@v4
with:
path: ${{ env.CCACHE_DIR }}
key: ccache-${{ runner.os }}-${{ github.ref_name }}-${{ hashFiles('CMakeLists.txt', 'src/**', 'include/**') }}
restore-keys: |
ccache-${{ runner.os }}-${{ github.ref_name }}-
ccache-${{ runner.os }}-

- name: Configure ccache
run: |
ccache --set-config=cache_dir=${{ env.CCACHE_DIR }}
ccache --set-config=max_size=500M
ccache --set-config=compression=true
ccache -z
- name: Configure ccache
run: |
ccache --set-config=cache_dir=${{ env.CCACHE_DIR }}
ccache --set-config=max_size=500M
ccache --set-config=compression=true
ccache -z

# FetchContent cache (sources only)
- name: Restore FetchContent sources
uses: actions/cache@v4
with:
path: |
build/_deps/cc-src
build/_deps/coretrace-logger-src
key: fetchcontent-${{ runner.os }}-llvm20-${{ hashFiles('CMakeLists.txt', 'cmake/**') }}
restore-keys: |
fetchcontent-${{ runner.os }}-llvm20-
- name: Restore FetchContent sources
uses: actions/cache@v4
with:
path: |
build/_deps/cc-src
build/_deps/coretrace-logger-src
key: fetchcontent-${{ runner.os }}-llvm20-${{ hashFiles('CMakeLists.txt', 'cmake/**') }}
restore-keys: |
fetchcontent-${{ runner.os }}-llvm20-

# Configure
- name: Configure
run: |
cmake -S . -B build -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DLLVM_DIR=${{ env.LLVM_DIR }} \
-DClang_DIR=${{ env.Clang_DIR }} \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DUSE_SHARED_LIB=OFF \
-DBUILD_TESTS=OFF \
${{ runner.os == 'Linux' && '-DCMAKE_EXE_LINKER_FLAGS=-fuse-ld=lld -DCMAKE_SHARED_LINKER_FLAGS=-fuse-ld=lld' || '' }}

# Build
- name: Build
run: cmake --build build --config Release

- name: Show ccache stats
if: always()
run: ccache -s
- name: Configure
run: |
cmake -S . -B build -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DLLVM_DIR=${{ env.LLVM_DIR }} \
-DClang_DIR=${{ env.Clang_DIR }} \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DUSE_SHARED_LIB=OFF \
-DBUILD_TESTS=OFF \
${{ runner.os == 'Linux' && '-DCMAKE_EXE_LINKER_FLAGS=-fuse-ld=lld -DCMAKE_SHARED_LINKER_FLAGS=-fuse-ld=lld' || '' }}

- name: Build
run: cmake --build build --config Release

- name: Show ccache stats
if: always()
run: ccache -s

# Tests
- name: Restore run_test cache
Expand Down Expand Up @@ -134,37 +127,199 @@ jobs:
CORETRACE_RUN_TEST_EXTRA_ANALYZER_ARGS="${EXTRA_ANALYZER_ARGS}" \
python3 -u run_test.py --jobs="${TEST_JOBS}"

# Self-analysis (Linux only)
- name: Restore resource summary cache
if: runner.os == 'Linux'
uses: actions/cache@v4
with:
path: .cache/resource-lifetime
key: resource-cache-${{ runner.os }}-${{ hashFiles('models/resource-lifetime/**') }}
restore-keys: |
resource-cache-${{ runner.os }}-

# Resource summary cache — stale entries are harmless (cache key includes
# schema + model + IR hash, so mismatches simply trigger a rebuild).
- name: Restore resource summary cache
if: runner.os == 'Linux'
uses: actions/cache@v4
with:
path: .cache/resource-lifetime
key: resource-cache-${{ runner.os }}-${{ hashFiles('models/resource-lifetime/**') }}
restore-keys: |
resource-cache-${{ runner.os }}-
- name: Self-analysis (analyze own source code)
if: runner.os == 'Linux'
run: |
mkdir -p artifacts
python3 scripts/ci/run_code_analysis.py \
--analyzer build/stack_usage_analyzer \
--compdb build/compile_commands.json \
--exclude build/_deps/ \
--base-dir ${{ github.workspace }} \
--sarif-out artifacts/self-analysis.sarif \
--json-out artifacts/self-analysis.json \
--fail-on error \
--analyzer-arg=--analysis-profile=fast \
--analyzer-arg=--resource-model=models/resource-lifetime/generic.txt

- name: Self-analysis (analyze own source code)
if: runner.os == 'Linux'
run: |
mkdir -p artifacts
python3 scripts/ci/run_code_analysis.py \
--analyzer build/stack_usage_analyzer \
--compdb build/compile_commands.json \
--exclude build/_deps/ \
--base-dir ${{ github.workspace }} \
--sarif-out artifacts/self-analysis.sarif \
--json-out artifacts/self-analysis.json \
--fail-on error \
--analyzer-arg=--analysis-profile=fast \
--analyzer-arg=--resource-model=models/resource-lifetime/generic.txt

- name: Upload SARIF to Code Scanning
if: runner.os == 'Linux' && always() && hashFiles('artifacts/self-analysis.sarif') != ''
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: artifacts/self-analysis.sarif
category: coretrace-self-analysis
- name: Upload SARIF to Code Scanning
if: runner.os == 'Linux' && always() && hashFiles('artifacts/self-analysis.sarif') != ''
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: artifacts/self-analysis.sarif
category: coretrace-self-analysis

build-windows:
name: Build on Windows (pinned LLVM 20.1.0)
runs-on: windows-2022
timeout-minutes: 45
permissions:
contents: read

steps:
- uses: actions/checkout@v4
with:
fetch-depth: 1

- name: Resolve dependency ref
shell: pwsh
run: |
$ErrorActionPreference = "Stop"
$ref = if ($env:GITHUB_HEAD_REF) { $env:GITHUB_HEAD_REF } else { $env:GITHUB_REF_NAME }
"DEPENDENCY_REF=$ref" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append

- name: Checkout coretrace-compiler matching ref
uses: actions/checkout@v4
with:
repository: CoreTrace/coretrace-compiler
ref: ${{ env.DEPENDENCY_REF }}
path: deps/coretrace-compiler
fetch-depth: 1

- name: Checkout coretrace-log matching ref
uses: actions/checkout@v4
with:
repository: CoreTrace/coretrace-log
ref: ${{ env.DEPENDENCY_REF }}
path: deps/coretrace-log
fetch-depth: 1

- name: Install LLVM 20.1.0 archive with 7-Zip
shell: pwsh
run: |
$ErrorActionPreference = "Stop"

$llvmVersion = "20.1.0"
$archiveName = "clang+llvm-$llvmVersion-x86_64-pc-windows-msvc.tar.xz"
$archiveUrl = "https://github.com/llvm/llvm-project/releases/download/llvmorg-$llvmVersion/$archiveName"
$archivePath = Join-Path $env:RUNNER_TEMP $archiveName
$extractRoot = Join-Path $env:RUNNER_TEMP "llvm-extract"
$installRoot = "C:\Program Files\LLVM-$llvmVersion"
$sevenZip = "${env:ProgramFiles}\7-Zip\7z.exe"
$tarPath = Join-Path $env:RUNNER_TEMP "clang+llvm-$llvmVersion-x86_64-pc-windows-msvc.tar"

if (-not (Test-Path $sevenZip)) {
throw "7z.exe not found at $sevenZip"
}

Write-Host "Downloading LLVM archive from $archiveUrl"
Invoke-WebRequest -Uri $archiveUrl -OutFile $archivePath
Write-Host "Download finished"
Get-Item $archivePath | Select-Object FullName, Length | Format-Table -AutoSize

if (Test-Path $extractRoot) {
Remove-Item -Recurse -Force $extractRoot
}
New-Item -ItemType Directory -Force -Path $extractRoot | Out-Null

if (Test-Path $tarPath) {
Remove-Item -Force $tarPath
}

Write-Host "Extracting .xz to .tar with 7-Zip"
& $sevenZip x $archivePath "-o$env:RUNNER_TEMP" -y
if ($LASTEXITCODE -ne 0) {
throw "7-Zip failed while extracting .xz archive"
}

if (-not (Test-Path $tarPath)) {
throw "Expected tar file not found after xz extraction: $tarPath"
}

Write-Host "Extracting .tar to $extractRoot"
& $sevenZip x $tarPath "-o$extractRoot" -y
if ($LASTEXITCODE -ne 0) {
throw "7-Zip failed while extracting .tar archive"
}

Write-Host "Listing extracted directories"
Get-ChildItem $extractRoot -Directory | Select-Object Name, FullName | Format-Table -AutoSize

$extractedDir = Get-ChildItem $extractRoot -Directory | Select-Object -First 1
if (-not $extractedDir) {
throw "Failed to find extracted LLVM directory under $extractRoot"
}

if (Test-Path $installRoot) {
Remove-Item -Recurse -Force $installRoot
}
Move-Item -Path $extractedDir.FullName -Destination $installRoot

$clangClPath = Join-Path $installRoot "bin\clang-cl.exe"
$llvmCmakeDir = Join-Path $installRoot "lib\cmake\llvm"
$clangCmakeDir = Join-Path $installRoot "lib\cmake\clang"
$llvmConfigPath = Join-Path $llvmCmakeDir "LLVMConfig.cmake"
$clangConfigPath = Join-Path $clangCmakeDir "ClangConfig.cmake"

Write-Host "Checking extracted LLVM files"
Write-Host "clang-cl path: $clangClPath"
Write-Host "LLVMConfig path: $llvmConfigPath"
Write-Host "ClangConfig path: $clangConfigPath"

if (-not (Test-Path $clangClPath)) {
throw "clang-cl.exe not found after LLVM archive extraction: $clangClPath"
}
if (-not (Test-Path $llvmConfigPath)) {
throw "LLVMConfig.cmake not found after LLVM archive extraction: $llvmConfigPath"
}
if (-not (Test-Path $clangConfigPath)) {
throw "ClangConfig.cmake not found after LLVM archive extraction: $clangConfigPath"
}

$clangVersion = (& $clangClPath --version) -join " "
if ($clangVersion -notmatch "clang version 20\.1\.0") {
throw "Unexpected clang-cl version. Got: $clangVersion"
}

"LLVM_CMAKE_DIR=$llvmCmakeDir" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
"LLVM_DIR=$llvmCmakeDir" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
"Clang_DIR=$clangCmakeDir" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append

- name: Configure + Build + Install
shell: pwsh
run: |
$ErrorActionPreference = "Stop"
powershell -ExecutionPolicy Bypass -File .\scripts\build-windows.ps1 `
-LLVMDir "${env:LLVM_CMAKE_DIR}" `
-CompilerSourceDir "${PWD}\deps\coretrace-compiler" `
-LoggerSourceDir "${PWD}\deps\coretrace-log" `
-Configuration Release

- name: Smoke test
shell: pwsh
run: |
$ErrorActionPreference = "Stop"

$helpLines = & .\dist\windows\bin\stack_usage_analyzer.exe --help 2>&1
$helpLines | Select-Object -First 20

$help = $helpLines -join "`n"
if ($help -notmatch "usage|Usage|--help") {
throw "help output invalid"
}

$analysisLines = & .\dist\windows\bin\stack_usage_analyzer.exe test\false-positif\unique_ptr_state.cpp --warnings-only 2>&1
$analysisLines | Select-Object -First 20

$analysis = $analysisLines -join "`n"
if ($analysis -notmatch "Diagnostics summary:") {
throw "analysis output missing summary"
}

- name: Run Windows regression suite
shell: pwsh
run: |
$ErrorActionPreference = "Stop"
$env:PYTHONUTF8 = "1"
$env:CORETRACE_RUN_TEST_ANALYZER = (Resolve-Path .\dist\windows\bin\stack_usage_analyzer.exe).Path
$jobs = [Math]::Max(1, [Math]::Min(6, [Environment]::ProcessorCount))
python -u run_test.py --jobs=$jobs
Loading
Loading