Skip to content

Build and Release

Build and Release #126

Workflow file for this run

name: Build and Release
on:
workflow_dispatch:
release:
types: [published]
jobs:
build:
permissions:
contents: write
strategy:
matrix:
include:
# - os: windows-latest
# target: x86_64-pc-windows-msvc
# asset_name: windows-amd64
# - os: ubuntu-latest
# target: x86_64-unknown-linux-gnu
# asset_name: linux-amd64
# - os: ubuntu-latest
# target: aarch64-unknown-linux-gnu
# asset_name: linux-arm64
# - os: ubuntu-latest
# target: armv7-unknown-linux-gnueabihf
# asset_name: linux-armv7
# - os: ubuntu-latest
# target: riscv64gc-unknown-linux-gnu
# asset_name: linux-riscv64
- os: ubuntu-latest
target: mips64-unknown-linux-gnuabi64
asset_name: linux-mips64
- os: ubuntu-latest
target: mips64el-unknown-linux-gnuabi64
asset_name: linux-mips64le
- os: ubuntu-latest
target: mips-unknown-linux-gnu
asset_name: linux-mips
- os: ubuntu-latest
target: mipsel-unknown-linux-gnu
asset_name: linux-mipsle
# - os: macos-latest
# target: aarch64-apple-darwin
# asset_name: darwin-arm64
# - os: macos-latest
# target: x86_64-apple-darwin
# asset_name: darwin-amd64
fail-fast: false
runs-on: ${{ matrix.os }}
env:
TARGET: ${{ matrix.target }}
ASSET_NAME: ${{ matrix.asset_name }}
EXE_EXT: ${{ contains(matrix.target, 'windows') && '.exe' || '' }}
steps:
- name: Checkout slipstream-rust-deploy repository
uses: actions/checkout@v4
- name: Checkout slipstream-rust repository
uses: actions/checkout@v4
with:
repository: Mygod/slipstream-rust
ref: main
submodules: recursive
path: slipstream-rust
- name: Set up QEMU
if: runner.os == 'Linux' && contains('aarch64-unknown-linux-gnu,armv7-unknown-linux-gnueabihf,riscv64gc-unknown-linux-gnu,mips64-unknown-linux-gnuabi64,mips64el-unknown-linux-gnuabi64,mips-unknown-linux-gnu,mipsel-unknown-linux-gnu', matrix.target)
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
if: runner.os == 'Linux' && contains('aarch64-unknown-linux-gnu,armv7-unknown-linux-gnueabihf,riscv64gc-unknown-linux-gnu,mips64-unknown-linux-gnuabi64,mips64el-unknown-linux-gnuabi64,mips-unknown-linux-gnu,mipsel-unknown-linux-gnu', matrix.target)
uses: docker/setup-buildx-action@v3
with:
platforms: linux/arm64,linux/arm/v7,linux/riscv64,linux/mips64,linux/mips64le,linux/mips,linux/mipsle
- name: Install Rust
if: runner.os != 'Linux' || !contains('aarch64-unknown-linux-gnu,armv7-unknown-linux-gnueabihf,riscv64gc-unknown-linux-gnu,mips64-unknown-linux-gnuabi64,mips64el-unknown-linux-gnuabi64,mips-unknown-linux-gnu,mipsel-unknown-linux-gnu', matrix.target)
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Install cross toolchain
if: runner.os != 'Linux' || !contains('aarch64-unknown-linux-gnu,armv7-unknown-linux-gnueabihf,riscv64gc-unknown-linux-gnu,mips64-unknown-linux-gnuabi64,mips64el-unknown-linux-gnuabi64,mips-unknown-linux-gnu,mipsel-unknown-linux-gnu', matrix.target)
uses: taiki-e/setup-cross-toolchain-action@v1
with:
target: ${{ env.TARGET }}
- name: Get slipstream-rust commit hash
id: get_commit
working-directory: slipstream-rust
shell: bash
run: |
echo "commit=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
echo "short_commit=$(git rev-parse --short=7 HEAD)" >> $GITHUB_OUTPUT
- name: Cache Rust dependencies
if: runner.os != 'Linux' || !contains('aarch64-unknown-linux-gnu,armv7-unknown-linux-gnueabihf,riscv64gc-unknown-linux-gnu,mips64-unknown-linux-gnuabi64,mips64el-unknown-linux-gnuabi64,mips-unknown-linux-gnu,mipsel-unknown-linux-gnu', matrix.target)
uses: actions/cache@v4
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
slipstream-rust/target/
key: ${{ runner.os }}-rust-${{ matrix.target }}-${{ steps.get_commit.outputs.commit }}
restore-keys: |
${{ runner.os }}-rust-${{ matrix.target }}-
${{ runner.os }}-rust-
- name: Install build dependencies (Linux)
if: runner.os == 'Linux' && !contains('aarch64-unknown-linux-gnu,armv7-unknown-linux-gnueabihf,riscv64gc-unknown-linux-gnu,mips64-unknown-linux-gnuabi64,mips64el-unknown-linux-gnuabi64,mips-unknown-linux-gnu,mipsel-unknown-linux-gnu', matrix.target)
run: |
sudo apt-get update
sudo apt-get install -y cmake pkg-config gcc g++ perl
if [[ "${{ matrix.target }}" == "x86_64-unknown-linux-gnu" ]]; then
sudo apt-get install -y libssl-dev
fi
- name: Install build dependencies (macOS)
if: runner.os == 'macOS'
run: |
brew install cmake pkg-config
if [[ "${{ matrix.target }}" == "x86_64-apple-darwin" ]]; then
# Install x86_64 Homebrew and OpenSSL for cross-compilation
arch -x86_64 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" || true
arch -x86_64 /usr/local/bin/brew install openssl@3
else
brew install openssl@3
fi
- name: Install build dependencies (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
choco install cmake pkgconfiglite strawberryperl -y
# Find and configure OpenSSL
$opensslPaths = @(
"C:\Program Files\OpenSSL",
"C:\Program Files\OpenSSL-Win64",
"C:\OpenSSL-Win64",
"C:\OpenSSL"
)
foreach ($path in $opensslPaths) {
if (Test-Path $path) {
$libDir = Get-ChildItem -Path "$path\lib" -Filter "libcrypto*.lib" -Recurse -ErrorAction SilentlyContinue |
Select-Object -First 1 | ForEach-Object { $_.DirectoryName }
if ($libDir) {
echo "OPENSSL_DIR=$path" >> $env:GITHUB_ENV
echo "OPENSSL_ROOT_DIR=$path" >> $env:GITHUB_ENV
echo "OPENSSL_LIB_DIR=$libDir" >> $env:GITHUB_ENV
echo "OPENSSL_INCLUDE_DIR=$path\include" >> $env:GITHUB_ENV
Write-Host "OpenSSL configured at $path (libs in $libDir)"
break
}
}
}
- name: Setup Perl for OpenSSL vendored build (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
$perlPaths = @(
"C:\Strawberry\perl\bin",
"C:\Program Files\Strawberry\perl\bin",
"${env:ProgramFiles}\Strawberry\perl\bin"
)
foreach ($path in $perlPaths) {
$exe = Join-Path $path "perl.exe"
if (Test-Path $exe) {
$env:Path = "$path;$env:Path"
echo "PATH=$path`;$env:Path" >> $env:GITHUB_ENV
echo "PERL=$exe" >> $env:GITHUB_ENV
Write-Host "Found Strawberry Perl at $path"
# Install Locale::Maketext::Simple if needed
$moduleCheck = & $exe -e "use Locale::Maketext::Simple; print 'OK'" 2>&1
if ($LASTEXITCODE -ne 0) {
$cpanmExe = Join-Path $path "cpanm.bat"
if (Test-Path $cpanmExe) {
& $cpanmExe --notest Locale::Maketext::Simple 2>&1 | Out-String | Write-Host
}
}
break
}
}
- name: Setup OpenSSL (macOS)
if: runner.os == 'macOS'
run: |
if [[ "${{ matrix.target }}" == "x86_64-apple-darwin" ]]; then
echo "PKG_CONFIG_PATH=/usr/local/opt/openssl@3/lib/pkgconfig:$PKG_CONFIG_PATH" >> $GITHUB_ENV
echo "OPENSSL_DIR=/usr/local/opt/openssl@3" >> $GITHUB_ENV
echo "OPENSSL_ROOT_DIR=/usr/local/opt/openssl@3" >> $GITHUB_ENV
else
echo "PKG_CONFIG_PATH=/opt/homebrew/opt/openssl@3/lib/pkgconfig:$PKG_CONFIG_PATH" >> $GITHUB_ENV
echo "OPENSSL_DIR=/opt/homebrew/opt/openssl@3" >> $GITHUB_ENV
echo "OPENSSL_ROOT_DIR=/opt/homebrew/opt/openssl@3" >> $GITHUB_ENV
fi
- name: Build with Docker buildx (Linux alternate architectures)
if: runner.os == 'Linux' && contains('aarch64-unknown-linux-gnu,armv7-unknown-linux-gnueabihf,riscv64gc-unknown-linux-gnu,mips64-unknown-linux-gnuabi64,mips64el-unknown-linux-gnuabi64,mips-unknown-linux-gnu,mipsel-unknown-linux-gnu', matrix.target)
run: |
set -e
TARGET="${{ matrix.target }}"
# Map Rust target to Docker platform and Dockerfile
# MIPS: no base image exists on Docker Hub; use amd64 and cross-compile in container
case "$TARGET" in
aarch64-unknown-linux-gnu) DOCKER_PLATFORM=linux/arm64 DOCKERFILE=Dockerfile.arm64 ;;
armv7-unknown-linux-gnueabihf) DOCKER_PLATFORM=linux/arm/v7 DOCKERFILE=Dockerfile.armv7 ;;
riscv64gc-unknown-linux-gnu) DOCKER_PLATFORM=linux/riscv64 DOCKERFILE=Dockerfile.riscv64 ;;
mips64-unknown-linux-gnuabi64) DOCKER_PLATFORM=linux/amd64 DOCKERFILE=Dockerfile.mips64 ;;
mips64el-unknown-linux-gnuabi64) DOCKER_PLATFORM=linux/amd64 DOCKERFILE=Dockerfile.mips64le ;;
mips-unknown-linux-gnu) DOCKER_PLATFORM=linux/amd64 DOCKERFILE=Dockerfile.mips ;;
mipsel-unknown-linux-gnu) DOCKER_PLATFORM=linux/amd64 DOCKERFILE=Dockerfile.mipsle ;;
*) echo "Unsupported Docker target: $TARGET"; exit 1 ;;
esac
TAG="slipstream-build:${TARGET%%-*}"
mkdir -p docker-build-output
mkdir -p "slipstream-rust/target/$TARGET/release"
docker buildx build \
--platform "$DOCKER_PLATFORM" \
--file "$DOCKERFILE" \
--tag "$TAG" \
--output type=docker,dest=- \
. | docker load
docker run --rm \
--platform "$DOCKER_PLATFORM" \
-v "${{ github.workspace }}/slipstream-rust:/workspace/slipstream-rust" \
-v "${{ github.workspace }}/docker-build-output:/workspace/output" \
"$TAG"
sudo chown -R $(id -u):$(id -g) slipstream-rust/target/ 2>/dev/null || true
cp docker-build-output/slipstream-client "slipstream-rust/target/$TARGET/release/"
cp docker-build-output/slipstream-server "slipstream-rust/target/$TARGET/release/"
ls -lh "slipstream-rust/target/$TARGET/release/"
- name: Build picoquic (Linux)
if: runner.os == 'Linux' && !contains('aarch64-unknown-linux-gnu,armv7-unknown-linux-gnueabihf,riscv64gc-unknown-linux-gnu,mips64-unknown-linux-gnuabi64,mips64el-unknown-linux-gnuabi64,mips-unknown-linux-gnu,mipsel-unknown-linux-gnu', matrix.target)
working-directory: slipstream-rust
run: |
bash scripts/build_picoquic.sh
echo "PICOQUIC_DIR=${GITHUB_WORKSPACE}/slipstream-rust/vendor/picoquic" >> $GITHUB_ENV
echo "PICOQUIC_BUILD_DIR=${GITHUB_WORKSPACE}/slipstream-rust/.picoquic-build" >> $GITHUB_ENV
- name: Build picoquic (macOS)
if: runner.os == 'macOS'
working-directory: slipstream-rust
shell: bash
run: |
PICOQUIC_DIR="${GITHUB_WORKSPACE}/slipstream-rust/vendor/picoquic"
PICOQUIC_BUILD_DIR="${GITHUB_WORKSPACE}/slipstream-rust/.picoquic-build"
CMAKE_ARGS=(-S "$PICOQUIC_DIR" -B "$PICOQUIC_BUILD_DIR"
-DCMAKE_BUILD_TYPE=Release
-DCMAKE_POLICY_VERSION_MINIMUM=3.5
-DPICOQUIC_FETCH_PTLS=ON
-DBUILD_TESTING=OFF
-Dpicoquic_BUILD_TESTS=OFF
-Wno-dev)
if [[ "${{ matrix.target }}" == "x86_64-apple-darwin" ]]; then
CMAKE_ARGS+=(
-DCMAKE_OSX_ARCHITECTURES=x86_64
-DCMAKE_OSX_DEPLOYMENT_TARGET=10.12
-DOPENSSL_ROOT_DIR=/usr/local/opt/openssl@3
-DOPENSSL_INCLUDE_DIR=/usr/local/opt/openssl@3/include
-DOPENSSL_CRYPTO_LIBRARY=/usr/local/opt/openssl@3/lib/libcrypto.dylib
-DOPENSSL_SSL_LIBRARY=/usr/local/opt/openssl@3/lib/libssl.dylib
-DCMAKE_C_FLAGS="-arch x86_64 -mmacosx-version-min=10.12"
-DCMAKE_CXX_FLAGS="-arch x86_64 -mmacosx-version-min=10.12")
fi
# Initial configure to fetch picotls
cmake "${CMAKE_ARGS[@]}" || true
# Patch picotls CMake version requirement
PTLS_CMAKE="$PICOQUIC_BUILD_DIR/_deps/picotls-src/CMakeLists.txt"
if [ -f "$PTLS_CMAKE" ]; then
sed -i '' 's/CMAKE_MINIMUM_REQUIRED(VERSION [0-9.]*)/CMAKE_MINIMUM_REQUIRED(VERSION 3.15)/' "$PTLS_CMAKE" || true
fi
# Reconfigure and build
cmake "${CMAKE_ARGS[@]}"
# Build targets - fusion only exists on x86_64 (uses AES-NI)
if [[ "${{ matrix.target }}" == "x86_64-apple-darwin" ]]; then
cmake --build "$PICOQUIC_BUILD_DIR" --target picoquic-core picotls-core picotls-fusion picotls-minicrypto picotls-openssl
else
cmake --build "$PICOQUIC_BUILD_DIR" --target picoquic-core picotls-core picotls-minicrypto picotls-openssl
# Create dummy fusion library for ARM64 (no AES-NI support)
PTLS_BUILD_DIR="$PICOQUIC_BUILD_DIR/_deps/picotls-build"
echo 'void picotls_fusion_placeholder(void) {}' | cc -c -x c - -o /tmp/dummy.o
ar rcs "$PTLS_BUILD_DIR/libpicotls-fusion.a" /tmp/dummy.o
fi
echo "PICOQUIC_DIR=$PICOQUIC_DIR" >> $GITHUB_ENV
echo "PICOQUIC_BUILD_DIR=$PICOQUIC_BUILD_DIR" >> $GITHUB_ENV
- name: Build picoquic (Windows)
if: runner.os == 'Windows'
working-directory: slipstream-rust
shell: bash
run: |
PICOQUIC_DIR="${GITHUB_WORKSPACE}/slipstream-rust/vendor/picoquic"
PICOQUIC_BUILD_DIR="${GITHUB_WORKSPACE}/slipstream-rust/.picoquic-build"
OPENSSL_PATH=$(echo "${OPENSSL_DIR:-}" | sed 's|\\|/|g')
CRYPTO_LIB=$(find "$OPENSSL_PATH/lib" -name "libcrypto*.lib" 2>/dev/null | head -1)
SSL_LIB=$(find "$OPENSSL_PATH/lib" -name "libssl*.lib" 2>/dev/null | head -1)
WINCOMPAT_H="${PICOQUIC_DIR}/picoquic/wincompat.h"
CMAKE_ARGS=(-S "$PICOQUIC_DIR" -B "$PICOQUIC_BUILD_DIR"
-G "Visual Studio 17 2022" -A x64
-DCMAKE_BUILD_TYPE=Release
-DCMAKE_POLICY_VERSION_MINIMUM=3.5
-DPICOQUIC_FETCH_PTLS=ON
-DBUILD_TESTING=OFF
-DCMAKE_C_FLAGS="/D_WINDOWS /FI\"${WINCOMPAT_H}\" /FI\"ws2tcpip.h\""
-DCMAKE_CXX_FLAGS="/D_WINDOWS /FI\"${WINCOMPAT_H}\" /FI\"ws2tcpip.h\""
-Dpicoquic_BUILD_TESTS=OFF
-Wno-dev)
if [ -n "$CRYPTO_LIB" ] && [ -n "$SSL_LIB" ]; then
CMAKE_ARGS+=(
-DOPENSSL_ROOT_DIR="$OPENSSL_PATH"
-DOPENSSL_CRYPTO_LIBRARY="$CRYPTO_LIB"
-DOPENSSL_SSL_LIBRARY="$SSL_LIB"
-DOPENSSL_INCLUDE_DIR="$OPENSSL_PATH/include")
fi
# Initial configure to fetch picotls
cmake "${CMAKE_ARGS[@]}" || true
# Patch picotls
PTLS_SRC="$PICOQUIC_BUILD_DIR/_deps/picotls-src"
PTLS_CMAKE="$PTLS_SRC/CMakeLists.txt"
if [ -f "$PTLS_CMAKE" ]; then
sed -i 's/CMAKE_MINIMUM_REQUIRED(VERSION [0-9.]*)/CMAKE_MINIMUM_REQUIRED(VERSION 3.15)/' "$PTLS_CMAKE" || true
fi
# Copy wincompat.h to picotls directories
WINCOMPAT_FILE=$(find "$PTLS_SRC" -name "wincompat.h" 2>/dev/null | head -1)
if [ -n "$WINCOMPAT_FILE" ]; then
cp "$WINCOMPAT_FILE" "$PTLS_SRC/include/" 2>/dev/null || true
cp "$WINCOMPAT_FILE" "$PTLS_SRC/lib/" 2>/dev/null || true
fi
# Add wincompat.c for wintimeofday implementation
WINCOMPAT_C_SRC="${GITHUB_WORKSPACE}/patches/wincompat.c"
if [ -f "$WINCOMPAT_C_SRC" ]; then
cp "$WINCOMPAT_C_SRC" "$PTLS_SRC/lib/wincompat.c"
cat >> "$PTLS_CMAKE" << 'EOF'
# Windows compatibility: add wintimeofday implementation
if(WIN32)
target_sources(picotls-core PRIVATE lib/wincompat.c)
endif()
EOF
fi
# Patch picoquic header for Windows function signature
PICOQUIC_HEADER="${PICOQUIC_DIR}/picoquic/picoquic_packet_loop.h"
if [ -f "$PICOQUIC_HEADER" ]; then
awk '/^void\* picoquic_packet_loop_v3\(void\* v_ctx\);$/ {
print "#ifdef _WINDOWS"
print "DWORD WINAPI picoquic_packet_loop_v3(LPVOID v_ctx);"
print "#else"
print "void* picoquic_packet_loop_v3(void* v_ctx);"
print "#endif"
next
} {print}' "$PICOQUIC_HEADER" > "${PICOQUIC_HEADER}.tmp" && mv "${PICOQUIC_HEADER}.tmp" "$PICOQUIC_HEADER"
fi
# Build
cmake "${CMAKE_ARGS[@]}"
cmake --build "$PICOQUIC_BUILD_DIR" --config Release \
--target picoquic-core picotls-core picotls-fusion picotls-minicrypto picotls-openssl
# Create .a symlinks for build.rs (expects Unix library names)
RELEASE_DIR="$PICOQUIC_BUILD_DIR/Release"
PTLS_RELEASE="${PICOQUIC_BUILD_DIR}/_deps/picotls-build/Release"
for lib in picoquic-core picotls-core picotls-fusion picotls-minicrypto picotls-openssl; do
src_dir="$RELEASE_DIR"
[ "$lib" != "picoquic-core" ] && src_dir="$PTLS_RELEASE"
if [ -f "$src_dir/${lib}.lib" ]; then
cp "$src_dir/${lib}.lib" "$RELEASE_DIR/lib${lib}.a"
cp "$src_dir/${lib}.lib" "$RELEASE_DIR/lib${lib//-/_}.a"
fi
done
echo "PICOQUIC_DIR=$PICOQUIC_DIR" >> $GITHUB_ENV
echo "PICOQUIC_BUILD_DIR=$PICOQUIC_BUILD_DIR" >> $GITHUB_ENV
echo "PICOQUIC_LIB_DIR=$RELEASE_DIR" >> $GITHUB_ENV
- name: Apply patches for macOS
if: runner.os == 'macOS'
working-directory: slipstream-rust
shell: bash
run: |
# Patch slipstream-ffi cross compiler env handling (x86_64 only)
if [[ "${{ matrix.target }}" == "x86_64-apple-darwin" ]]; then
CC_RS="crates/slipstream-ffi/build/cc.rs"
if [ ! -f "$CC_RS" ]; then
echo "Error: Missing file: $CC_RS"
exit 1
fi
# Check if already patched
if ! grep -q "CC_\"" "$CC_RS" && ! grep -q "CC_{target_key}" "$CC_RS"; then
# Patch resolve_cc and resolve_ar functions to honor CC_<target>/AR_<target>
perl -i -pe '
if (/^pub\(crate\) fn resolve_cc\(target: &str\) -> String \{$/) {
$_ .= "\n let target_key = target.replace('\''-'\'', \"_\");\n let cc_target_key = format!(\"CC_{}\", target_key);\n if let Ok(cc) = env::var(&cc_target_key) {\n return cc;\n }";
}
' "$CC_RS"
perl -i -pe '
if (/^pub\(crate\) fn resolve_ar\(target: &str, cc: &str\) -> String \{$/) {
$_ .= "\n let target_key = target.replace('\''-'\'', \"_\");\n let ar_target_key = format!(\"AR_{}\", target_key);\n if let Ok(ar) = env::var(&ar_target_key) {\n return ar;\n }";
}
' "$CC_RS"
fi
fi
# Patch macOS sockaddr compatibility
for file in "crates/slipstream-ffi/src/runtime.rs" "crates/slipstream-server/src/server.rs" "crates/slipstream-server/src/udp_fallback.rs"; do
if [ -f "$file" ] && ! grep -q "sin_len:" "$file"; then
perl -i -pe 's/(let sockaddr = libc::sockaddr_in \{)/$1\n sin_len: std::mem::size_of::<libc::sockaddr_in>() as u8,/' "$file"
perl -i -pe 's/(let sockaddr = libc::sockaddr_in6 \{)/$1\n sin6_len: std::mem::size_of::<libc::sockaddr_in6>() as u8,/' "$file"
fi
done
- name: Apply patches for Windows
if: runner.os == 'Windows'
working-directory: slipstream-rust
shell: bash
run: |
# Patch picoquic headers
PICOQUIC_DIR="${GITHUB_WORKSPACE}/slipstream-rust/vendor/picoquic"
# Update Windows check to include MinGW defines
sed -i 's/#ifdef _WINDOWS/#if defined(_WINDOWS) || defined(__WIN32__) || defined(__MINGW32__) || defined(_WIN32)/' \
"$PICOQUIC_DIR/picoquic/picoquic.h" || true
# Patch headers that include arpa/inet.h directly
HEADER_FILE="${PICOQUIC_DIR}/picoquic/picosocks.h"
if [ -f "$HEADER_FILE" ]; then
awk '{
if ($0 == "#include <arpa/inet.h>") {
print "#if defined(_WINDOWS) || defined(__WIN32__) || defined(__MINGW32__) || defined(_WIN32)"
print "#include <winsock2.h>"
print "#else"
print "#include <arpa/inet.h>"
print "#endif"
} else { print }
}' "$HEADER_FILE" > "${HEADER_FILE}.tmp" && mv "${HEADER_FILE}.tmp" "$HEADER_FILE"
fi
# Patch build.rs for Windows
BUILD_RS="crates/slipstream-ffi/build.rs"
if [ -f "$BUILD_RS" ]; then
# Add is_windows definition after target
sed -i 's/let target = env::var("TARGET").unwrap_or_default();/let target = env::var("TARGET").unwrap_or_default();\n let is_windows = target.contains("windows") || target.contains("pc-windows");/' "$BUILD_RS"
# Replace ssl/crypto linking with Windows-aware version
sed -i 's/println!("cargo:rustc-link-lib=dylib=ssl");/if is_windows {\n if let Ok(openssl_lib_dir) = env::var("OPENSSL_LIB_DIR") {\n println!("cargo:rustc-link-search=native={}", openssl_lib_dir);\n }\n println!("cargo:rustc-link-lib=dylib=libssl");\n println!("cargo:rustc-link-lib=dylib=libcrypto");\n } else {\n println!("cargo:rustc-link-lib=dylib=ssl");\n println!("cargo:rustc-link-lib=dylib=crypto");\n }/' "$BUILD_RS"
sed -i '/println!("cargo:rustc-link-lib=dylib=crypto");/d' "$BUILD_RS"
# Replace pthread with ws2_32 on Windows
sed -i 's/println!("cargo:rustc-link-lib=dylib=pthread");/if is_windows {\n println!("cargo:rustc-link-lib=dylib=ws2_32");\n } else {\n println!("cargo:rustc-link-lib=dylib=pthread");\n }/' "$BUILD_RS"
fi
# Apply patches from patches directory
for patch_file in "${GITHUB_WORKSPACE}/patches/picoquic_utils.h.patch" "${GITHUB_WORKSPACE}/patches/Cargo.toml.patch"; do
if [ -f "$patch_file" ]; then
sed -i 's/\r$//' "$patch_file"
patch -p1 < "$patch_file" || patch -p1 --merge < "$patch_file" || exit 1
fi
done
# Apply Windows socket patch script
if [ -f "${GITHUB_WORKSPACE}/patches/apply_windows_socket_patch.sh" ]; then
bash "${GITHUB_WORKSPACE}/patches/apply_windows_socket_patch.sh"
fi
- name: Build slipstream binaries
if: runner.os != 'Linux' || !contains('aarch64-unknown-linux-gnu,armv7-unknown-linux-gnueabihf,riscv64gc-unknown-linux-gnu,mips64-unknown-linux-gnuabi64,mips64el-unknown-linux-gnuabi64,mips-unknown-linux-gnu,mipsel-unknown-linux-gnu', matrix.target)
working-directory: slipstream-rust
shell: bash
env:
PICOQUIC_FETCH_PTLS: ON
PICOQUIC_AUTO_BUILD: 1
run: |
# macOS ARM64 native build
if [[ "${{ matrix.target }}" == "aarch64-apple-darwin" ]]; then
export OPENSSL_LIB_DIR=/opt/homebrew/opt/openssl@3/lib
export OPENSSL_INCLUDE_DIR=/opt/homebrew/opt/openssl@3/include
export CARGO_TARGET_AARCH64_APPLE_DARWIN_RUSTFLAGS="-C link-arg=-L/opt/homebrew/opt/openssl@3/lib"
fi
# macOS Intel cross-compilation from ARM64 runner
if [[ "${{ matrix.target }}" == "x86_64-apple-darwin" ]]; then
export MACOSX_DEPLOYMENT_TARGET=10.12
mkdir -p /tmp/cross-bin
printf '#!/bin/bash\nexec clang -arch x86_64 -mmacosx-version-min=10.12 "$@"\n' > /tmp/cross-bin/x86_64-cc
printf '#!/bin/bash\nexec clang++ -arch x86_64 -mmacosx-version-min=10.12 "$@"\n' > /tmp/cross-bin/x86_64-c++
chmod +x /tmp/cross-bin/x86_64-cc /tmp/cross-bin/x86_64-c++
export CC_x86_64_apple_darwin=/tmp/cross-bin/x86_64-cc
export CXX_x86_64_apple_darwin=/tmp/cross-bin/x86_64-c++
export CFLAGS_x86_64_apple_darwin="-arch x86_64 -mmacosx-version-min=10.12"
export CXXFLAGS_x86_64_apple_darwin="-arch x86_64 -mmacosx-version-min=10.12"
export OPENSSL_LIB_DIR=/usr/local/opt/openssl@3/lib
export OPENSSL_INCLUDE_DIR=/usr/local/opt/openssl@3/include
export CARGO_TARGET_X86_64_APPLE_DARWIN_RUSTFLAGS="-C link-arg=-L/usr/local/opt/openssl@3/lib -C link-arg=-arch -C link-arg=x86_64"
fi
# Use vendored OpenSSL for Windows; Linux alternate arches use Docker
if [[ "${{ runner.os }}" == "Windows" ]]; then
cargo build --release --target ${{ matrix.target }} -p slipstream-client -p slipstream-server --features openssl-vendored
else
cargo build --release --target ${{ matrix.target }} -p slipstream-client -p slipstream-server
fi
- name: Prepare binaries
shell: bash
run: |
set -e
mkdir -p build_assets
TARGET_DIR="slipstream-rust/target/${{ matrix.target }}/release"
CLIENT_BIN="$TARGET_DIR/slipstream-client${{ env.EXE_EXT }}"
SERVER_BIN="$TARGET_DIR/slipstream-server${{ env.EXE_EXT }}"
echo "Checking for binaries..."
echo "Target directory: $TARGET_DIR"
echo "Client binary: $CLIENT_BIN"
echo "Server binary: $SERVER_BIN"
# Check if target directory exists
if [ ! -d "$TARGET_DIR" ]; then
echo "ERROR: Target directory does not exist: $TARGET_DIR"
echo "Contents of slipstream-rust/target/:"
ls -la "slipstream-rust/target/" || true
exit 1
fi
# Check for client binary
if [ ! -f "$CLIENT_BIN" ]; then
echo "ERROR: Client binary not found at $CLIENT_BIN"
echo "Looking for files matching 'slipstream-client*':"
find "$TARGET_DIR" -name "slipstream-client*" -type f || true
exit 1
fi
# Check for server binary
if [ ! -f "$SERVER_BIN" ]; then
echo "ERROR: Server binary not found at $SERVER_BIN"
echo "Looking for files matching 'slipstream-server*':"
find "$TARGET_DIR" -name "slipstream-server*" -type f || true
exit 1
fi
echo "Copying binaries..."
cp "$CLIENT_BIN" "build_assets/slipstream-client-${{ env.ASSET_NAME }}${{ env.EXE_EXT }}"
cp "$SERVER_BIN" "build_assets/slipstream-server-${{ env.ASSET_NAME }}${{ env.EXE_EXT }}"
[ "${{ runner.os }}" != "Windows" ] && chmod +x build_assets/*
echo "Binaries prepared successfully"
- name: Create release if needed
shell: bash
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
TAG="${{ steps.get_commit.outputs.short_commit }}"
if ! gh release view "$TAG" &>/dev/null; then
gh release create "$TAG" \
--title "Release $TAG" \
--notes "Release for slipstream-rust commit $TAG
This release contains prebuilt binaries for:
- Linux (x86_64, ARM64, ARMv7, RISC-V 64, MIPS64, MIPS64LE, MIPS, MIPSLE)
- Windows (x86_64)
- macOS (ARM64)
- macOS (Intel x86_64)"
fi
- name: Upload binaries to release
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: build_assets/slipstream-*
file_glob: true
tag: ${{ steps.get_commit.outputs.short_commit }}
overwrite: true
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: slipstream-${{ env.ASSET_NAME }}
path: build_assets/slipstream-*
retention-days: 7