Files
hakorune/docs/guides/build/cross-platform.md

7.4 KiB

🌍 Cross-Platform Development Guide

How to build and distribute Nyash applications across Windows, Linux, and macOS.

🎯 Philosophy: Write Once, Run Everywhere

Nyash achieves true cross-platform compatibility through:

  • Platform-agnostic configuration (nyash.toml)
  • Automatic library resolution (plugin loader)
  • Unified plugin system (C ABI)

🔄 Cross-Platform Plugin Loading

The Magic Behind It

ChatGPT5's resolve_library_path implementation in src/runtime/plugin_loader_v2.rs:

// Automatic extension mapping
let cur_ext: &str = if cfg!(target_os = "windows") { "dll" } 
                   else if cfg!(target_os = "macos") { "dylib" } 
                   else { "so" };

// Windows: try without 'lib' prefix
if cfg!(target_os = "windows") {
    if let Some(stripped) = stem.strip_prefix("lib") {
        // Try nyash_plugin.dll instead of libnyash_plugin.dll
    }
}

Configuration That Works Everywhere

# nyash.toml - Same file works on all platforms!
[libraries."libnyash_filebox_plugin.so"]
boxes = ["FileBox"]
path = "libnyash_filebox_plugin.so"  # .so works everywhere!

Runtime Resolution:

  • Linux: libnyash_filebox_plugin.so
  • Windows: nyash_filebox_plugin.dll (lib prefix removed)
  • macOS: libnyash_filebox_plugin.dylib

🏗️ Building for Multiple Platforms

# For Linux (native)
cargo build --release

# For Windows
cargo xwin build --target x86_64-pc-windows-msvc --release

# For macOS (requires macOS SDK)
# cargo build --target x86_64-apple-darwin --release

Build Matrix

Host OS Target Tool Command
Linux/WSL Linux cargo cargo build --release
Linux/WSL Windows cargo-xwin cargo xwin build --target x86_64-pc-windows-msvc
Windows Windows cargo cargo build --release
Windows Linux cross cross build --target x86_64-unknown-linux-gnu
macOS macOS cargo cargo build --release
macOS Linux cross cross build --target x86_64-unknown-linux-gnu

📦 Creating Universal Distributions

Directory Structure

nyash-universal/
├── bin/
│   ├── linux/
│   │   └── nyash
│   ├── windows/
│   │   └── nyash.exe
│   └── macos/
│       └── nyash
├── plugins/
│   ├── linux/
│   │   ├── libnyash_filebox_plugin.so
│   │   └── ...
│   ├── windows/
│   │   ├── nyash_filebox_plugin.dll
│   │   └── ...
│   └── macos/
│       ├── libnyash_filebox_plugin.dylib
│       └── ...
├── nyash.toml          # Universal config
├── examples/
└── README.md

Universal Launcher Script

Create run.sh (Linux/macOS) and run.bat (Windows):

run.sh:

#!/bin/bash
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
OS="$(uname -s)"

case "$OS" in
    Linux*)  BIN="linux/nyash" ;;
    Darwin*) BIN="macos/nyash" ;;
    *)       echo "Unsupported OS: $OS"; exit 1 ;;
esac

export NYASH_PLUGIN_PATH="$SCRIPT_DIR/plugins/$(echo $OS | tr '[:upper:]' '[:lower:]')"
"$SCRIPT_DIR/bin/$BIN" "$@"

run.bat:

@echo off
set SCRIPT_DIR=%~dp0
set NYASH_PLUGIN_PATH=%SCRIPT_DIR%plugins\windows
"%SCRIPT_DIR%bin\windows\nyash.exe" %*

🔌 Plugin Compatibility

Building Plugins for All Platforms

Automated build script (build_all_plugins.sh):

#!/bin/bash
PLUGINS="filebox array map string integer net"

for plugin in $PLUGINS; do
    echo "Building $plugin plugin..."
    cd "plugins/nyash-$plugin-plugin" || exit 1
    
    # Linux
    cargo build --release
    cp target/release/lib*.so ../../dist/plugins/linux/
    
    # Windows (from WSL)
    cargo xwin build --target x86_64-pc-windows-msvc --release
    cp target/x86_64-pc-windows-msvc/release/*.dll ../../dist/plugins/windows/
    
    cd ../..
done

Plugin ABI Stability

The C ABI ensures plugins work across platforms:

// Standard C ABI functions (same on all platforms)
extern "C" {
    fn nyash_plugin_abi_version() -> u32;
    fn nyash_plugin_init(host_fns: *const HostFunctions) -> i32;
    fn nyash_plugin_invoke(params: *const InvokeParams) -> i32;
    fn nyash_plugin_shutdown();
}

🎯 Testing Cross-Platform Builds

Test Matrix Script

#!/bin/bash
# test_all_platforms.sh

echo "=== Testing Linux Build ==="
./target/release/nyash test/cross_platform.hako

echo "=== Testing Windows Build (Wine) ==="
wine ./target/x86_64-pc-windows-msvc/release/nyash.exe test/cross_platform.hako

echo "=== Testing WASM Build ==="
wasmtime ./target/wasm32-wasi/release/nyash.wasm test/cross_platform.hako

Cross-Platform Test Program

// test/cross_platform.hako
print("Platform Test Starting...")

// Test basic plugins
local arr = new ArrayBox()
arr.push("Cross")
arr.push("Platform")
arr.push("Success!")
print("Array test: " + arr.get(0) + "-" + arr.get(1) + " " + arr.get(2))

// Test file operations (platform-specific paths)
local file = new FileBox()
if file {
    print("FileBox available on this platform")
}

print("✅ All tests passed!")

🚀 CI/CD for Cross-Platform

GitHub Actions Example

name: Cross-Platform Build

on: [push, pull_request]

jobs:
  build:
    strategy:
      matrix:
        include:
          - os: ubuntu-latest
            target: x86_64-unknown-linux-gnu
          - os: windows-latest
            target: x86_64-pc-windows-msvc
          - os: macos-latest
            target: x86_64-apple-darwin
    
    runs-on: ${{ matrix.os }}
    
    steps:
    - uses: actions/checkout@v2
    
    - name: Install Rust
      uses: actions-rs/toolchain@v1
      with:
        toolchain: stable
        target: ${{ matrix.target }}
    
    - name: Build
      run: cargo build --release --target ${{ matrix.target }}
    
    - name: Test
      run: cargo test --release --target ${{ matrix.target }}
    
    - name: Upload artifacts
      uses: actions/upload-artifact@v2
      with:
        name: nyash-${{ matrix.target }}
        path: target/${{ matrix.target }}/release/nyash*

💡 Best Practices

1. Always Test on Target Platform

# Quick test after cross-compile
wine ./nyash.exe --version  # Windows binary on Linux

2. Use Platform-Agnostic Paths

// Bad
local file = new FileBox()
file.open("C:\\data\\file.txt", "r")  // Windows-specific

// Good
local file = new FileBox()
file.open("./data/file.txt", "r")  // Works everywhere

3. Handle Platform Differences Gracefully

box PlatformHelper {
    static getPlatformName() {
        // Future: return actual platform
        return "universal"
    }
    
    static getPathSeparator() {
        // Future: return platform-specific separator
        return "/"
    }
}

🔧 Troubleshooting

"Can't find plugin" after cross-compile

  • Check file naming (lib prefix on Windows)
  • Verify correct architecture (x86_64 vs ARM)
  • Use --verbose flag for detailed logs

Different behavior across platforms

  • File path separators (/ vs \)
  • Case sensitivity (Linux/macOS vs Windows)
  • Line endings (LF vs CRLF)

Performance variations

  • Debug vs Release builds
  • Native CPU optimizations
  • Plugin loading overhead

📚 References