Skip to content

Revert "Fix memory leak" #402

Revert "Fix memory leak"

Revert "Fix memory leak" #402

name: Multi-platform build
on:
push:
branches: [ "main", "development" ]
pull_request:
branches: [ "main" ]
workflow_dispatch:
jobs:
config:
name: Configure Workflow
runs-on: ubuntu-latest
outputs:
enable_freebsd: ${{ steps.set_vars.outputs.enable_freebsd }}
steps:
- id: set_vars
run: echo "enable_freebsd=true" >> "$GITHUB_OUTPUT"
build:
name: build (${{ matrix.asset_name }})
runs-on: ${{ matrix.runs_on }}
strategy:
fail-fast: false
matrix:
include:
- id: ubuntu-gcc
runs_on: ubuntu-latest
build_type: Release
c_compiler: gcc
cpp_compiler: g++
ocaml_version: "4.14.2"
binary_path: bin/Release/chsl
asset_name: "linux-x64-gcc"
- id: ubuntu-clang
runs_on: ubuntu-latest
build_type: Release
c_compiler: clang
cpp_compiler: clang++
ocaml_version: "4.14.2"
binary_path: bin/Release/chsl
asset_name: "linux-x64-clang"
- id: ubuntu-arm
runs_on: ubuntu-24.04-arm
build_type: Release
c_compiler: gcc
cpp_compiler: g++
ocaml_version: "4.14.2"
binary_path: bin/Release/chsl
asset_name: "linux-arm64"
- id: macos-intel
runs_on: macos-15-intel
build_type: Release
c_compiler: clang
cpp_compiler: clang++
ocaml_version: "4.14.2"
binary_path: bin/Release/chsl
asset_name: "macos-x64"
- id: macos-arm
runs_on: macos-26
build_type: Release
c_compiler: clang
cpp_compiler: clang++
ocaml_version: "4.14.2"
binary_path: bin/Release/chsl
asset_name: "macos-arm64"
- id: windows-x64
runs_on: windows-latest
build_type: Release
c_compiler: cl
cpp_compiler: cl
extra_cmake_args: -DENABLE_MP3PACKER=OFF -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_TARGET_TRIPLET=x64-windows-static
binary_path: bin/Release/chsl.exe
asset_name: "windows-x64"
- id: windows-arm
runs_on: windows-11-arm
build_type: Release
c_compiler: cl
cpp_compiler: cl
extra_cmake_args: -DENABLE_MP3PACKER=OFF -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_TARGET_TRIPLET=arm64-windows-static
binary_path: bin/Release/chsl.exe
asset_name: "windows-arm64"
steps:
- name: Disable Git AutoCRLF
if: runner.os == 'Windows' && (!contains(matrix.extra_cmake_args, 'ENABLE_MP3PACKER=OFF'))
run: git config --global core.autocrlf false
- name: Checkout repository
uses: actions/checkout@v6
with:
submodules: recursive
fetch-depth: 0
lfs: true
- name: Setup Git LFS
run: |
git lfs install
git lfs pull
- name: Set up OCaml
if: (!contains(matrix.extra_cmake_args, 'ENABLE_MP3PACKER=OFF'))
uses: ocaml/setup-ocaml@v3
with:
ocaml-compiler: ${{ matrix.ocaml_version }}
dune-cache: true
- name: Install OCaml Dependencies
if: (!contains(matrix.extra_cmake_args, 'ENABLE_MP3PACKER=OFF'))
run: |
opam install dune dune-configurator --yes
opam exec -- ocamlopt -version
- name: Install build dependencies (Linux)
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y build-essential cmake ninja-build pkg-config \
autoconf automake libtool m4 nasm yasm curl unzip tar gzip python3-pip
- name: Install build dependencies (macOS)
if: runner.os == 'macOS'
run: |
brew update
brew remove --force $(brew list --formula)
brew remove --cask --force $(brew list)
brew install autoconf automake libtool nasm yasm cmake ninja
- name: Setup MSVC Developer Environment
if: runner.os == 'Windows'
uses: TheMrMilchmann/setup-msvc-dev@v4
with:
arch: ${{ matrix.id == 'windows-arm' && 'arm64' || 'x64' }}
- name: Install build dependencies (Windows)
if: runner.os == 'Windows'
run: choco install ninja
- name: Set up Rust
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
- name: Set build output directory
id: strings
shell: bash
run: echo "build-output-dir=${{ github.workspace }}/build" >> "$GITHUB_OUTPUT"
- name: Configure CMake
run: >
cmake -B ${{ steps.strings.outputs.build-output-dir }}
-DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
-DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }}
-DCMAKE_C_COMPILER=${{ matrix.c_compiler }}
${{ matrix.extra_cmake_args }}
-S ${{ github.workspace }}
- name: Build
run: cmake --build ${{ steps.strings.outputs.build-output-dir }} --config ${{ matrix.build_type }}
- name: Determine Version
shell: bash
run: |
if [[ $GITHUB_REF == refs/tags/v* ]]; then
echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
else
echo "VERSION=dev" >> $GITHUB_ENV
fi
- name: Rename Binary
shell: bash
run: |
EXT=""
SRC="${{ matrix.binary_path }}"
if [[ "${{ runner.os }}" == "Windows" ]]; then
EXT=".exe"
if [[ "$SRC" != *".exe" ]]; then SRC="$SRC.exe"; fi
fi
DEST="chsl-${{ matrix.asset_name }}-${{ env.VERSION }}$EXT"
echo "Renaming $SRC to $DEST"
mv "$SRC" "$DEST"
echo "ARTIFACT_PATH=$DEST" >> $GITHUB_ENV
- name: Upload binary artifact
uses: actions/upload-artifact@v7
with:
name: binary-${{ matrix.asset_name }}
path: ${{ env.ARTIFACT_PATH }}
if-no-files-found: error
build-freebsd-x64:
name: build (freebsd-x64)
needs: config
if: needs.config.outputs.enable_freebsd == 'true'
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
submodules: recursive
fetch-depth: 0
lfs: true
- name: Setup Git LFS
run: |
git lfs install
git lfs pull
- name: Build on FreeBSD
uses: vmactions/freebsd-vm@v1
with:
arch: amd64
release: "15.0"
usesh: true
prepare: |
pkg install -y cmake ninja pkgconf autoconf automake libtool m4 nasm yasm gmake git llvm20 rust
run: |
echo "--- Starting FreeBSD Build ---"
export MAKE=gmake
mkdir -p $HOME/bin
ln -s /usr/local/bin/gmake $HOME/bin/make
export PATH=$HOME/bin:$PATH
# disable mp3packer as ocaml is not installed
cmake -G Ninja -DCMAKE_CXX_STANDARD=20 \
-DCMAKE_C_COMPILER=/usr/local/bin/clang20 \
-DCMAKE_CXX_COMPILER=/usr/local/bin/clang++20 \
-DCMAKE_CXX_FLAGS="-stdlib=libc++ -fexperimental-library" \
-DCMAKE_EXE_LINKER_FLAGS="-stdlib=libc++ -fexperimental-library" \
-DENABLE_MP3PACKER=OFF \
-B build -DCMAKE_BUILD_TYPE=Release -S ${{ github.workspace }}
cmake --build build --config Release
echo "--- Build Complete ---"
- name: Determine Version
shell: bash
run: |
if [[ $GITHUB_REF == refs/tags/v* ]]; then
echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
else
echo "VERSION=dev" >> $GITHUB_ENV
fi
- name: Rename Binary
shell: bash
run: |
SRC="bin/Release/chsl"
DEST="chsl-freebsd-x64-${{ env.VERSION }}"
echo "Renaming $SRC to $DEST"
mv "$SRC" "$DEST"
echo "ARTIFACT_PATH=$DEST" >> $GITHUB_ENV
- name: Upload binary artifact
uses: actions/upload-artifact@v7
with:
name: binary-freebsd-x64
path: ${{ env.ARTIFACT_PATH }}
if-no-files-found: error
build-freebsd-arm64:
name: build (freebsd-arm64)
needs: config
if: needs.config.outputs.enable_freebsd == 'true'
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
submodules: recursive
fetch-depth: 0
lfs: true
- name: Setup Git LFS
run: |
git lfs install
git lfs pull
- name: Build on FreeBSD
uses: vmactions/freebsd-vm@v1
with:
arch: arm64
release: "15.0"
usesh: true
prepare: |
pkg install -y cmake ninja pkgconf autoconf automake libtool m4 nasm yasm gmake git llvm20 rust
run: |
echo "--- Starting FreeBSD Build ---"
export MAKE=gmake
mkdir -p $HOME/bin
ln -s /usr/local/bin/gmake $HOME/bin/make
export PATH=$HOME/bin:$PATH
# disable mp3packer as ocaml is not installed
cmake -G Ninja -DCMAKE_CXX_STANDARD=20 \
-DCMAKE_C_COMPILER=/usr/local/bin/clang20 \
-DCMAKE_CXX_COMPILER=/usr/local/bin/clang++20 \
-DCMAKE_CXX_FLAGS="-stdlib=libc++ -fexperimental-library" \
-DCMAKE_EXE_LINKER_FLAGS="-stdlib=libc++ -fexperimental-library" \
-DENABLE_MP3PACKER=OFF \
-B build -DCMAKE_BUILD_TYPE=Release -S ${{ github.workspace }}
cmake --build build --config Release
echo "--- Build Complete ---"
- name: Determine Version
shell: bash
run: |
if [[ $GITHUB_REF == refs/tags/v* ]]; then
echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
else
echo "VERSION=dev" >> $GITHUB_ENV
fi
- name: Rename Binary
shell: bash
run: |
SRC="bin/Release/chsl"
DEST="chsl-freebsd-arm64-${{ env.VERSION }}"
echo "Renaming $SRC to $DEST"
mv "$SRC" "$DEST"
echo "ARTIFACT_PATH=$DEST" >> $GITHUB_ENV
- name: Upload binary artifact
uses: actions/upload-artifact@v7
with:
name: binary-freebsd-arm64
path: ${{ env.ARTIFACT_PATH }}
if-no-files-found: error
test:
name: test (${{ matrix.asset_name }})
needs: build
runs-on: ${{ matrix.runs_on }}
strategy:
fail-fast: false
matrix:
include:
- id: ubuntu-gcc
runs_on: ubuntu-latest
asset_name: "linux-x64-gcc"
- id: ubuntu-clang
runs_on: ubuntu-latest
asset_name: "linux-x64-clang"
- id: ubuntu-arm
runs_on: ubuntu-24.04-arm
asset_name: "linux-arm64"
- id: macos-intel
runs_on: macos-15-intel
asset_name: "macos-x64"
- id: macos-arm
runs_on: macos-26
asset_name: "macos-arm64"
- id: windows-x64
runs_on: windows-latest
asset_name: "windows-x64"
# disabled, takes longer than 6 hours
#- id: windows-arm
# runs_on: windows-11-arm
# asset_name: "windows-arm64"
env:
TEST_ARCHIVE_NAME: chisel_samples.zip
TEST_DIR: test-data
BIN_DIR: bin
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Download binary artifact
uses: actions/download-artifact@v8
with:
name: binary-${{ matrix.asset_name }}
path: ${{ env.BIN_DIR }}
- name: Restore Binary Name
shell: bash
run: |
cd ${{ env.BIN_DIR }}
find . -maxdepth 1 -type f -name "chsl-*" ! -name "chsl" ! -name "chsl.exe" -exec mv {} chsl \; || true
if [[ "${{ runner.os }}" == "Windows" ]] && [ -f "chsl" ]; then
mv chsl chsl.exe
fi
ls -la
- name: Make binary executable
if: runner.os != 'Windows'
run: chmod +x ${{ env.BIN_DIR }}/chsl
shell: bash
- name: Install test dependencies (Linux)
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y python3-pip unzip
pip3 install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib
- name: Install test dependencies (macOS)
if: runner.os == 'macOS'
run: |
brew install unzip
python3 -m venv ${{ github.workspace }}/venv-gdrive
${{ github.workspace }}/venv-gdrive/bin/pip3 install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib
- name: Install test dependencies (Windows)
if: runner.os == 'Windows'
run: |
python -m pip install --upgrade pip
python -m pip install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib
shell: bash
- name: Cache test data archive
id: cache-test-archive
uses: actions/cache@v5
with:
path: ${{ env.TEST_ARCHIVE_NAME }}
key: ${{ runner.os }}-testarchive-v1-${{ secrets.GDRIVE_FILE_ID }}
- name: Authenticate and Download Test Data from Google Drive
if: steps.cache-test-archive.outputs.cache-hit != 'true'
env:
GDRIVE_CREDENTIALS_JSON: ${{ secrets.GDRIVE_CREDENTIALS_JSON }}
GDRIVE_FILE_ID: ${{ secrets.GDRIVE_FILE_ID }}
run: |
PY_EXE="python3"
if [[ "$RUNNER_OS" == "Windows" ]]; then
PY_EXE="python"
elif [[ "$RUNNER_OS" == "macOS" ]]; then
# Point to the python inside the venv
PY_EXE="${{ github.workspace }}/venv-gdrive/bin/python3"
fi
"$PY_EXE" -c "
import os
import io
import json
import sys
from google.oauth2 import service_account
from googleapiclient.discovery import build
from googleapiclient.http import MediaIoBaseDownload
creds_json_string = os.environ.get('GDRIVE_CREDENTIALS_JSON')
if not creds_json_string:
print('::error::Secret GDRIVE_CREDENTIALS_JSON is not set.', file=sys.stderr)
sys.exit(1)
try:
creds_info = json.loads(creds_json_string)
creds = service_account.Credentials.from_service_account_info(creds_info)
except json.JSONDecodeError:
print('::error::Could not decode credentials JSON. Check the secret.', file=sys.stderr)
sys.exit(1)
except Exception as e:
print(f'::error::Failed to load service account credentials: {e}', file=sys.stderr)
sys.exit(1)
file_id = os.environ.get('GDRIVE_FILE_ID')
output_filename = os.environ.get('TEST_ARCHIVE_NAME')
if not file_id:
print('::error::Secret GDRIVE_FILE_ID is not set.', file=sys.stderr)
sys.exit(1)
if not output_filename:
print('::error::Environment variable TEST_ARCHIVE_NAME is not set.', file=sys.stderr)
sys.exit(1)
print(f'Authenticating and creating Google Drive service...')
try:
service = build('drive', 'v3', credentials=creds)
except Exception as e:
print(f'::error::Failed to build Drive service: {e}', file=sys.stderr)
sys.exit(1)
print(f'Requesting file ID: {file_id}...')
try:
request = service.files().get_media(fileId=file_id)
except Exception as e:
print(f'::error::Failed to create download request for file ID {file_id}: {e}', file=sys.stderr)
sys.exit(1)
try:
print(f'Opening output file: {output_filename}...')
fh = io.FileIO(output_filename, 'wb')
except Exception as e:
print(f'::error::Failed to open output file {output_filename} for writing: {e}', file=sys.stderr)
sys.exit(1)
downloader = MediaIoBaseDownload(fh, request)
done = False
print(f'Starting download -> {output_filename}...')
try:
while done is False:
status, done = downloader.next_chunk()
if status:
print(f'Download {int(status.progress() * 100)}%.')
except Exception as e:
print(f'::error::Download failed: {e}', file=sys.stderr)
# Ensure file handle is closed before attempting removal
if not fh.closed:
fh.close()
# Attempt to remove partially downloaded file
try:
if os.path.exists(output_filename):
os.remove(output_filename)
print(f'Removed partially downloaded file: {output_filename}')
except OSError as oe:
print(f'Warning: Could not remove partial file {output_filename}: {oe}', file=sys.stderr)
sys.exit(1)
finally:
# Ensure file handle is closed even if download finished successfully
if not fh.closed:
fh.close()
print(f'Download complete: {output_filename}.')
"
shell: bash
- name: Extract Test Data
run: |
echo "Extracting test data..."
mkdir ${{ env.TEST_DIR }}
unzip -q ${{ env.TEST_ARCHIVE_NAME }} -d ${{ env.TEST_DIR }}
shell: bash
- name: Run Chisel Tests
run: |
if [[ "$RUNNER_OS" == "Windows" ]]; then
CHISEL_EXE="./${{ env.BIN_DIR }}/chsl.exe"
else
CHISEL_EXE="./${{ env.BIN_DIR }}/chsl"
fi
echo "Running chisel from: $CHISEL_EXE"
echo "Processing files in: ${{ env.TEST_DIR }}"
if [[ "$RUNNER_OS" == "Windows" ]]; then
"$CHISEL_EXE" "${{ env.TEST_DIR }}" --recursive --threads 3 --log-level=ALL --log-file chisel.log --iterations 2 --iterations-large 2
else
"$CHISEL_EXE" "${{ env.TEST_DIR }}" --recursive --threads 4 --log-level=ALL --log-file chisel.log --iterations 2 --iterations-large 2
fi
shell: bash
- name: Check for errors in Chisel Log
if: always()
run: |
LOG_FILE="build/chisel.log"
if [ ! -f "$LOG_FILE" ]; then
if [ -f "${{ github.workspace }}/chisel.log" ]; then
LOG_FILE="${{ github.workspace }}/chisel.log"
elif [ -f "chisel.log" ]; then
LOG_FILE="chisel.log"
else
echo "Log file not found at build/chisel.log, ${{ github.workspace }}/chisel.log, or current directory."
exit 0
fi
fi
echo "Checking log file at: $LOG_FILE"
if grep -q '\[ERROR\]' "$LOG_FILE"; then
echo "::error::Errors detected in chisel.log!"
grep '\[ERROR\]' "$LOG_FILE"
exit 1
else
echo "No [ERROR] lines found in chisel.log."
exit 0
fi
shell: bash
- name: Upload Chisel Log File
if: always()
uses: actions/upload-artifact@v7
with:
name: chisel-log-${{ matrix.id }}
path: |
build/chisel.log
${{ github.workspace }}/chisel.log
chisel.log
if-no-files-found: warn
retention-days: 7
test-freebsd:
name: test (${{ matrix.asset_name }})
if: needs.config.outputs.enable_freebsd == 'true'
needs: [config, build-freebsd-x64]
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- id: freebsd-x64
arch: amd64
asset_name: "freebsd-x64"
# disabled, takes too long
# - id: freebsd-arm
# arch: arm64
# asset_name: "freebsd-arm64"
env:
TEST_ARCHIVE_NAME: chisel_samples.zip
TEST_DIR: test-data
BIN_DIR: bin
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Download binary artifact
uses: actions/download-artifact@v8
with:
name: binary-${{ matrix.asset_name }}
path: ${{ env.BIN_DIR }}
- name: Restore Binary Name
shell: bash
run: |
cd ${{ env.BIN_DIR }}
find . -maxdepth 1 -type f -name "chsl-*" ! -name "chsl" -exec mv {} chsl \; || true
ls -la
- name: Make binary executable (Host)
run: chmod +x ${{ env.BIN_DIR }}/chsl
- name: Install test dependencies (Linux Host for GDrive)
run: |
sudo apt-get update
sudo apt-get install -y python3-pip unzip
pip3 install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib
- name: Cache test data archive
id: cache-test-archive
uses: actions/cache@v5
with:
path: ${{ env.TEST_ARCHIVE_NAME }}
key: ${{ runner.os }}-testarchive-v1-${{ secrets.GDRIVE_FILE_ID }}
- name: Authenticate and Download Test Data from Google Drive
if: steps.cache-test-archive.outputs.cache-hit != 'true'
env:
GDRIVE_CREDENTIALS_JSON: ${{ secrets.GDRIVE_CREDENTIALS_JSON }}
GDRIVE_FILE_ID: ${{ secrets.GDRIVE_FILE_ID }}
run: |
python3 -c "
import os, io, json, sys
from google.oauth2 import service_account
from googleapiclient.discovery import build
from googleapiclient.http import MediaIoBaseDownload
creds_json_string = os.environ.get('GDRIVE_CREDENTIALS_JSON')
if not creds_json_string: sys.exit(1)
try:
creds_info = json.loads(creds_json_string)
creds = service_account.Credentials.from_service_account_info(creds_info)
except: sys.exit(1)
file_id = os.environ.get('GDRIVE_FILE_ID')
output_filename = os.environ.get('TEST_ARCHIVE_NAME')
if not file_id or not output_filename: sys.exit(1)
try: service = build('drive', 'v3', credentials=creds)
except: sys.exit(1)
try: request = service.files().get_media(fileId=file_id)
except: sys.exit(1)
try: fh = io.FileIO(output_filename, 'wb')
except: sys.exit(1)
downloader = MediaIoBaseDownload(fh, request)
done = False
try:
while done is False: status, done = downloader.next_chunk()
except:
if not fh.closed: fh.close()
try:
if os.path.exists(output_filename): os.remove(output_filename)
except: pass
sys.exit(1)
finally:
if not fh.closed: fh.close()
"
shell: bash
- name: Extract Test Data
run: |
echo "Extracting test data..."
mkdir ${{ env.TEST_DIR }}
unzip -q ${{ env.TEST_ARCHIVE_NAME }} -d ${{ env.TEST_DIR }}
shell: bash
- name: Run Chisel Tests (in FreeBSD VM)
uses: vmactions/freebsd-vm@v1
with:
arch: ${{ matrix.arch }}
release: "15.0"
usesh: true
run: |
echo "--- Starting FreeBSD Test ---"
CHISEL_EXE="./${{ env.BIN_DIR }}/chsl"
echo "Running chisel from: $CHISEL_EXE"
echo "Processing files in: ${{ env.TEST_DIR }}"
$CHISEL_EXE "${{ env.TEST_DIR }}" --recursive --threads 4 --log-level=ALL --log-file chisel.log
echo "--- Test Run Complete ---"
- name: Check for errors in Chisel Log
if: always()
run: |
LOG_FILE="chisel.log"
if grep -q '\[ERROR\]' "$LOG_FILE"; then
echo "::error::Errors detected in chisel.log!"
grep '\[ERROR\]' "$LOG_FILE"
exit 1
else
echo "No [ERROR] lines found in chisel.log."
exit 0
fi
shell: bash
- name: Upload Chisel Log File
if: always()
uses: actions/upload-artifact@v7
with:
name: chisel-log-${{ matrix.asset_name }}
path: chisel.log
if-no-files-found: warn
retention-days: 7
combine-logs:
name: combine-logs
needs: [test, test-freebsd]
runs-on: ubuntu-latest
if: always()
steps:
- name: Download all log artifacts
uses: actions/download-artifact@v8
with:
pattern: chisel-log-*
path: logs
- name: Combine logs
run: |
mkdir -p combined
find logs -type f -name "*.log" -exec cat {} + > combined/chisel-combined.log
sort -u combined/chisel-combined.log > combined/chisel-combined-unique.log
- name: Upload combined log
uses: actions/upload-artifact@v7
with:
name: chisel-combined-logs
path: combined/
retention-days: 14
publish_nightly:
name: Publish Nightly Pre-Release
runs-on: ubuntu-latest
needs: [test, test-freebsd]
if: |
always() &&
needs.test.result == 'success' &&
(needs.test-freebsd.result == 'success' || needs.test-freebsd.result == 'skipped') &&
github.ref == 'refs/heads/development'
permissions:
actions: read
contents: write
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Download all build and log artifacts
uses: actions/download-artifact@v8
with:
path: artifacts/
- name: Prepare assets for release
run: |
mkdir release_assets
function package_unix {
SRC_DIR="artifacts/$1"
OUT_NAME="$2"
# skip if freebsd artifact is missing
if [ ! -d "$SRC_DIR" ]; then return; fi
mv "$SRC_DIR"/* "release_assets/chsl"
chmod +x "release_assets/chsl"
tar -czf "release_assets/$OUT_NAME.tar.gz" -C release_assets "chsl"
rm "release_assets/chsl"
}
function package_windows {
SRC_DIR="artifacts/$1"
OUT_NAME="$2"
mv "$SRC_DIR"/*.exe "release_assets/chsl.exe"
zip -j "release_assets/$OUT_NAME.zip" "release_assets/chsl.exe"
rm "release_assets/chsl.exe"
}
# --- FreeBSD ---
package_unix "binary-freebsd-x64" "chsl-freebsd-x64"
package_unix "binary-freebsd-arm64" "chsl-freebsd-arm64"
# --- Linux ---
package_unix "binary-linux-x64-gcc" "chsl-linux-x64-gcc"
package_unix "binary-linux-x64-clang" "chsl-linux-x64-clang"
package_unix "binary-linux-arm64" "chsl-linux-arm64"
# --- macOS ---
package_unix "binary-macos-x64" "chsl-macos-x64"
package_unix "binary-macos-arm64" "chsl-macos-arm64"
# --- Windows ---
package_windows "binary-windows-x64" "chsl-windows-x64"
package_windows "binary-windows-arm64" "chsl-windows-arm64"
# --- Logs ---
find artifacts/ -type f -name '*.log' -exec cp {} release_assets/ \;
- name: Delete and recreate 'development-latest' release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release delete development-latest -y || echo "No previous nightly release to delete."
git push origin --delete development-latest || echo "No previous nightly tag to delete."
gh release create development-latest \
--prerelease \
--title "Nightly Build" \
--notes "Latest successful build from 'development' branch. Not a stable release." \
release_assets/*
publish_stable:
name: Publish Stable Release
runs-on: ubuntu-latest
needs: [test, test-freebsd]
if: |
always() &&
needs.test.result == 'success' &&
(needs.test-freebsd.result == 'success' || needs.test-freebsd.result == 'skipped') &&
startsWith(github.ref, 'refs/tags/v')
permissions:
actions: read
contents: write
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Download all build and log artifacts
uses: actions/download-artifact@v8
with:
path: artifacts/
- name: Prepare assets for release
run: |
mkdir release_assets
function package_unix {
SRC_DIR="artifacts/$1"
OUT_NAME="$2"
# skip if freebsd artifact is missing
if [ ! -d "$SRC_DIR" ]; then return; fi
mv "$SRC_DIR"/* "release_assets/$OUT_NAME"
chmod +x "release_assets/$OUT_NAME"
tar -czf "release_assets/$OUT_NAME.tar.gz" -C release_assets "$OUT_NAME"
rm "release_assets/$OUT_NAME"
}
function package_windows {
SRC_DIR="artifacts/$1"
OUT_NAME="$2"
mv "$SRC_DIR"/*.exe "release_assets/$OUT_NAME.exe"
zip -j "release_assets/$OUT_NAME.zip" "release_assets/$OUT_NAME.exe"
rm "release_assets/$OUT_NAME.exe"
}
# Packaging
package_unix "binary-linux-x64-gcc" "chsl-linux-x64-gcc"
package_unix "binary-linux-x64-clang" "chsl-linux-x64-clang"
package_unix "binary-linux-arm64" "chsl-linux-arm64"
package_unix "binary-macos-x64" "chsl-macos-x64"
package_unix "binary-macos-arm64" "chsl-macos-arm64"
package_unix "binary-freebsd-x64" "chsl-freebsd-x64"
package_unix "binary-freebsd-arm64" "chsl-freebsd-arm64"
package_windows "binary-windows-x64" "chsl-windows-x64"
package_windows "binary-windows-arm64" "chsl-windows-arm64"
# Logs
find artifacts/ -type f -name '*.log' -exec cp {} release_assets/ \;
- name: Create Release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release create ${{ github.ref_name }} \
--title "Chisel ${{ github.ref_name }}" \
--generate-notes \
release_assets/*
verify-static-linking:
name: verify-static-linking (${{ matrix.asset_name }})
needs: build
runs-on: ${{ matrix.runs_on }}
strategy:
fail-fast: false
matrix:
include:
- id: ubuntu-gcc
runs_on: ubuntu-latest
asset_name: "linux-x64-gcc"
- id: ubuntu-clang
runs_on: ubuntu-latest
asset_name: "linux-x64-clang"
- id: ubuntu-arm
runs_on: ubuntu-24.04-arm
asset_name: "linux-arm64"
- id: macos-intel
runs_on: macos-15-intel
asset_name: "macos-x64"
- id: macos-arm
runs_on: macos-15
asset_name: "macos-arm64"
- id: windows-x64
runs_on: windows-latest
asset_name: "windows-x64"
- id: windows-arm
runs_on: windows-11-arm
asset_name: "windows-arm64"
env:
BIN_DIR: bin
FORBIDDEN_LIBS: "jpeg|png|flac|archive|zlib|jxl|tiff|qpdf|webp|wavpack|sqlite|magic|mseed|ebml|matroska|mkclean|zopfli|ape|gif|mac|flexigif|tag"
steps:
- name: Setup MSVC Developer Environment
if: runner.os == 'Windows'
uses: TheMrMilchmann/setup-msvc-dev@v4
with:
arch: ${{ matrix.id == 'windows-arm' && 'arm64' || 'x64' }}
- name: Download binary artifact
uses: actions/download-artifact@v8
with:
name: binary-${{ matrix.asset_name }}
path: ${{ env.BIN_DIR }}
- name: Restore Binary Name
shell: bash
run: |
cd ${{ env.BIN_DIR }}
find . -maxdepth 1 -type f -name "chsl-*" ! -name "chsl" ! -name "chsl.exe" -exec mv {} chsl \; || true
if [[ "${{ runner.os }}" == "Windows" ]] && [ -f "chsl" ]; then
mv chsl chsl.exe
fi
ls -la
- name: Make binary executable
if: runner.os != 'Windows'
run: chmod +x ${{ env.BIN_DIR }}/chsl
- name: Verify Linux (ldd)
if: runner.os == 'Linux'
run: |
echo "Checking dependencies for Linux..."
ldd ${{ env.BIN_DIR }}/chsl
echo "---"
matches=$(ldd ${{ env.BIN_DIR }}/chsl | grep -iE "(${FORBIDDEN_LIBS})" || true)
if [ -n "$matches" ]; then
echo "::error::Found forbidden dynamic libraries!"
echo "$matches"
exit 1
else
echo "OK: No forbidden dynamic libraries found."
fi
- name: Verify macOS (otool)
if: runner.os == 'macOS'
run: |
echo "Checking dependencies for macOS..."
otool -L ${{ env.BIN_DIR }}/chsl
echo "---"
matches=$(otool -L ${{ env.BIN_DIR }}/chsl | grep -iE "(${FORBIDDEN_LIBS})" || true)
if [ -n "$matches" ]; then
echo "::error::Found forbidden dynamic libraries!"
echo "$matches"
exit 1
else
echo "OK: No forbidden dynamic libraries found."
fi
- name: Verify Windows (dumpbin + PowerShell)
if: runner.os == 'Windows'
shell: pwsh
run: |
Write-Output "Checking dependencies for Windows..."
$deps = & dumpbin /dependents "${{ env.BIN_DIR }}\chsl.exe"
$deps | Out-String | Write-Output
Write-Output "---"
$pattern = [regex]"(${env:FORBIDDEN_LIBS})\.dll"
$matches = $deps | Select-String -Pattern $pattern -AllMatches
if ($matches) {
Write-Error "Found forbidden dynamic libraries!"
$matches | ForEach-Object { $_.Matches.Value } | Sort-Object -Unique | ForEach-Object { Write-Output $_ }
exit 1
} else {
Write-Output "OK: No forbidden dynamic libraries found."
}
verify-static-linking-freebsd:
name: verify-static-linking (${{ matrix.asset_name }})
if: needs.config.outputs.enable_freebsd == 'true'
needs: [config, build-freebsd-x64, build-freebsd-arm64]
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- id: freebsd-x64
arch: amd64
asset_name: "freebsd-x64"
- id: freebsd-arm
arch: arm64
asset_name: "freebsd-arm64"
env:
BIN_DIR: bin
FORBIDDEN_LIBS: "jpeg|png|flac|archive|zlib|jxl|tiff|qpdf|webp|wavpack|sqlite|magic|mseed|ebml|matroska|mkclean|zopfli|ape|gif|mac|flexigif|tag"
steps:
- name: Download binary artifact
uses: actions/download-artifact@v8
with:
name: binary-${{ matrix.asset_name }}
path: ${{ env.BIN_DIR }}
- name: Restore Binary Name
shell: bash
run: |
cd ${{ env.BIN_DIR }}
find . -maxdepth 1 -type f -name "chsl-*" ! -name "chsl" -exec mv {} chsl \; || true
- name: Make binary executable (Host)
run: chmod +x ${{ env.BIN_DIR }}/chsl
- name: Verify FreeBSD (ldd)
uses: vmactions/freebsd-vm@v1
with:
arch: ${{ matrix.arch }}
release: "15.0"
usesh: true
run: |
echo "Checking dependencies for FreeBSD..."
ldd ${{ env.BIN_DIR }}/chsl
echo "---"
matches=$(ldd ${{ env.BIN_DIR }}/chsl | grep -iE "(${FORBIDDEN_LIBS})" || true)
if [ -n "$matches" ]; then
echo "::error::Found forbidden dynamic libraries!"
echo "$matches"
exit 1
else
echo "OK: No forbidden dynamic libraries found."
fi