Skip to content

fix(wasm): arm epoch deadline before instantiation #884

fix(wasm): arm epoch deadline before instantiation

fix(wasm): arm epoch deadline before instantiation #884

Workflow file for this run

# Copyright 2025 The PECOS Developers
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
# specific language governing permissions and limitations under the License.
name: Julia Artifacts
permissions:
contents: read
env:
TRIGGER_ON_PR_PUSH: true # Set to true to enable triggers on PR pushes
LLVM_VERSION: "21.1"
LLVM_RELEASE_VERSION: "21.1.8"
CARGO_HTTP_MULTIPLEXING: "false"
CARGO_NET_GIT_FETCH_WITH_CLI: "true"
CARGO_NET_RETRY: "10"
on:
push:
branches:
- main
- dev
- development
- master
tags:
- 'jl-*' # Trigger on Julia-specific tags
paths:
- 'julia/**'
- 'crates/**'
- 'Cargo.toml'
- 'Cargo.lock'
- 'scripts/ci/**'
- '.github/workflows/julia-release.yml'
pull_request:
branches:
- main
- dev
- development
- master
paths:
- 'julia/**'
- 'crates/**'
- 'Cargo.toml'
- 'Cargo.lock'
- 'scripts/ci/**'
- '.github/workflows/julia-release.yml'
workflow_dispatch:
inputs:
sha:
description: Commit SHA
type: string
dry_run:
description: 'Dry run (build but not publish)'
type: boolean
default: true
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
defaults:
run:
shell: bash
jobs:
check_pr_push:
runs-on: ubuntu-latest
if: |
github.event_name == 'pull_request' && github.event.action != 'closed' ||
github.event_name == 'push' && contains(fromJSON('["main", "master", "dev", "development"]'), github.ref_name) ||
github.event_name == 'push' && startsWith(github.ref, 'refs/tags/jl-')
outputs:
run: ${{ steps.check.outputs.run }}
steps:
- name: Harden the runner (egress audit)
uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4
with:
egress-policy: audit
- name: Check if should run on PR push
id: check
env:
EVENT_NAME: ${{ github.event_name }}
REF: ${{ github.ref }}
REF_NAME: ${{ github.ref_name }}
TRIGGER_ON_PR_PUSH_VALUE: ${{ env.TRIGGER_ON_PR_PUSH }}
run: |
# Always run on tag pushes (jl-* tags trigger releases)
if [ "$EVENT_NAME" = "push" ] && [[ "$REF" == refs/tags/jl-* ]]; then
echo "run=true" >> $GITHUB_OUTPUT
# Always run on pushes to main branches
elif [ "$EVENT_NAME" = "push" ] && [[ "$REF_NAME" =~ ^(main|master|dev|development)$ ]]; then
echo "run=true" >> $GITHUB_OUTPUT
# For PRs, check the TRIGGER_ON_PR_PUSH setting
elif [ "$EVENT_NAME" = "pull_request" ] && [ "$TRIGGER_ON_PR_PUSH_VALUE" = "true" ]; then
echo "run=true" >> $GITHUB_OUTPUT
else
echo "run=false" >> $GITHUB_OUTPUT
fi
build_julia_binaries:
needs: check_pr_push
if: needs.check_pr_push.result == 'success' && needs.check_pr_push.outputs.run == 'true'
runs-on: ${{ matrix.runner || matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
architecture: x86_64
- os: ubuntu-latest
architecture: aarch64
runner: ubuntu-latest
- os: macos-15-intel
architecture: x86_64
runner: macos-15-intel # Intel Mac for x86_64
- os: macos-latest
architecture: aarch64
runner: macos-latest # ARM64 Mac
- os: windows-2022
architecture: x86_64
steps:
- name: Harden the runner (egress audit)
if: runner.os == 'Linux'
uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4
with:
egress-policy: audit
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
persist-credentials: false
ref: ${{ inputs.sha || github.sha }}
- name: Set up Rust
run: rustup show
- name: Install LLVM 21.1 (Unix)
if: runner.os != 'Windows'
run: |
if [ "$RUNNER_OS" = "macOS" ]; then
echo "Installing LLVM 21 with Homebrew..."
HOMEBREW_NO_AUTO_UPDATE=1 brew install llvm@21
LLVM_PREFIX="$(brew --prefix llvm@21)"
else
echo "Installing LLVM 21.1 using PECOS-managed packages..."
cargo run --locked -p pecos-cli --release -- llvm ensure --managed --no-configure || bash scripts/ci/install-llvm-21-conda-linux.sh
LLVM_PREFIX="$HOME/.pecos/deps/llvm-21.1"
fi
echo "Setting LLVM environment variables..."
cargo run --locked -p pecos-cli --release -- llvm configure "$LLVM_PREFIX"
export PECOS_LLVM="$LLVM_PREFIX"
export LLVM_SYS_211_PREFIX="$LLVM_PREFIX"
echo "PECOS_LLVM=$PECOS_LLVM" >> $GITHUB_ENV
echo "LLVM_SYS_211_PREFIX=$LLVM_SYS_211_PREFIX" >> $GITHUB_ENV
echo "Verifying LLVM installation..."
cargo run --locked -p pecos-cli --release -- llvm check
- name: Install LLVM 21.1 (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
$llvmRoot = Join-Path $env:USERPROFILE ".pecos\deps\llvm-21.1"
$llvmPrefix = Join-Path $llvmRoot "Library"
Write-Host "Installing conda-forge LLVM 21.1..."
./scripts/ci/install-llvm-21-windows.ps1 -InstallDir $llvmRoot -Version ${{ env.LLVM_RELEASE_VERSION }}
Write-Host "Setting LLVM environment variables..."
$env:PECOS_LLVM = $llvmPrefix
$env:LLVM_SYS_211_PREFIX = $env:PECOS_LLVM
$env:LIBCLANG_PATH = Join-Path $llvmPrefix "bin"
cargo run --locked -p pecos-cli --release -- llvm configure "$env:PECOS_LLVM"
"PECOS_LLVM=$env:PECOS_LLVM" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
"LLVM_SYS_211_PREFIX=$env:LLVM_SYS_211_PREFIX" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
"LIBCLANG_PATH=$env:LIBCLANG_PATH" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
Write-Host "Verifying LLVM installation..."
cargo run --locked -p pecos-cli --release -- llvm check
- name: Install Rust target
run: |
# With native ARM64 runners, no cross-compilation setup is needed
# All builds are now native for their respective architectures
echo "Using native build for ${{ matrix.architecture }} on ${{ matrix.os }}"
- name: Set up Visual Studio environment on Windows
if: runner.os == 'Windows'
shell: pwsh
run: ./scripts/ci/setup-msvc.ps1 -Arch x64 -HostArch x64
- name: Build library (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
cd julia/pecos-julia-ffi
cargo build --locked --release
# Create artifact directory
New-Item -ItemType Directory -Force -Path ..\..\artifacts
# Copy the built library
Copy-Item ..\..\target\release\pecos_julia.dll -Destination ..\..\artifacts\
# List artifacts
Get-ChildItem ..\..\artifacts\
- name: Build library (Unix)
if: runner.os != 'Windows'
shell: bash
run: |
cd julia/pecos-julia-ffi
# Set up build flags for macOS to avoid LLVM dependency issues
if [[ "${{ matrix.os }}" == macos-* ]]; then
# Prevent linking against LLVM's libunwind
export RUSTFLAGS="-C link-arg=-Wl,-dead_strip_dylibs -C link-arg=-Wl,-ld_classic"
# Remove LLVM from library paths during build
unset DYLD_LIBRARY_PATH
unset DYLD_FALLBACK_LIBRARY_PATH
# Explicitly exclude LLVM libraries from linking
export RUSTFLAGS="$RUSTFLAGS -L native=/usr/lib"
fi
# Native build for all platforms (no cross-compilation needed with native ARM64 runners)
cargo build --locked --release
target_dir="../../target/release"
# Create artifact directory
mkdir -p ../../artifacts
# Copy the built library
if [[ "${{ matrix.os }}" == macos-* ]]; then
cp $target_dir/libpecos_julia.dylib ../../artifacts/
# Fix any remaining LLVM dependencies
echo "Checking and fixing library dependencies..."
otool -L ../../artifacts/libpecos_julia.dylib
# Check for any problematic dependencies
if otool -L ../../artifacts/libpecos_julia.dylib | grep -q "/tmp/llvm"; then
echo "ERROR: Binary has dependencies on /tmp/llvm which won't exist at runtime!"
echo "Attempting to fix..."
# For libunwind specifically, we'll strip it out by creating a new dylib without it
if otool -L ../../artifacts/libpecos_julia.dylib | grep -q "/tmp/llvm/lib/libunwind.dylib"; then
echo "Creating fixed library without LLVM libunwind dependency..."
# Use install_name_tool to remove the dependency by setting it to a weak import
# that can fail at runtime without crashing
install_name_tool -change /tmp/llvm/lib/libunwind.dylib /usr/lib/libSystem.B.dylib ../../artifacts/libpecos_julia.dylib || \
echo "Warning: Could not remap libunwind dependency"
fi
fi
echo "Final library dependencies:"
otool -L ../../artifacts/libpecos_julia.dylib
else
cp $target_dir/libpecos_julia.so ../../artifacts/
fi
# List artifacts
ls -la ../../artifacts/
- name: Create tarball
run: |
cd artifacts
mkdir -p lib
mv * lib/ 2>/dev/null || true
tar -czf ../pecos_julia-${{ matrix.os }}-${{ matrix.architecture }}.tar.gz lib
cd ..
ls -la *.tar.gz
- name: Upload binary
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: julia-binary-${{ matrix.os }}-${{ matrix.architecture }}
path: pecos_julia-*.tar.gz
if-no-files-found: error
test_binaries:
needs: build_julia_binaries
if: |
always() &&
needs.build_julia_binaries.result == 'success'
runs-on: ${{ matrix.platform.runner }}
strategy:
fail-fast: false
matrix:
julia-version: ['1.10', '1'] # 1.10 = LTS, 1 = latest stable
platform:
- runner: ubuntu-latest
os: ubuntu-latest
architecture: x86_64
- runner: windows-2022
os: windows-2022
architecture: x86_64
- runner: macos-15-intel
os: macos-15-intel
architecture: x86_64
- runner: macos-latest
os: macos-latest
architecture: aarch64
steps:
- name: Harden the runner (egress audit)
if: runner.os == 'Linux'
uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4
with:
egress-policy: audit
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
persist-credentials: false
ref: ${{ inputs.sha || github.sha }}
- name: Set up Julia ${{ matrix.julia-version }}
uses: julia-actions/setup-julia@fa02766e078afaaf09b14210362cee14137e6a32 # v3
with:
version: ${{ matrix.julia-version }}
- name: Download binary
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7
with:
name: julia-binary-${{ matrix.platform.os }}-${{ matrix.platform.architecture }}
path: ./julia-binary
- name: Set up test environment
run: |
# Extract the tarball
cd julia-binary
tar -xzf *.tar.gz
cd ..
# Create a temporary JLL structure
mkdir -p temp_jll
cp -r julia-binary/lib temp_jll/
cd julia/PECOS.jl
# Create a test script that uses the binary directly
cat > test_binary.jl << 'EOF'
# Add the library path
lib_path = joinpath(@__DIR__, "..", "..", "temp_jll", "lib")
# Determine the library name based on OS
lib_name = if Sys.iswindows()
"pecos_julia.dll"
elseif Sys.isapple()
"libpecos_julia.dylib"
else
"libpecos_julia.so"
end
lib_file = joinpath(lib_path, lib_name)
# Test direct ccall
println("Testing binary at: $lib_file")
# Test version function
ptr = ccall((:pecos_version, lib_file), Ptr{UInt8}, ())
version = unsafe_string(ptr)
ccall((:free_rust_string, lib_file), Cvoid, (Ptr{UInt8},), ptr)
println("Version: $version")
# Test add function
result = ccall((:add_two_numbers, lib_file), Int64, (Int64, Int64), 10, 32)
println("10 + 32 = $result")
if result == 42
println("Binary test passed!")
exit(0)
else
println("Binary test failed!")
exit(1)
end
EOF
- name: Test binary with Julia ${{ matrix.julia-version }}
run: |
cd julia/PECOS.jl
julia test_binary.jl
create_jll_package:
needs: [build_julia_binaries, test_binaries]
if: |
needs.build_julia_binaries.result == 'success' &&
needs.test_binaries.result == 'success'
runs-on: ubuntu-latest
steps:
- name: Harden the runner (egress audit)
uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4
with:
egress-policy: audit
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
persist-credentials: false
ref: ${{ inputs.sha || github.sha }}
- name: Set up Julia
uses: julia-actions/setup-julia@fa02766e078afaaf09b14210362cee14137e6a32 # v3
with:
version: '1.10'
- name: Create distribution directories
run: |
mkdir -p dist/binaries
mkdir -p dist/jll
# Download artifacts into temp directory first
- name: Download all binaries
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7
with:
path: temp-artifacts/
- name: Organize binaries
run: |
# Move all binaries to distribution directory
for artifact in temp-artifacts/julia-binary-*/; do
if [ -d "$artifact" ]; then
echo "Processing $artifact"
cp "$artifact"* dist/binaries/
fi
done
# List collected binaries
echo "=== Collected binaries ==="
ls -la dist/binaries/
- name: Create JLL structure
run: |
cd julia/PECOS.jl
# Create a script to generate JLL package structure
cat > create_jll.jl << 'EOF'
version = "0.1.0"
# Create JLL directory structure
jll_dir = joinpath(@__DIR__, "..", "..", "dist", "jll", "PECOS_julia_jll")
mkpath(joinpath(jll_dir, "src"))
# Create Project.toml
project_content = """
name = "PECOS_julia_jll"
uuid = "00000000-0000-0000-0000-000000000000" # Will be assigned by registry
version = "$version+0"
[deps]
JLLWrappers = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210"
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb"
[compat]
JLLWrappers = "1.6"
julia = "1.10"
"""
write(joinpath(jll_dir, "Project.toml"), project_content)
# Create basic JLL wrapper
jll_content = """
module PECOS_julia_jll
using Libdl
const libpecos_julia = "libpecos_julia"
function __init__()
# Initialization code will be added by BinaryBuilder
end
end # module
"""
write(joinpath(jll_dir, "src", "PECOS_julia_jll.jl"), jll_content)
println("Created JLL structure at: $jll_dir")
EOF
julia create_jll.jl
- name: Create release info
run: |
cat > dist/RELEASE_INFO.md << 'EOF'
# PECOS Julia Binary Distribution
This distribution contains:
1. **binaries/** - Pre-built libraries for all platforms
- Linux x86_64: libpecos_julia.so
- Linux aarch64: libpecos_julia.so
- macOS x86_64: libpecos_julia.dylib
- macOS aarch64: libpecos_julia.dylib
- Windows x86_64: pecos_julia.dll
2. **jll/** - JLL package structure (for BinaryBuilder submission)
## Next Steps
1. Submit to Yggdrasil for JLL creation
2. Wait for JLL registration
3. Update PECOS.jl to use registered JLL
4. Register PECOS.jl package
## Version
Version: 0.1.0
Commit: ${{ github.sha }}
EOF
- name: Upload distribution bundle
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: pecos-julia-distribution
path: dist/
if-no-files-found: error
create_release_bundle:
needs: [build_julia_binaries, test_binaries]
if: |
needs.build_julia_binaries.result == 'success' &&
needs.test_binaries.result == 'success'
runs-on: ubuntu-latest
steps:
- name: Harden the runner (egress audit)
uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4
with:
egress-policy: audit
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
ref: ${{ inputs.sha || github.sha }}
- name: Create distribution directories
run: |
mkdir -p release-bundle/binaries
mkdir -p release-bundle/checksums
# Download artifacts
- name: Download all binaries
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7
with:
path: temp-artifacts/
- name: Organize and checksum binaries
run: |
# Process each platform's binary
for artifact in temp-artifacts/julia-binary-*/; do
if [ -d "$artifact" ]; then
platform=$(basename "$artifact" | sed 's/julia-binary-//')
echo "Processing $platform"
# Move the tarball
mv "$artifact"/*.tar.gz "release-bundle/binaries/" || true
# Create checksum
cd release-bundle/binaries
for tarball in pecos_julia-*.tar.gz; do
if [ -f "$tarball" ]; then
sha256sum "$tarball" > "../checksums/${tarball}.sha256"
fi
done
cd ../..
fi
done
# List final structure
echo "=== Release Bundle Structure ==="
find release-bundle -type f | sort
- name: Generate Artifacts.toml
env:
RELEASE_REF_NAME: ${{ github.ref_name }}
run: |
cd release-bundle
# Create Artifacts.toml with actual checksums
{
printf '%s\n' '# Auto-generated by julia-release workflow'
printf '# For release: %s\n\n' "$RELEASE_REF_NAME"
printf '%s\n' '[PECOS_julia]'
printf '%s\n\n' 'git-tree-sha1 = "0000000000000000000000000000000000000000" # Tree hash will be computed on first use'
} > ../julia/PECOS.jl/Artifacts.toml
# Add download entries for each platform
for tarball in binaries/*.tar.gz; do
if [ -f "$tarball" ]; then
filename=$(basename "$tarball")
platform=$(echo "$filename" | sed 's/pecos_julia-//; s/.tar.gz//')
sha256=$(sha256sum "$tarball" | cut -d' ' -f1)
{
printf '%s\n' '[[PECOS_julia.download]]'
printf 'url = "https://github.com/PECOS-packages/PECOS/releases/download/%s/%s"\n' "$RELEASE_REF_NAME" "$filename"
printf 'sha256 = "%s"\n\n' "$sha256"
} >> ../julia/PECOS.jl/Artifacts.toml
fi
done
echo "Generated Artifacts.toml:"
cat ../julia/PECOS.jl/Artifacts.toml
- name: Create submission instructions
env:
RELEASE_SHA: ${{ github.sha }}
RELEASE_REF_NAME: ${{ github.ref_name }}
run: |
cat > release-bundle/SUBMISSION_INSTRUCTIONS.md << 'EOF'
# Julia Package Submission Instructions
This bundle contains pre-built binaries for PECOS.jl.
## Contents
- `binaries/` - Pre-built libraries for all platforms
- `checksums/` - SHA256 checksums for verification
## Manual Submission Process
### Option 1: Submit to Julia General Registry (Recommended)
1. Update `julia/PECOS.jl/deps/Artifacts.toml`:
- Add the URLs where you'll host these binaries
- Add the SHA256 checksums from the checksums folder
2. Host the binaries:
- Create a GitHub release and upload the tarballs
- Or use any other hosting service
3. Register the package:
```julia
using Registrator
Registrator.register(
"https://github.com/PECOS-packages/PECOS.git",
subdir="julia/PECOS.jl"
)
```
### Option 2: Submit to Yggdrasil (For JLL creation)
1. Fork https://github.com/JuliaPackaging/Yggdrasil
2. Create a new folder: `P/PECOS_julia/`
3. Copy `build_tarballs.jl` from the PECOS repo
4. Create a pull request
## Platform Support
Binaries are included for:
- Linux x86_64
- Linux aarch64
- macOS x86_64
- macOS aarch64
- Windows x86_64
## Version Info
EOF
{
printf '\n'
printf '%s\n' '- Version: 0.1.0'
printf -- '- Commit: %s\n' "$RELEASE_SHA"
printf -- '- Branch: %s\n' "$RELEASE_REF_NAME"
printf -- '- Date: %s\n' "$(date -u +%Y-%m-%d)"
} >> release-bundle/SUBMISSION_INSTRUCTIONS.md
- name: Create tarball of entire bundle
run: |
tar -czf pecos-julia-release-bundle-${{ github.run_number }}.tar.gz release-bundle/
ls -lh pecos-julia-release-bundle-*.tar.gz
- name: Upload release bundle
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: pecos-julia-release-bundle
path: pecos-julia-release-bundle-*.tar.gz
if-no-files-found: error
retention-days: 30 # Keep for 30 days
- name: Determine if pre-release
id: check-prerelease
if: startsWith(github.ref, 'refs/tags/jl-')
env:
RELEASE_REF_NAME: ${{ github.ref_name }}
run: |
# Extract version from tag (remove jl- prefix)
VERSION="$RELEASE_REF_NAME"
VERSION="${VERSION#jl-}"
# Check if it contains a hyphen (pre-release indicator)
if [[ "$VERSION" == *"-"* ]]; then
echo "is_prerelease=true" >> $GITHUB_OUTPUT
echo "Pre-release detected: $VERSION"
else
echo "is_prerelease=false" >> $GITHUB_OUTPUT
echo "Release version detected: $VERSION"
fi
- name: Create GitHub Release and Upload Binaries
if: startsWith(github.ref, 'refs/tags/jl-')
uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2
with:
files: release-bundle/binaries/*.tar.gz
body: |
## Julia binaries for PECOS ${{ github.ref_name }}
These binaries are automatically downloaded when installing the Julia package.
### Installation
```julia
using Pkg
Pkg.add(url="https://github.com/PECOS-packages/PECOS", subdir="julia/PECOS.jl")
```
The correct binary for your platform will be downloaded automatically.
draft: false
prerelease: ${{ steps.check-prerelease.outputs.is_prerelease }}
fail_on_unmatched_files: true
- name: Commit Artifacts.toml to branch
if: startsWith(github.ref, 'refs/tags/jl-')
env:
RELEASE_REF_NAME: ${{ github.ref_name }}
run: |
# Configure git
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
# Add and commit the Artifacts.toml
git add julia/PECOS.jl/Artifacts.toml
git commit -m "Add Artifacts.toml for $RELEASE_REF_NAME" || echo "No changes to commit"
# Push to the tag's branch
git push origin "HEAD:${RELEASE_REF_NAME}-artifacts" || echo "Push failed"