# msger Build System

## Overview

The msger build system is unified and configuration-driven, supporting multiple platforms through a single entry point.

## Build Configuration

Build targets are controlled via `msger-native/builder/build-config.json`:

```json
{
    "platforms": {
        "windows": true,    // Windows x64 binary
        "wsl": false,       // Linux x64 binary (via WSL)
        "pi": false,        // Raspberry Pi ARM64 (via SSH)
        "arm64": false      // Generic ARM64 (cross-compile in WSL)
    },
    "options": {
        "release": true,
        "verbose": false,
        "piHost": "pi4c",
        "piProjectPath": "/home/bob/projects/msger/msger-native"
    }
}
```

## Build Commands

### Standard Build
```bash
npm run build              # Build TypeScript + native binaries
npm run build:ts           # Build TypeScript only
npm run build:native       # Build native binaries only
```

### Release & Publish
```bash
npm run release            # Bump version, build, publish to npm
npm run installer          # Release + install globally (Windows & WSL)
```

## Platform-Specific Details

### Windows (x64)
- Built using native Rust toolchain
- Requires Visual Studio Build Tools or MSVC
- Output: `msger-native/bin/msgernative.exe`
- Auto-detects source changes to skip unnecessary rebuilds

### WSL Linux (x64)
- Builds Linux binary inside WSL
- Runs `msger-native/builder/build-under-wsl.ts` via WSL
- Output: `msger-native/bin/msgernative`
- Requires WSL with Rust installed

### Raspberry Pi (ARM64)
- Builds on remote Raspberry Pi via SSH
- Requires:
  - SSH access to Pi (`piHost` in config)
  - Project synced to Pi (`piProjectPath` in config)
  - Rust installed on Pi
- Output: `msger-native/bin/msgernative-linux-aarch64`
- See [PI-RENDERING-NOTES.md](PI-RENDERING-NOTES.md) for Pi-specific details

### Generic ARM64 (Cross-compile)
- Cross-compiles ARM64 binary in WSL
- Automatically installs dependencies:
  1. Rust (via `install-rust-wsl.sh`)
  2. ARM64 toolchain (via `setup-arm64-toolchain.sh`)
- Output: `msger-native/bin/msgernative-linux-aarch64`
- Uses `aarch64-unknown-linux-gnu` target

## Build Scripts

### Main Builder
**Location**: `msger-native/builder/builder.ts`

Unified build orchestrator that:
- Reads `build-config.json`
- Detects source changes
- Coordinates platform-specific builds
- Reports build summary

**Key Features**:
- `wslExec()`: Executes commands in WSL using spawn (avoids quoting issues)
- `toWSLPath()`: Converts Windows paths to WSL paths
- `needsRebuild()`: Checks if sources changed since last build
- Automatic Rust installation for ARM64 builds

### WSL Builder
**Location**: `msger-native/builder/build-under-wsl.ts`

Runs natively inside WSL to build Linux binaries:
- Supports both x64 and ARM64 targets
- Auto-installs Rust toolchains
- Handles cross-compilation setup

### Helper Scripts

#### `install-rust-wsl.sh`
Installs Rust in WSL if not present:
```bash
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
```

#### `setup-arm64-toolchain.sh`
Sets up ARM64 cross-compilation in WSL:
- Installs `aarch64-unknown-linux-gnu` Rust target
- Installs ARM64 cross-compiler (`gcc-aarch64-linux-gnu`)
- Configures cargo for cross-compilation

#### `build-on-pi.sh`
Helper for remote Pi builds (called via SSH)

## Important Considerations

### Line Endings
- All `.sh` scripts MUST use LF (Unix) line endings
- `.gitattributes` enforces this: `*.sh text eol=lf`
- Use `dos2unix` to fix if needed

### Path Handling
- Use `wslExec()` and `toWSLPath()` for WSL operations
- Avoids shell quoting issues
- Properly converts Windows → WSL paths

### Postinstall Hook
- **Location**: `msger-native/builder/postinstall.js`
- **Must be .js**: Node.js can't execute .ts in node_modules
- Sets executable permissions on Linux binaries
- Checks for system dependencies (webkit2gtk, gtk3)

### TypeScript Compilation
- TypeScript source lives alongside compiled .js files
- Includes .map files for debugging
- All checked into git for production debugging

## Troubleshooting

### ARM64 Build Fails
1. Check Rust installed in WSL: `wsl rustup --version`
2. If not, run manually: `wsl bash msger-native/pibuild/install-rust-wsl.sh`
3. Check toolchain: `wsl rustup target list --installed | grep aarch64`

### WSL Path Conversion Fails
- Ensure WSL installed and accessible
- Test: `wsl wslpath "Y:\dev\utils\msger"`
- Should output: `/mnt/y/dev/utils/msger`

### Pi Build Fails
1. Test SSH: `ssh pi4c echo test`
2. Check project exists on Pi: `ssh pi4c ls /home/bob/projects/msger`
3. Verify Rust on Pi: `ssh pi4c rustc --version`

## Build Flow Diagram

```
npm run build
    ↓
npm run build:ts (compile TypeScript)
    ↓
npm run build:native
    ↓
msger-native/builder/builder.ts
    ↓
    ├─→ Windows? → cargo build --release
    ├─→ WSL? → wsl build-under-wsl.ts → cargo build (x64)
    ├─→ Pi? → ssh pi4c "cargo build" → scp binary
    └─→ ARM64? → install Rust → setup toolchain → cargo build (aarch64)
```

## Adding New Platforms

1. Add platform flag to `build-config.json`
2. Create build function in `builder.ts`
3. Add case to `main()` function
4. Update this documentation
5. Test on target platform

## ARM64 Build Debugging Notes (2025-11-17)

### Issues Fixed

#### 1. Path Conversion (Y: to /mnt/y)
**Problem**: wslpath failed when given Windows paths with backslashes
**Fix**: `toWSLPath()` now converts backslashes to forward slashes
**Location**: builder.ts:74-83

#### 2. wslExec Function
**Problem**: Was double-wrapping bash commands causing syntax errors
**Fix**: Simplified to pass args directly to spawnSync
**Location**: builder.ts:58-69

#### 3. PATH with Parentheses
**Problem**: Windows PATH contains "Program Files (x86)" causing bash syntax errors
**Fix**: Quoted all PATH and directory references in bash commands
**Location**: builder.ts:217, 360

#### 4. Cargo Version Mismatch
**Problem**: System cargo in WSL (1.75) incompatible with Windows cargo (1.87) Cargo.lock v4
**Fix**: Always use rustup's cargo by setting `PATH="$HOME/.cargo/bin:$PATH"`

#### 5. Toolchain Detection After Install
**Problem**: `checkARM64Toolchain()` couldn't find rustup immediately after installation
**Fix**: Check now includes PATH setup
**Location**: builder.ts:288-293

#### 6. pkg-config Cross-Compilation
**Problem**: pkg-config not configured for ARM64 cross-compilation
**Fix**: Set `PKG_CONFIG_ALLOW_CROSS=1` and created `~/.cargo/config.toml` with linker
**Location**: setup-arm64-toolchain.sh:60-66

#### 7. Silent Compilation
**Problem**: Long compilation appeared stuck with no output
**Fix**: Added "Compiling ARM64 binary (this may take 2-5 minutes)..." message
**Location**: builder.ts:355

### Key Implementation Details

#### Auto-Installation Flow
1. `buildARM64()` calls `checkARM64Toolchain()`
2. If false, calls `installARM64Toolchain()`
3. `installARM64Toolchain()` checks for rustup:
   - If missing: runs `install-rust-wsl.sh`
   - Always runs `setup-arm64-toolchain.sh`
4. Both scripts are idempotent (safe to run multiple times)

#### Build Command Structure
```bash
export PATH="$HOME/.cargo/bin:$PATH" && \
export PKG_CONFIG_ALLOW_CROSS=1 && \
cd "/mnt/y/dev/utils/msger/msger-native" && \
cargo build --release --target aarch64-unknown-linux-gnu
```

#### 8. ARM64 Cross-Compilation Not Viable
**Problem**: Cannot install ARM64 packages on x64 WSL - Ubuntu repos return 404 for ARM64 packages
**Root Cause**: `dpkg --add-architecture arm64` only works on native multi-arch systems, not WSL
**Attempted Fix**: Tried installing ARM64 library packages - repos don't exist for x64→ARM64
**Solution**: Use Pi build option instead - builds natively on ARM64 hardware via SSH
**Conclusion**: Cross-compiling GUI apps (webkit2gtk) from x64→ARM64 requires complex sysroot setup. Native Pi build is simpler and more reliable.

### Important Notes
- System cargo (old 1.75) vs rustup cargo (new 1.91) - always use rustup
- Spawn with arg arrays avoids shell quoting issues with paths containing spaces/parentheses
- **Build process must be defensive**: Check for required tools/dependencies on every build, auto-install if missing
- Build checks every time, only installs if missing - not a one-time setup
- `PKG_CONFIG_ALLOW_CROSS` required for cross-compilation
- **ARM64 cross-compile from x64 WSL not supported** - use Pi build instead
- **Pi build must auto-install Rust if missing** - cannot assume Pi environment is configured
- Pi build copies only source files (src/, Cargo.toml, Cargo.lock, build.rs), copies back only binary
- No rsync on Windows - use scp for Pi file transfers
- Compilation takes 2-5 minutes on typical hardware
