From b599cb862e39800e594034b1d2e6b68cd1cb7879 Mon Sep 17 00:00:00 2001 From: TachibanaLolo Date: Fri, 9 Jan 2026 05:29:33 +0800 Subject: [PATCH] feat: add RISC-V packaging support This commit introduces comprehensive support for packaging Netcatty for RISC-V architecture. Changes: - Added 'scripts/pack-riscv.sh': A unified script for building, assembling, and packaging the application into .deb files for RISC-V. It supports standard and debug builds (with --disable-gpu). - Added 'scripts/get-config.cjs': A helper script to read configuration from package.json and electron-builder.json, ensuring consistency across builds. - Added 'RISCV_README.md': Documentation for building and running Netcatty on RISC-V devices. - Updated 'package.json': Added 'pack:riscv' script. - Removed obsolete scripts ('scripts/mkdeb-riscv.sh', 'scripts/monitor-pack.sh'). The new packaging flow avoids app.asar for better compatibility on some RISC-V boards and provides a clean separation between build assembly and package generation. --- RISCV_README.md | 109 +++++++++++++++++++++ package.json | 1 + scripts/get-config.cjs | 31 ++++++ scripts/pack-riscv.sh | 208 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 349 insertions(+) create mode 100644 RISCV_README.md create mode 100644 scripts/get-config.cjs create mode 100755 scripts/pack-riscv.sh diff --git a/RISCV_README.md b/RISCV_README.md new file mode 100644 index 00000000..98cdd3ac --- /dev/null +++ b/RISCV_README.md @@ -0,0 +1,109 @@ +# Netcatty RISC-V Build Guide + +This document describes how to build and package Netcatty for the RISC-V (riscv64) architecture. Since Electron does not officially support RISC-V yet, we rely on community builds and manual packaging. + +## Prerequisites + +### 1. Node.js (riscv64) +Official Node.js builds for RISC-V are not always available or up-to-date. We recommend using the unofficial builds which are tested on actual RISC-V hardware. + +* **Download Source**: [gounthar/unofficial-builds](https://github.com/gounthar/unofficial-builds/releases) +* **Recommendation**: Download the latest `.deb` package (e.g., v22.x or v24.x) and install it: + ```bash + wget https://github.com/gounthar/unofficial-builds/releases/download/v24.12.0/nodejs-unofficial_24.12.0-1_riscv64.deb + sudo dpkg -i nodejs-unofficial_*.deb + ``` + +### 2. Electron Binary (riscv64) +You need a pre-built Electron binary for RISC-V. +* **Download Source**: [riscv-forks/electron-riscv-releases](https://github.com/riscv-forks/electron-riscv-releases/releases) +* **Version**: Ensure you download a version matching our `package.json` (currently **v39.2.7** or compatible v39.x). +* **Setup**: + 1. Download `electron-v39.2.7-linux-riscv64.zip`. + 2. Extract it to a known location (e.g., `~/electron-riscv`). + 3. This folder will serve as the "host" for our application. + +### 3. System Dependencies +Install build tools required for compiling native modules (like `node-pty`, `serialport`) and runtime libraries. + +```bash +sudo apt update +sudo apt install build-essential python3 pkg-config libsecret-1-dev +``` + +*Note: Building native modules requires significant RAM. If you have <8GB RAM, we strongly recommend setting up a 4GB Swap file to avoid compilation crashes.* + +## Building & Packaging + +We provide scripts to automate the build and packaging process. + +### 1. Build and Generate `.deb` Packages (Recommended) +This method generates ready-to-install Debian packages. + +1. **Clone & Install Dependencies**: + ```bash + git clone https://github.com/your-repo/netcatty.git + cd netcatty + npm install + ``` + +2. **Set Environment Variable**: + Tell the script where your Electron binary is located. + ```bash + export ELECTRON_RISCV_DIST="$HOME/electron-riscv" + ``` + +3. **Run the Build Script**: + ```bash + ./scripts/pack-riscv.sh # Generates app.asar + ./scripts/mkdeb-riscv.sh # Generates .deb packages + ``` + + This will produce two packages in the `release/` directory: + * `netcatty_x.x.x_riscv64.deb`: Standard version. + * `netcatty-debug_x.x.x_riscv64.deb`: **Safe Mode version** (runs with `--disable-gpu --no-sandbox`). + +### 2. Installation +Install the package suitable for your board. + +* **For most RISC-V boards (Spacemit K1, Lichee Pi 4A, etc.)**: + The GPU drivers might be unstable with Electron. Use the **debug** package if you encounter rendering issues (black screen, flickering). + ```bash + sudo dpkg -i release/netcatty-debug_*.deb + ``` + +* **For boards with working GPU acceleration**: + ```bash + sudo dpkg -i release/netcatty_*.deb + ``` + +## Troubleshooting + +### "Bus error" or Compilation Crashes +This usually means you ran out of memory during `npm install` or `npm rebuild`. +**Fix**: Add Swap space. +```bash +sudo fallocate -l 4G /swapfile +sudo chmod 600 /swapfile +sudo mkswap /swapfile +sudo swapon /swapfile +``` + +### "Cannot find module .../pty.node" +This happens if the native modules were compiled for the system Node.js version instead of Electron's internal Node.js version. +**Fix**: Rebuild native modules for Electron. +```bash +# Inside netcatty directory +export npm_config_runtime=electron +export npm_config_target=39.2.7 # Match your Electron version +export npm_config_disturl=https://electronjs.org/headers +npm rebuild @serialport/bindings-cpp node-pty --build-from-source +``` + +### Graphical Glitches / Black Window +Electron often has trouble with current RISC-V GPU drivers (PowerVR, Imagination, etc.). +**Fix**: Run with GPU disabled. +```bash +netcatty --disable-gpu --no-sandbox +``` +*Note: The `netcatty-debug` package applies these flags automatically.* diff --git a/package.json b/package.json index 1167945f..55e14c84 100755 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "pack:win": "npm run build && cross-env NODE_OPTIONS=--disable-warning=DEP0190 electron-builder --config electron-builder.json --win --publish=never", "pack:mac": "npm run build && cross-env NODE_OPTIONS=--disable-warning=DEP0190 electron-builder --config electron-builder.json --mac --publish=never", "pack:linux": "npm run build && cross-env NODE_OPTIONS=--disable-warning=DEP0190 electron-builder --config electron-builder.json --linux --publish=never", + "pack:riscv": "./scripts/pack-riscv.sh", "postinstall": "electron-builder install-app-deps", "rebuild": "electron-builder install-app-deps", "lint": "eslint .", diff --git a/scripts/get-config.cjs b/scripts/get-config.cjs new file mode 100644 index 00000000..01ca9a09 --- /dev/null +++ b/scripts/get-config.cjs @@ -0,0 +1,31 @@ +const fs = require('fs'); +const path = require('path'); + +const pkgPath = path.resolve(__dirname, '../package.json'); +const builderPath = path.resolve(__dirname, '../electron-builder.json'); + +try { + const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8')); + let builder = {}; + if (fs.existsSync(builderPath)) { + builder = JSON.parse(fs.readFileSync(builderPath, 'utf8')); + } + + const safe = (str) => (str || '').replace(/"/g, '\\"'); + + console.log(`APP_NAME="${safe(pkg.name)}"`); + console.log(`VERSION="${safe(pkg.version)}"`); + console.log(`PRODUCT_NAME="${safe(builder.productName || pkg.name)}"`); + console.log(`APP_ID="${safe(builder.appId || 'com.example.app')}"`); + console.log(`DESCRIPTION="${safe(pkg.description || '')}"`); + console.log(`AUTHOR="${safe(pkg.author || '')}"`); + console.log(`MAINTAINER="${safe(pkg.author || '')}"`); + + // Linux specific + const linux = builder.linux || {}; + console.log(`CATEGORY="${safe(linux.category || 'Utility')}"`); + +} catch (e) { + console.error('Error reading config:', e); + process.exit(1); +} diff --git a/scripts/pack-riscv.sh b/scripts/pack-riscv.sh new file mode 100755 index 00000000..ba8be18f --- /dev/null +++ b/scripts/pack-riscv.sh @@ -0,0 +1,208 @@ +#!/bin/bash +set -e + +# Load configuration +SCRIPT_DIR=$(dirname "$0") +PROJECT_ROOT=$(cd "$SCRIPT_DIR/.." && pwd) + +# Load metadata +if [ -f "$PROJECT_ROOT/scripts/get-config.cjs" ]; then + eval $(node "$PROJECT_ROOT/scripts/get-config.cjs") +else + echo "Warning: Config script not found, using defaults." + APP_NAME="netcatty" + VERSION="0.0.0" + PRODUCT_NAME="Netcatty" + MAINTAINER="binaricat" + DESCRIPTION="Netcatty SSH Client" + CATEGORY="Development" +fi + +# Configuration +ARCH="riscv64" +DIST_DIR="$PROJECT_ROOT/release/riscv_build" +OUTPUT_ROOT="$PROJECT_ROOT/release" +ELECTRON_BINARY_DIR="${ELECTRON_PATH:-$HOME/electron-riscv}" + +echo "----------------------------------------------------------------" +echo "Netcatty RISC-V Build & Pack" +echo "----------------------------------------------------------------" +echo "Product: $PRODUCT_NAME ($APP_NAME)" +echo "Version: $VERSION" +echo "Target Dir: $DIST_DIR" +echo "Electron Source: $ELECTRON_BINARY_DIR" + +# Check dependencies +if ! command -v npm >/dev/null 2>&1; then + echo "Error: npm is not installed." + exit 1 +fi + +# ============================================================================== +# Phase 1: Build & Assembly (Assembly) +# ============================================================================== + +if [ "$SKIP_ASSEMBLY" != "true" ]; then + # 1. Build Frontend + if [ "$SKIP_BUILD" != "true" ]; then + echo "Building frontend..." + cd "$PROJECT_ROOT" + npm run build + else + echo "Skipping build step (SKIP_BUILD=true)..." + fi + + # 2. Prepare Directory Structure + echo "Cleaning distribution directory..." + rm -rf "$DIST_DIR" + mkdir -p "$DIST_DIR/resources/app" + + # 3. Copy Electron Binary + if [ -f "$ELECTRON_BINARY_DIR/electron" ]; then + echo "Copying Electron binary and resources from $ELECTRON_BINARY_DIR..." + rsync -av --exclude 'resources/app' "$ELECTRON_BINARY_DIR/" "$DIST_DIR/" + else + echo "Warning: Electron binary not found at $ELECTRON_BINARY_DIR." + echo "You will need to manually place the 'electron' binary in $DIST_DIR before packaging." + fi + + # 4. Copy Application Files (No ASAR) + echo "Copying application files to resources/app..." + APP_DIR="$DIST_DIR/resources/app" + + cp "$PROJECT_ROOT/package.json" "$APP_DIR/" + cp -r "$PROJECT_ROOT/electron" "$APP_DIR/" + cp -r "$PROJECT_ROOT/dist" "$APP_DIR/" + + # 5. Handle node_modules (Clean & Production) + echo "Handling node_modules..." + if [ -d "$PROJECT_ROOT/node_modules" ]; then + echo "Copying node_modules..." + cp -r "$PROJECT_ROOT/node_modules" "$APP_DIR/" + + if [ -f "$APP_DIR/package.json" ]; then + echo "Pruning development dependencies..." + cd "$APP_DIR" + npm prune --production + cd "$PROJECT_ROOT" + fi + else + echo "Warning: node_modules not found. Skipping." + fi +else + echo "Skipping assembly phase (SKIP_ASSEMBLY=true)..." +fi + +# ============================================================================== +# Phase 2: Debian Packaging +# ============================================================================== + +if [ "$SKIP_DEB" == "true" ]; then + echo "Skipping Debian package generation (SKIP_DEB=true)." + echo "Assembly completed at: $DIST_DIR" + exit 0 +fi + +SOURCE_DIR="$DIST_DIR" + +if [ ! -d "$SOURCE_DIR" ]; then + echo "Error: Source directory $SOURCE_DIR does not exist." + exit 1 +fi + +# Function to build a package +build_package() { + local PKG_NAME="$1" + local PKG_SUFFIX="$2" # e.g., "-debug" or empty + local EXTRA_FLAGS="$3" + + local DEB_DIR="$OUTPUT_ROOT/deb_dist_${PKG_NAME}" + local INSTALL_DIR="/opt/$PKG_NAME" + + echo "----------------------------------------------------------------" + echo "Building package: $PKG_NAME" + echo "Flags: $EXTRA_FLAGS" + echo "----------------------------------------------------------------" + + # Clean up previous build + rm -rf "$DEB_DIR" + mkdir -p "$DEB_DIR/DEBIAN" + mkdir -p "$DEB_DIR$INSTALL_DIR" + mkdir -p "$DEB_DIR/usr/bin" + mkdir -p "$DEB_DIR/usr/share/applications" + mkdir -p "$DEB_DIR/usr/share/icons/hicolor/512x512/apps" + + # Copy application files + echo "Copying application files..." + cp -r "$SOURCE_DIR/"* "$DEB_DIR$INSTALL_DIR/" + chmod -R 755 "$DEB_DIR$INSTALL_DIR" + + # Create wrapper script + echo "Creating wrapper script..." + if [ -f "$DEB_DIR$INSTALL_DIR/netcatty" ]; then + BIN_NAME="netcatty" + elif [ -f "$DEB_DIR$INSTALL_DIR/electron" ]; then + BIN_NAME="electron" + else + BIN_NAME=$(find "$DEB_DIR$INSTALL_DIR" -maxdepth 1 -type f -executable -printf "%s\t%p\n" | sort -n | tail -1 | awk '{print $2}' | xargs basename) + fi + + mv "$DEB_DIR$INSTALL_DIR/$BIN_NAME" "$DEB_DIR$INSTALL_DIR/$PKG_NAME-bin" + + cat > "$DEB_DIR$INSTALL_DIR/$PKG_NAME" < "$DEB_DIR/usr/share/applications/$PKG_NAME.desktop" < "$DEB_DIR/DEBIAN/control" <