feat: add experimental LoongArch desktop preview

GoodBuddy can now be cross-packaged as an isolated Debian loong64 preview with verified Electron, node-pty, and Koffi binaries. The preview remains separate from the standard release matrix and excludes Agent, Remote Runtime, OpenCode, and native Canvas until those dependencies support LoongArch.

The Chinese website identifies GoodBuddy as the first open-source desktop AI assistant with LoongArch support while clearly labeling the independently built package as a preview.

Release note: 新增龙芯 LoongArch 独立编译预览版,并提供完整构建文档;当前预览版不包含 Agent、Remote Runtime、OpenCode 和原生 Canvas。
This commit is contained in:
mesalogo
2026-08-25 18:41:35 +08:00
parent e5aebaa67d
commit 500f7d2735
13 changed files with 1294 additions and 15 deletions
+1
View File
@@ -0,0 +1 @@
results
+54
View File
@@ -0,0 +1,54 @@
FROM ubuntu:26.04
ARG DEBIAN_FRONTEND=noninteractive
ARG RUST_TOOLCHAIN=1.93.1
RUN apt-get update \
&& apt-get install --yes --no-install-recommends \
binutils-loongarch64-linux-gnu \
build-essential \
ca-certificates \
cmake \
dpkg-dev \
fakeroot \
file \
g++-loongarch64-linux-gnu \
gcc-loongarch64-linux-gnu \
libc6-dev-loong64-cross \
make \
ninja-build \
node-gyp \
nodejs \
npm \
pkg-config \
python3 \
qemu-user \
rustup \
tar \
xz-utils \
&& rm -rf /var/lib/apt/lists/*
RUN rustup set profile minimal \
&& rustup toolchain install "${RUST_TOOLCHAIN}" \
--target loongarch64-unknown-linux-gnu
ENV CC=loongarch64-linux-gnu-gcc \
CXX=loongarch64-linux-gnu-g++ \
AR=loongarch64-linux-gnu-ar \
RANLIB=loongarch64-linux-gnu-ranlib \
STRIP=loongarch64-linux-gnu-strip \
CARGO_BUILD_TARGET=loongarch64-unknown-linux-gnu \
CARGO_TARGET_LOONGARCH64_UNKNOWN_LINUX_GNU_LINKER=loongarch64-linux-gnu-gcc \
RUSTUP_TOOLCHAIN=${RUST_TOOLCHAIN}
COPY toolchain.cmake /opt/goodbuddy/loongarch64-toolchain.cmake
COPY probe.sh /usr/local/bin/goodbuddy-loongarch-cross-probe
COPY preview-deb.sh /usr/local/bin/goodbuddy-loongarch-preview-deb
RUN chmod 0755 \
/usr/local/bin/goodbuddy-loongarch-cross-probe \
/usr/local/bin/goodbuddy-loongarch-preview-deb
WORKDIR /work
ENTRYPOINT ["/usr/local/bin/goodbuddy-loongarch-cross-probe"]
+78
View File
@@ -0,0 +1,78 @@
# LoongArch cross-compilation probe
This directory defines an isolated Ubuntu 26.04 amd64 environment for probing
GoodBuddy's Linux `loong64` prerequisites. It does not build Electron or
OpenCode.
The image includes:
- GCC and G++ targeting `loongarch64-linux-gnu`
- A LoongArch glibc development sysroot
- QEMU user-mode execution
- CMake and Ninja
- Rust's `loongarch64-unknown-linux-gnu` target
- Node.js, npm, and node-gyp
The probe validates:
- C, C++, CMake, and Rust LoongArch ELF output
- C, C++, and Rust execution through QEMU
- A minimal NAPI-RS Rust addon cross-build
- A Debian package with `Architecture: loong64`
- Koffi 3.1.4's published LoongArch glibc binding and the absence of a musl
binding
- The current npm availability of an `@napi-rs/canvas` LoongArch package
- A source cross-build of node-pty 1.1.0
The node-pty probe uses its upstream node-gyp 11.4.2 dependency. Ubuntu's
distribution node-gyp unconditionally links Linux addons with `-lnode`, which
is appropriate for Ubuntu's shared Node.js package but not for Electron native
addons.
Build and run it from this directory on an amd64 Docker host:
```sh
docker build \
--tag goodbuddy-loongarch-cross:ubuntu-26.04 \
.
mkdir -p results
docker run --rm \
--volume "$PWD/results:/results" \
goodbuddy-loongarch-cross:ubuntu-26.04
```
Each run writes to a new UTC timestamped directory below `results`. A passing
run contains `summary.txt`, `SHA256SUMS`, the generated ELF files, and the
probe DEB.
QEMU only checks user-mode execution against the cross sysroot. Native Electron
loading, PTY behavior, desktop integration, GPU, audio, and packaging must
still be validated on a real Debian `loong64` host.
Koffi 3.1.4 currently publishes only `linux_loong64/koffi.node`, not a
`musl_loong64` binding. That is sufficient for a Debian desktop package but
does not satisfy GoodBuddy Agent's current dual-glibc/musl bundle contract.
The NAPI-RS probe confirms that a Rust Node addon can be cross-compiled. It
does not build Canvas itself, whose Skia dependency requires a separate port
and native validation.
## Experimental desktop preview
`prepare-input.cjs` creates the architecture-neutral GoodBuddy input archive.
`preview-deb.sh` combines it with the verified community Electron 42.3.0
LoongArch shell and produces an isolated `goodbuddy-loongarch-preview` DEB.
The preview:
- uses a separate application name and user-data directory;
- includes the direct model path and Continue runtime;
- cross-builds node-pty against Electron 42.3.0;
- includes Koffi's LoongArch glibc binding;
- does not include GoodBuddy Agent, Remote Runtime, OpenCode, or native Canvas;
- is not part of the production release matrix.
See
[`docs/development/loongarch-preview-build.md`](../../docs/development/loongarch-preview-build.md)
for the complete build and validation procedure.
+108
View File
@@ -0,0 +1,108 @@
const {
existsSync,
mkdirSync,
renameSync,
rmSync,
statSync
} = require('node:fs')
const { dirname, join, resolve } = require('node:path')
const tar = require('tar')
const root = join(__dirname, '..', '..')
const defaultOutput = join(
root,
'dist',
'loongarch-cross',
'goodbuddy-loongarch-cross-input.tgz'
)
const inputPaths = [
'LICENSE',
'agent-runtime-lock.json',
'package.json',
'package-lock.json',
'remote-runtime-lock.json',
'out',
'resources/agent-release-keys.json',
'resources/release-notes.json',
'resources/skills',
'build/icon.png',
'build/icon-tray.png',
'node_modules/@continuedev/cli/package.json',
'node_modules/@continuedev/cli/dist/cn.js',
'node_modules/@continuedev/cli/dist/index.js',
'node_modules/@continuedev/cli/dist/xhr-sync-worker.js',
'node_modules/npm'
]
function parseArguments(argv) {
const options = { output: defaultOutput }
for (let index = 0; index < argv.length; index += 1) {
const argument = argv[index]
if (argument !== '--output') {
throw new Error(`未知参数:${argument}`)
}
const value = argv[index + 1]
if (!value) {
throw new Error('--output 缺少值')
}
options.output = resolve(value)
index += 1
}
return options
}
function verifyInputs(projectRoot = root) {
for (const relativePath of inputPaths) {
if (!existsSync(join(projectRoot, relativePath))) {
throw new Error(`龙芯交叉构建输入缺失:${relativePath}`)
}
}
}
async function createInputArchive(outputPath, projectRoot = root) {
verifyInputs(projectRoot)
const resolvedOutput = resolve(outputPath)
const temporaryOutput = `${resolvedOutput}.partial-${process.pid}`
mkdirSync(dirname(resolvedOutput), { recursive: true })
rmSync(temporaryOutput, { force: true })
try {
await tar.c(
{
cwd: projectRoot,
file: temporaryOutput,
gzip: true,
portable: true,
noMtime: true
},
inputPaths
)
if (!statSync(temporaryOutput).isFile()) {
throw new Error('龙芯交叉构建输入归档未生成')
}
rmSync(resolvedOutput, { force: true })
renameSync(temporaryOutput, resolvedOutput)
} finally {
rmSync(temporaryOutput, { force: true })
}
return resolvedOutput
}
async function main(argv = process.argv.slice(2)) {
const options = parseArguments(argv)
const output = await createInputArchive(options.output)
console.log(`龙芯交叉构建输入已生成:${output}`)
}
module.exports = {
createInputArchive,
inputPaths,
parseArguments,
verifyInputs
}
if (require.main === module) {
main().catch((error) => {
console.error(error)
process.exitCode = 1
})
}
+322
View File
@@ -0,0 +1,322 @@
#!/usr/bin/env bash
set -euo pipefail
input_archive="${1:?missing GoodBuddy input archive}"
electron_archive="${2:?missing Electron loong64 archive}"
output_root="${3:-/preview-output}"
electron_version="42.3.0"
electron_sha256="92b0ca0c9c18ed90166918a4ac1970266c4fa967aee9277031b3b250b905526e"
koffi_version="3.1.4"
node_pty_version="1.1.0"
node_gyp_version="11.4.2"
preview_iteration="1"
application_directory="GoodBuddy-LoongArch-Preview"
executable_name="goodbuddy-loongarch-preview"
assert_file() {
if ! test -f "$1"; then
echo "missing required file: $1" >&2
exit 1
fi
}
assert_loongarch_elf() {
local file_path="$1"
assert_file "${file_path}"
file "${file_path}"
readelf -h "${file_path}" | grep -Eq \
'Machine:[[:space:]]+(LoongArch|Loongson Loongarch)'
}
assert_file "${input_archive}"
assert_file "${electron_archive}"
mkdir -p "${output_root}"
actual_electron_sha256="$(
sha256sum "${electron_archive}" | cut -d ' ' -f 1
)"
if test "${actual_electron_sha256}" != "${electron_sha256}"; then
echo "Electron loong64 archive digest mismatch" >&2
exit 1
fi
run_id="$(date -u +%Y%m%dT%H%M%SZ)"
work_root="${output_root}/.work-${run_id}"
input_root="${work_root}/input"
package_root="${work_root}/package"
application_root="${package_root}/opt/${application_directory}"
resources_root="${application_root}/resources"
app_root="${resources_root}/app"
artifact_root="${output_root}/${run_id}"
if test -e "${work_root}" || test -e "${artifact_root}"; then
echo "refusing to reuse preview build directory" >&2
exit 1
fi
cleanup() {
rm -rf "${work_root}"
}
trap cleanup EXIT
mkdir -p "${input_root}" "${app_root}" "${artifact_root}"
tar -xzf "${input_archive}" -C "${input_root}"
project_version="$(
node -p \
"require('${input_root}/package.json').version"
)"
preview_version="${project_version}-loong64-preview.${preview_iteration}"
deb_version="${project_version}~loong64preview${preview_iteration}"
artifact_name="GoodBuddy-${project_version}-linux-loong64-preview.deb"
echo "== extract verified Electron shell =="
python3 -m zipfile -e "${electron_archive}" "${application_root}"
assert_loongarch_elf "${application_root}/electron"
mv "${application_root}/electron" \
"${application_root}/${executable_name}"
chmod 0755 "${application_root}/${executable_name}"
rm -f "${resources_root}/default_app.asar"
if test -f "${application_root}/chrome-sandbox"; then
chmod 4755 "${application_root}/chrome-sandbox"
fi
echo "== install production JavaScript dependencies =="
cp "${input_root}/package.json" "${app_root}/package.json"
cp "${input_root}/package-lock.json" "${app_root}/package-lock.json"
(
cd "${app_root}"
npm ci \
--ignore-scripts \
--omit=dev \
--cpu=loong64 \
--os=linux
)
rm -rf \
"${app_root}/node_modules/@esbuild" \
"${app_root}/node_modules/@img" \
"${app_root}/node_modules/@rollup"
find "${app_root}/node_modules/@koromix" \
-mindepth 1 \
-maxdepth 1 \
-type d \
-exec rm -rf -- {} + 2>/dev/null || true
find "${app_root}/node_modules/@napi-rs" \
-mindepth 1 \
-maxdepth 1 \
-type d \
-name 'canvas-*' \
-exec rm -rf -- {} + 2>/dev/null || true
node - "${input_root}" "${app_root}/package.json" \
"${preview_version}" <<'NODE'
const { readFileSync, writeFileSync } = require('node:fs')
const [inputRoot, outputPath, version] = process.argv.slice(2)
const metadata = JSON.parse(
readFileSync(`${inputRoot}/package.json`, 'utf8')
)
metadata.name = 'goodbuddy-loongarch-preview'
metadata.productName = 'GoodBuddy LoongArch Preview'
metadata.desktopName = 'GoodBuddy LoongArch Preview'
metadata.version = version
metadata.main = './out/main/index.js'
delete metadata.build
delete metadata.devDependencies
delete metadata.optionalDependencies
writeFileSync(outputPath, `${JSON.stringify(metadata, null, 2)}\n`)
NODE
rm -f "${app_root}/package-lock.json"
echo "== stage target Koffi binding =="
koffi_stage="${work_root}/koffi"
mkdir -p "${koffi_stage}"
koffi_pack_json="$(
npm pack \
"@koromix/koffi-linux-loong64@${koffi_version}" \
--ignore-scripts \
--json \
--pack-destination "${koffi_stage}"
)"
koffi_archive="$(
node -e \
'const value=JSON.parse(process.argv[1]); process.stdout.write(value[0].filename)' \
"${koffi_pack_json}"
)"
koffi_integrity="$(
node -p \
"require('${input_root}/package-lock.json').packages['node_modules/@koromix/koffi-linux-loong64'].integrity"
)"
node - "${koffi_stage}/${koffi_archive}" \
"${koffi_integrity}" <<'NODE'
const { createHash } = require('node:crypto')
const { readFileSync } = require('node:fs')
const [filePath, integrity] = process.argv.slice(2)
const [algorithm, expected] = integrity.split('-', 2)
const actual = createHash(algorithm)
.update(readFileSync(filePath))
.digest('base64')
if (actual !== expected) {
throw new Error('Koffi archive integrity mismatch')
}
NODE
koffi_target="${app_root}/node_modules/@koromix/koffi-linux-loong64"
mkdir -p "${koffi_target}"
tar \
-xzf "${koffi_stage}/${koffi_archive}" \
-C "${koffi_target}" \
--strip-components 1
koffi_binding="${koffi_target}/linux_loong64/koffi.node"
assert_loongarch_elf "${koffi_binding}"
echo "== cross-build node-pty for Electron ${electron_version} =="
node_gyp_root="${work_root}/node-gyp"
npm install \
--ignore-scripts \
--prefix "${node_gyp_root}" \
"node-gyp@${node_gyp_version}"
node_pty_root="${app_root}/node_modules/node-pty"
test "$(
node -p "require('${node_pty_root}/package.json').version"
)" = "${node_pty_version}"
rm -rf "${node_pty_root}/build" "${node_pty_root}/prebuilds"
(
cd "${node_pty_root}"
CC=loongarch64-linux-gnu-gcc \
CXX=loongarch64-linux-gnu-g++ \
npm_config_arch=loong64 \
npm_config_target_arch=loong64 \
npm_config_runtime=electron \
npm_config_target="${electron_version}" \
npm_config_disturl=https://electronjs.org/headers \
"${node_gyp_root}/node_modules/.bin/node-gyp" rebuild \
--arch=loong64
)
node_pty_binding="${node_pty_root}/build/Release/pty.node"
assert_loongarch_elf "${node_pty_binding}"
echo "== stage GoodBuddy application and architecture-neutral runtimes =="
cp -a "${input_root}/out" "${app_root}/out"
mkdir -p \
"${resources_root}/licenses" \
"${resources_root}/runtimes" \
"${resources_root}/skills"
cp -a "${input_root}/resources/skills/." "${resources_root}/skills/"
cp "${input_root}/resources/release-notes.json" \
"${resources_root}/release-notes.json"
cp "${input_root}/resources/agent-release-keys.json" \
"${resources_root}/agent-release-keys.json"
cp "${input_root}/agent-runtime-lock.json" \
"${resources_root}/agent-runtime-lock.json"
cp "${input_root}/remote-runtime-lock.json" \
"${resources_root}/remote-runtime-lock.json"
cp "${input_root}/build/icon.png" "${resources_root}/icon.png"
cp "${input_root}/build/icon-tray.png" \
"${resources_root}/tray-icon.png"
cp "${input_root}/LICENSE" \
"${resources_root}/licenses/GoodBuddy-0BSD.txt"
mkdir -p "${resources_root}/runtimes/continue/dist"
cp "${input_root}/node_modules/@continuedev/cli/package.json" \
"${resources_root}/runtimes/continue/package.json"
cp "${input_root}/node_modules/@continuedev/cli/dist/cn.js" \
"${resources_root}/runtimes/continue/dist/cn.js"
cp "${input_root}/node_modules/@continuedev/cli/dist/index.js" \
"${resources_root}/runtimes/continue/dist/index.js"
cp "${input_root}/node_modules/@continuedev/cli/dist/xhr-sync-worker.js" \
"${resources_root}/runtimes/continue/dist/xhr-sync-worker.js"
cp -a "${input_root}/node_modules/npm" \
"${resources_root}/runtimes/npm"
echo "== reject foreign native addons =="
while IFS= read -r -d '' native_addon; do
assert_loongarch_elf "${native_addon}"
done < <(
find "${app_root}/node_modules" \
-type f \
-name '*.node' \
-print0
)
if test -e "${resources_root}/agents" ||
test -e "${resources_root}/remote-runtimes" ||
test -e "${resources_root}/runtimes/opencode"
then
echo "preview package unexpectedly contains Agent or OpenCode payload" >&2
exit 1
fi
echo "== build isolated preview DEB =="
mkdir -p \
"${package_root}/DEBIAN" \
"${package_root}/usr/bin" \
"${package_root}/usr/share/applications" \
"${package_root}/usr/share/icons/hicolor/512x512/apps"
ln -s \
"/opt/${application_directory}/${executable_name}" \
"${package_root}/usr/bin/${executable_name}"
cp "${input_root}/build/icon.png" \
"${package_root}/usr/share/icons/hicolor/512x512/apps/${executable_name}.png"
cat > "${package_root}/usr/share/applications/${executable_name}.desktop" <<EOF
[Desktop Entry]
Name=GoodBuddy LoongArch Preview
Comment=GoodBuddy LoongArch 主体预览版
Exec=/opt/${application_directory}/${executable_name} %U
Terminal=false
Type=Application
Icon=${executable_name}
Categories=Utility;
StartupWMClass=GoodBuddy LoongArch Preview
EOF
cat > "${package_root}/DEBIAN/control" <<EOF
Package: goodbuddy-loongarch-preview
Version: ${deb_version}
Architecture: loong64
Maintainer: MesaLogo
Section: utils
Priority: optional
Depends: libasound2t64, libatspi2.0-0t64, libgbm1, libgtk-3-0t64, libnotify4, libnss3, libpulse0, libsecret-1-0, libuuid1, libxss1, libxtst6, xdg-utils
Description: GoodBuddy LoongArch desktop preview
Experimental LoongArch desktop build without bundled Agent, Remote Runtime,
OpenCode, or native Canvas image decoding.
EOF
artifact="${artifact_root}/${artifact_name}"
dpkg-deb --root-owner-group --build "${package_root}" "${artifact}"
echo "== verify preview package =="
test "$(dpkg-deb --field "${artifact}" Architecture)" = "loong64"
verify_root="${work_root}/verify"
mkdir "${verify_root}"
dpkg-deb --extract "${artifact}" "${verify_root}"
assert_loongarch_elf \
"${verify_root}/opt/${application_directory}/${executable_name}"
assert_loongarch_elf \
"${verify_root}/opt/${application_directory}/resources/app/${node_pty_binding#${app_root}/}"
assert_loongarch_elf \
"${verify_root}/opt/${application_directory}/resources/app/${koffi_binding#${app_root}/}"
sha256sum "${artifact}" > "${artifact_root}/SHA256SUMS"
cat > "${artifact_root}/preview-manifest.json" <<EOF
{
"formatVersion": 1,
"product": "GoodBuddy LoongArch Preview",
"goodBuddyVersion": "${project_version}",
"previewVersion": "${preview_version}",
"electronVersion": "${electron_version}",
"architecture": "loong64",
"artifact": "${artifact_name}",
"bundledAgent": false,
"bundledRemoteRuntime": false,
"bundledOpenCode": false,
"nativeCanvas": false,
"continueRuntime": true,
"nodePty": true,
"koffiGlibc": true,
"nativeLaunchVerified": false
}
EOF
cat "${artifact_root}/preview-manifest.json"
echo "artifact=${artifact}"
+314
View File
@@ -0,0 +1,314 @@
#!/usr/bin/env bash
set -euo pipefail
results_root="${1:-/results}"
run_id="$(date -u +%Y%m%dT%H%M%SZ)"
results="${results_root}/${run_id}"
mkdir -p "${results}"
log="${results}/probe.log"
exec > >(tee "${log}") 2>&1
assert_loongarch_elf() {
local file_path="$1"
file "${file_path}"
readelf -h "${file_path}" | grep -Eq \
'Machine:[[:space:]]+(LoongArch|Loongson Loongarch)'
}
echo "== tool versions =="
loongarch64-linux-gnu-gcc --version | head -n 1
loongarch64-linux-gnu-g++ --version | head -n 1
loongarch64-linux-gnu-ld --version | head -n 1
qemu-loongarch64 --version | head -n 1
node --version
npm --version
node-gyp --version
rustc --version
cargo --version
cmake --version | head -n 1
echo "== C probe =="
cat > "${results}/hello.c" <<'EOF'
#include <stdio.h>
int main(void) {
puts("goodbuddy-loongarch-c-ok");
return 0;
}
EOF
loongarch64-linux-gnu-gcc \
-O2 \
-Wall \
-Wextra \
-Werror \
"${results}/hello.c" \
-o "${results}/hello-c"
assert_loongarch_elf "${results}/hello-c"
test "$(
qemu-loongarch64 \
-L /usr/loongarch64-linux-gnu \
"${results}/hello-c"
)" = "goodbuddy-loongarch-c-ok"
echo "== C++ probe =="
cat > "${results}/hello.cpp" <<'EOF'
#include <iostream>
#include <string_view>
int main() {
constexpr std::string_view message{"goodbuddy-loongarch-cpp-ok"};
std::cout << message << '\n';
return 0;
}
EOF
loongarch64-linux-gnu-g++ \
-std=c++20 \
-O2 \
-Wall \
-Wextra \
-Werror \
"${results}/hello.cpp" \
-o "${results}/hello-cpp"
assert_loongarch_elf "${results}/hello-cpp"
test "$(
qemu-loongarch64 \
-L /usr/loongarch64-linux-gnu \
"${results}/hello-cpp"
)" = "goodbuddy-loongarch-cpp-ok"
echo "== CMake probe =="
mkdir "${results}/cmake-source"
cat > "${results}/cmake-source/CMakeLists.txt" <<'EOF'
cmake_minimum_required(VERSION 3.20)
project(goodbuddy_loongarch_probe LANGUAGES C)
add_executable(goodbuddy-cmake-probe main.c)
target_compile_options(
goodbuddy-cmake-probe
PRIVATE -Wall -Wextra -Werror
)
EOF
cp "${results}/hello.c" "${results}/cmake-source/main.c"
cmake \
-S "${results}/cmake-source" \
-B "${results}/cmake-build" \
-G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_TOOLCHAIN_FILE=/opt/goodbuddy/loongarch64-toolchain.cmake
cmake --build "${results}/cmake-build"
assert_loongarch_elf \
"${results}/cmake-build/goodbuddy-cmake-probe"
echo "== Rust probe =="
mkdir -p "${results}/rust-probe/src"
cat > "${results}/rust-probe/Cargo.toml" <<'EOF'
[package]
name = "goodbuddy-loongarch-rust-probe"
version = "0.1.0"
edition = "2024"
[dependencies]
EOF
cat > "${results}/rust-probe/src/main.rs" <<'EOF'
fn main() {
println!("goodbuddy-loongarch-rust-ok");
}
EOF
cargo build \
--release \
--manifest-path "${results}/rust-probe/Cargo.toml"
rust_binary="$(
find "${results}/rust-probe/target" \
-type f \
-name goodbuddy-loongarch-rust-probe \
-print \
-quit
)"
test -n "${rust_binary}"
assert_loongarch_elf "${rust_binary}"
test "$(
qemu-loongarch64 \
-L /usr/loongarch64-linux-gnu \
"${rust_binary}"
)" = "goodbuddy-loongarch-rust-ok"
echo "== NAPI-RS Rust addon probe =="
mkdir -p "${results}/napi-rs-probe/src"
cat > "${results}/napi-rs-probe/Cargo.toml" <<'EOF'
[package]
name = "goodbuddy-loongarch-napi-probe"
version = "0.1.0"
edition = "2024"
[lib]
crate-type = ["cdylib"]
[dependencies]
napi = { version = "3", default-features = false, features = ["napi8"] }
napi-derive = "3"
[build-dependencies]
napi-build = "2"
EOF
cat > "${results}/napi-rs-probe/build.rs" <<'EOF'
fn main() {
napi_build::setup();
}
EOF
cat > "${results}/napi-rs-probe/src/lib.rs" <<'EOF'
use napi_derive::napi;
#[napi]
pub fn architecture_probe() -> &'static str {
"loong64"
}
EOF
cargo build \
--release \
--manifest-path "${results}/napi-rs-probe/Cargo.toml"
napi_binding="$(
find "${results}/napi-rs-probe/target" \
-type f \
-name 'libgoodbuddy_loongarch_napi_probe.so' \
-print \
-quit
)"
test -n "${napi_binding}"
assert_loongarch_elf "${napi_binding}"
echo "== Debian package probe =="
package_root="${results}/deb-root"
mkdir -p \
"${package_root}/DEBIAN" \
"${package_root}/usr/lib/goodbuddy-loongarch-probe"
cp "${results}/hello-c" \
"${package_root}/usr/lib/goodbuddy-loongarch-probe/hello"
cat > "${package_root}/DEBIAN/control" <<'EOF'
Package: goodbuddy-loongarch-cross-probe
Version: 1.0.0
Architecture: loong64
Maintainer: MesaLogo
Description: GoodBuddy LoongArch cross-compilation probe
EOF
dpkg-deb --build \
"${package_root}" \
"${results}/goodbuddy-loongarch-cross-probe_1.0.0_loong64.deb"
test "$(
dpkg-deb \
--field \
"${results}/goodbuddy-loongarch-cross-probe_1.0.0_loong64.deb" \
Architecture
)" = "loong64"
echo "== Koffi prebuilt probe =="
mkdir "${results}/koffi"
npm pack \
"@koromix/koffi-linux-loong64@3.1.4" \
--ignore-scripts \
--pack-destination "${results}/koffi"
koffi_archive="$(
find "${results}/koffi" \
-maxdepth 1 \
-type f \
-name '*.tgz' \
-print \
-quit
)"
test -n "${koffi_archive}"
mkdir "${results}/koffi/package"
tar \
-xzf "${koffi_archive}" \
-C "${results}/koffi/package" \
--strip-components 1
koffi_binding="${results}/koffi/package/linux_loong64/koffi.node"
assert_loongarch_elf "${koffi_binding}"
if test -e "${results}/koffi/package/musl_loong64/koffi.node"; then
echo "Unexpected Koffi musl binding is present"
exit 1
fi
echo "Koffi loong64 currently provides a glibc binding only"
echo "== Canvas package availability probe =="
canvas_package_status=unavailable
if npm view \
"@napi-rs/canvas-linux-loong64-gnu" \
version \
> "${results}/canvas-package-version.txt" \
2> "${results}/canvas-package-error.txt"
then
canvas_package_status=available
fi
echo "@napi-rs/canvas loong64 package: ${canvas_package_status}"
echo "== node-pty cross-build probe =="
mkdir "${results}/node-pty"
npm pack \
"node-pty@1.1.0" \
--ignore-scripts \
--pack-destination "${results}/node-pty"
node_pty_archive="$(
find "${results}/node-pty" \
-maxdepth 1 \
-type f \
-name '*.tgz' \
-print \
-quit
)"
test -n "${node_pty_archive}"
mkdir "${results}/node-pty/package"
tar \
-xzf "${node_pty_archive}" \
-C "${results}/node-pty/package" \
--strip-components 1
(
cd "${results}/node-pty/package"
npm install --ignore-scripts --omit=dev
npm install \
--ignore-scripts \
--no-save \
"node-gyp@11.4.2"
CC=loongarch64-linux-gnu-gcc \
CXX=loongarch64-linux-gnu-g++ \
npm_config_arch=loong64 \
npm_config_target_arch=loong64 \
npm_config_runtime=electron \
npm_config_target=43.2.0 \
npm_config_disturl=https://electronjs.org/headers \
./node_modules/.bin/node-gyp rebuild \
--arch=loong64
)
node_pty_binding="${results}/node-pty/package/build/Release/pty.node"
assert_loongarch_elf "${node_pty_binding}"
echo "== summary =="
sha256sum \
"${results}/hello-c" \
"${results}/hello-cpp" \
"${rust_binary}" \
"${napi_binding}" \
"${results}/goodbuddy-loongarch-cross-probe_1.0.0_loong64.deb" \
"${koffi_binding}" \
"${node_pty_binding}" \
> "${results}/SHA256SUMS"
cat > "${results}/summary.txt" <<EOF
result=pass
target=loong64
c=pass
cpp=pass
cmake=pass
rust=pass
napi_rs=pass
qemu=pass
deb=pass
koffi=pass
koffi_musl=unavailable
canvas_package=${canvas_package_status}
node_pty=pass
EOF
cat "${results}/summary.txt"
echo "results=${results}"
+14
View File
@@ -0,0 +1,14 @@
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR loongarch64)
set(CMAKE_C_COMPILER loongarch64-linux-gnu-gcc)
set(CMAKE_CXX_COMPILER loongarch64-linux-gnu-g++)
set(CMAKE_AR loongarch64-linux-gnu-ar)
set(CMAKE_RANLIB loongarch64-linux-gnu-ranlib)
set(CMAKE_STRIP loongarch64-linux-gnu-strip)
set(CMAKE_FIND_ROOT_PATH /usr/loongarch64-linux-gnu)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)