feat: ODiff v3 SIMD #748
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: Build | |
on: | |
pull_request: | |
push: | |
branches: | |
- main | |
tags: | |
- "v*.*.*" | |
jobs: | |
build: | |
runs-on: ${{ matrix.os }} | |
strategy: | |
matrix: | |
include: | |
- target: x86_64-linux-gnu | |
os: ubuntu-latest | |
artifact: "linux-x64" | |
triplet: "x64-linux" | |
- target: aarch64-linux-gnu | |
os: ubuntu-latest | |
artifact: "linux-arm64" | |
triplet: "arm64-linux" | |
toolchain: "gcc-aarch64-linux-gnu g++-aarch64-linux-gnu" | |
- target: x86_64-windows-gnu | |
os: windows-latest | |
artifact: "windows-x64.exe" | |
triplet: "x64-mingw-static" | |
- target: aarch64-windows-gnu | |
os: ubuntu-latest | |
artifact: "windows-arm64.exe" | |
triplet: "arm64-mingw-static" | |
toolchain: "llvm-mingw" | |
- target: aarch64-macos | |
os: macos-latest | |
artifact: "macos-arm64" | |
triplet: "arm64-osx" | |
- target: x86_64-macos | |
os: macos-13 | |
artifact: "macos-x64" | |
triplet: "x64-osx" | |
defaults: | |
run: | |
shell: bash | |
steps: | |
- name: Checkout code | |
uses: actions/checkout@v4 | |
- if: runner.os == 'Windows' | |
run: | | |
rm -rf $(which pkg-config) | |
choco install pkgconfiglite | |
- name: Install cross-compilation toolchain | |
if: runner.os == 'Linux' && matrix.toolchain | |
run: | | |
if [[ "${{ matrix.target }}" == "aarch64-windows-gnu" ]]; then | |
wget https://github.com/mstorsjo/llvm-mingw/releases/download/20240417/llvm-mingw-20240417-ucrt-ubuntu-20.04-x86_64.tar.xz | |
tar -xf llvm-mingw-20240417-ucrt-ubuntu-20.04-x86_64.tar.xz | |
echo "${GITHUB_WORKSPACE}/llvm-mingw-20240417-ucrt-ubuntu-20.04-x86_64/bin" >> $GITHUB_PATH | |
sudo apt-get update | |
sudo apt-get install -y pkg-config | |
echo "CC=aarch64-w64-mingw32-clang" >> $GITHUB_ENV | |
echo "CXX=aarch64-w64-mingw32-clang++" >> $GITHUB_ENV | |
echo "AR=aarch64-w64-mingw32-llvm-ar" >> $GITHUB_ENV | |
echo "LD=aarch64-w64-mingw32-ld" >> $GITHUB_ENV | |
echo "STRIP=aarch64-w64-mingw32-llvm-strip" >> $GITHUB_ENV | |
echo "PKG_CONFIG=pkg-config" >> $GITHUB_ENV | |
else | |
# Regular GCC cross-compilation for Linux ARM64 | |
sudo apt-get update | |
sudo apt-get install -y ${{ matrix.toolchain }} | |
fi | |
- name: Setup Zig | |
uses: goto-bus-stop/setup-zig@v2 | |
with: | |
version: 0.15.1 | |
- uses: lukka/get-cmake@latest | |
- name: Setup vcpkg | |
uses: lukka/run-vcpkg@v11 | |
env: | |
VCPKG_DEFAULT_TRIPLET: ${{ matrix.triplet }} | |
VCPKG_DEFAULT_HOST_TRIPLET: ${{ matrix.triplet }} | |
VCPKG_BUILD_TYPE: release | |
with: | |
runVcpkgInstall: true | |
runVcpkgFormatString: '["install", "--clean-after-build"]' | |
- name: Set pkg-config path on Unix | |
if: runner.os != 'Windows' | |
run: | | |
ls "${GITHUB_WORKSPACE}/vcpkg_installed/${VCPKG_DEFAULT_TRIPLET}/lib/pkgconfig" | |
echo "PKG_CONFIG_PATH=${GITHUB_WORKSPACE}/vcpkg_installed/${VCPKG_DEFAULT_TRIPLET}/lib/pkgconfig" >> $GITHUB_ENV | |
- name: Set pkg-config path on Windows | |
shell: bash | |
if: runner.os == 'Windows' | |
run: | | |
echo "PKG_CONFIG_PATH=${GITHUB_WORKSPACE}\\vcpkg_installed\\${VCPKG_DEFAULT_TRIPLET}\\lib\\pkgconfig" >> $GITHUB_ENV | |
- name: Build for ${{ matrix.target }} | |
env: | |
VCPKG_ROOT: ${{ github.workspace }}/vcpkg_installed | |
run: | | |
echo "🔧 Building for target: ${{ matrix.target }}" | |
echo "📁 VCPKG_ROOT: $VCPKG_ROOT" | |
echo "🔗 PKG_CONFIG_PATH: $PKG_CONFIG_PATH" | |
# Create unique build directory to prevent matrix job collisions | |
BUILD_DIR="zig-out-${{ matrix.artifact }}" | |
echo "🏗️ Using isolated build directory: $BUILD_DIR" | |
# Clean any existing build directory | |
rm -rf zig-out "$BUILD_DIR" | |
# Verify vcpkg installation | |
if [[ ! -d "$VCPKG_ROOT/${{ matrix.triplet }}" ]]; then | |
echo "❌ ERROR: vcpkg triplet directory not found: $VCPKG_ROOT/${{ matrix.triplet }}" | |
echo "Available directories in $VCPKG_ROOT:" | |
ls -la "$VCPKG_ROOT/" || echo "VCPKG_ROOT directory not found" | |
exit 1 | |
fi | |
# Show available libraries | |
echo "📚 Available pkg-config libraries:" | |
pkg-config --list-all | grep -E "(spng|jpeg|tiff|zlib)" || echo "No image libraries found via pkg-config" | |
# Build with Zig (outputs to default zig-out/) | |
echo "🚀 Starting Zig build..." | |
if ! zig build -Dtarget=${{ matrix.target }} -Doptimize=ReleaseFast --verbose; then | |
echo "❌ Build failed for target ${{ matrix.target }}" | |
echo "📋 Build environment info:" | |
echo " - Runner OS: ${{ runner.os }}" | |
echo " - Target: ${{ matrix.target }}" | |
echo " - Triplet: ${{ matrix.triplet }}" | |
exit 1 | |
fi | |
echo "✅ Build completed successfully" | |
echo "🔍 Checking default zig-out directory:" | |
ls -la zig-out/bin/ || echo "Default zig-out directory not found" | |
# Move binary to isolated directory to prevent matrix job conflicts | |
echo "📦 Moving binary to isolated directory: $BUILD_DIR/bin/" | |
mkdir -p "$BUILD_DIR/bin" | |
echo "🔍 What did Zig actually produce?" | |
ls -la zig-out/bin/ | |
# Find and move the actual binary (handle various naming) | |
if [[ -f "zig-out/bin/odiff.exe" ]]; then | |
mv "zig-out/bin/odiff.exe" "$BUILD_DIR/bin/odiff.exe" | |
echo "✅ Moved zig-out/bin/odiff.exe to $BUILD_DIR/bin/odiff.exe" | |
elif [[ -f "zig-out/bin/odiff" ]]; then | |
mv "zig-out/bin/odiff" "$BUILD_DIR/bin/odiff" | |
echo "✅ Moved zig-out/bin/odiff to $BUILD_DIR/bin/odiff" | |
else | |
# Find any file that starts with "odiff" (handle edge cases) | |
FOUND_BINARY=$(find zig-out/bin/ -name "odiff*" -type f | head -1) | |
if [[ -n "$FOUND_BINARY" ]]; then | |
BASENAME=$(basename "$FOUND_BINARY") | |
mv "$FOUND_BINARY" "$BUILD_DIR/bin/$BASENAME" | |
echo "✅ Moved $FOUND_BINARY to $BUILD_DIR/bin/$BASENAME" | |
else | |
echo "❌ ERROR: No binary found in zig-out/bin/" | |
ls -la zig-out/bin/ || echo "zig-out/bin/ directory not found" | |
exit 1 | |
fi | |
fi | |
echo "📁 Final build output location: $BUILD_DIR/bin/" | |
ls -la "$BUILD_DIR/bin/" | |
echo "🔍 Checking if there are any committed binaries in repo:" | |
find . -name "odiff*" -type f -exec file {} \; || echo "No odiff binaries found in repo" | |
- name: Validate binary architecture | |
shell: bash | |
run: | | |
echo "Validating binary for target: ${{ matrix.target }}" | |
BUILD_DIR="zig-out-${{ matrix.artifact }}" | |
# Find the correct binary path (handle various binary names) | |
echo "🔍 Checking for binaries in $BUILD_DIR/bin/" | |
echo " - Looking for $BUILD_DIR/bin/odiff.exe: $(test -f "$BUILD_DIR/bin/odiff.exe" && echo "EXISTS" || echo "NOT FOUND")" | |
echo " - Looking for $BUILD_DIR/bin/odiff: $(test -f "$BUILD_DIR/bin/odiff" && echo "EXISTS" || echo "NOT FOUND")" | |
if [[ -f "$BUILD_DIR/bin/odiff.exe" ]]; then | |
BINARY_PATH="$BUILD_DIR/bin/odiff.exe" | |
echo "✅ Using odiff.exe" | |
elif [[ -f "$BUILD_DIR/bin/odiff" ]]; then | |
BINARY_PATH="$BUILD_DIR/bin/odiff" | |
echo "✅ Using odiff" | |
else | |
# Find any file that starts with "odiff" (handle edge cases) | |
echo "🔍 Searching for any odiff* files..." | |
FOUND_BINARY=$(find "$BUILD_DIR/bin/" -name "odiff*" -type f | head -1) | |
if [[ -n "$FOUND_BINARY" ]]; then | |
BINARY_PATH="$FOUND_BINARY" | |
echo "✅ Using found binary: $FOUND_BINARY" | |
else | |
echo "ERROR: No binary found in $BUILD_DIR/bin/" | |
echo "Contents of $BUILD_DIR/bin/:" | |
ls -la "$BUILD_DIR/bin/" || echo "Build directory not found" | |
exit 1 | |
fi | |
fi | |
echo "Found binary at: $BINARY_PATH" | |
# Get binary info | |
echo "Binary info:" | |
file "$BINARY_PATH" | |
# Validate target architecture matches expectation | |
BINARY_INFO=$(file "$BINARY_PATH") | |
case "${{ matrix.target }}" in | |
*"windows"*) | |
if [[ ! "$BINARY_INFO" =~ "PE32+".*"x86-64" ]] && [[ ! "$BINARY_INFO" =~ "PE32+".*"Aarch64" ]] && [[ ! "$BINARY_INFO" =~ "COFF" ]]; then | |
echo "ERROR: Expected Windows PE/COFF executable, got: $BINARY_INFO" | |
exit 1 | |
fi | |
;; | |
*"linux"*) | |
if [[ ! "$BINARY_INFO" =~ "ELF".*"x86-64" ]] && [[ ! "$BINARY_INFO" =~ "ELF".*"aarch64" ]]; then | |
echo "ERROR: Expected Linux ELF executable, got: $BINARY_INFO" | |
exit 1 | |
fi | |
;; | |
*"macos"*) | |
if [[ ! "$BINARY_INFO" =~ "Mach-O".*"x86_64" ]] && [[ ! "$BINARY_INFO" =~ "Mach-O".*"arm64" ]]; then | |
echo "ERROR: Expected macOS Mach-O executable, got: $BINARY_INFO" | |
exit 1 | |
fi | |
;; | |
*) | |
echo "WARNING: Unknown target type, skipping validation" | |
;; | |
esac | |
echo "✅ Binary validation passed for ${{ matrix.target }}" | |
- name: Test binary execution (if possible) | |
shell: bash | |
run: | | |
# Only test execution on native or compatible targets | |
SHOULD_TEST=false | |
case "${{ matrix.target }}" in | |
"x86_64-linux-gnu") | |
if [[ "${{ runner.os }}" == "Linux" ]]; then SHOULD_TEST=true; fi | |
;; | |
"x86_64-windows-gnu") | |
if [[ "${{ runner.os }}" == "Windows" ]]; then SHOULD_TEST=true; fi | |
;; | |
"x86_64-macos") | |
if [[ "${{ runner.os }}" == "macOS" ]]; then SHOULD_TEST=true; fi | |
;; | |
"aarch64-macos") | |
if [[ "${{ runner.os }}" == "macOS" ]] && [[ "$(uname -m)" == "arm64" ]]; then SHOULD_TEST=true; fi | |
;; | |
esac | |
if [[ "$SHOULD_TEST" == "true" ]]; then | |
echo "Testing binary execution on compatible platform" | |
BUILD_DIR="zig-out-${{ matrix.artifact }}" | |
if [[ "${{ matrix.target }}" == *"windows"* ]]; then | |
"$BUILD_DIR/bin/odiff.exe" --help || "$BUILD_DIR/bin/odiff" --help | |
else | |
"$BUILD_DIR/bin/odiff" --help | |
fi | |
echo "✅ Binary execution test passed" | |
else | |
echo "⏭️ Skipping execution test (cross-compiled binary)" | |
fi | |
- name: Copy binary to artifact name | |
run: | | |
BUILD_DIR="zig-out-${{ matrix.artifact }}" | |
# Copy the correct binary based on target | |
if [[ "${{ matrix.target }}" == *"windows"* ]]; then | |
# For Windows targets, check if .exe exists | |
if [[ -f "$BUILD_DIR/bin/odiff.exe" ]]; then | |
cp "$BUILD_DIR/bin/odiff.exe" "odiff-${{ matrix.artifact }}" | |
elif [[ -f "$BUILD_DIR/bin/odiff" ]]; then | |
cp "$BUILD_DIR/bin/odiff" "odiff-${{ matrix.artifact }}" | |
else | |
echo "ERROR: No binary found for Windows target in $BUILD_DIR/bin/" | |
ls -la "$BUILD_DIR/bin/" || echo "Build directory not found" | |
exit 1 | |
fi | |
else | |
# For Unix targets | |
if [[ -f "$BUILD_DIR/bin/odiff" ]]; then | |
cp "$BUILD_DIR/bin/odiff" "odiff-${{ matrix.artifact }}" | |
else | |
echo "ERROR: No binary found for Unix target in $BUILD_DIR/bin/" | |
ls -la "$BUILD_DIR/bin/" || echo "Build directory not found" | |
exit 1 | |
fi | |
fi | |
echo "✅ Binary copied to odiff-${{ matrix.artifact }}" | |
- name: Upload artifact | |
uses: actions/upload-artifact@v4 | |
with: | |
if-no-files-found: error | |
name: odiff-${{ matrix.artifact }} | |
path: odiff-${{ matrix.artifact }} | |
retention-days: 14 | |
test: | |
runs-on: ubuntu-latest | |
name: Run Tests | |
steps: | |
- name: Checkout code | |
uses: actions/checkout@v4 | |
- name: Setup Zig | |
uses: goto-bus-stop/setup-zig@v2 | |
with: | |
version: 0.15.1 | |
- name: Install system dependencies | |
run: | | |
sudo apt-get update | |
sudo apt-get install -y libspng-dev libjpeg-dev libtiff-dev pkg-config | |
- name: Run tests | |
run: | | |
zig build test-all | |
spellcheck: | |
name: Spell check | |
runs-on: ubuntu-latest | |
steps: | |
- name: Checkout code | |
uses: actions/checkout@v4 | |
- name: Run typos | |
uses: crate-ci/typos@master | |
with: | |
config: ./typos.toml | |
publish: | |
name: Publish release | |
needs: [build, test] | |
if: startsWith(github.ref, 'refs/tags/') | |
runs-on: ubuntu-latest | |
steps: | |
- name: Checkout | |
uses: actions/checkout@v1 | |
- name: Download built binaries | |
uses: actions/download-artifact@v4 | |
with: | |
pattern: odiff-* | |
merge-multiple: true | |
path: npm_package/raw_binaries | |
- name: Set up Node.js | |
uses: actions/setup-node@v4 | |
with: | |
node-version: "20" | |
cache: "npm" | |
always-auth: true | |
registry-url: "https://registry.npmjs.org" | |
cache-dependency-path: "package-lock.json" | |
- name: Publish npm package | |
working-directory: npm_package | |
run: npm publish | |
env: | |
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} | |
- name: Create github release | |
uses: softprops/action-gh-release@v1 | |
with: | |
files: "npm_package/raw_binaries/*" | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |