极空间跨平台构建体系:一套 Go 代码编译 ARM 与 x86

2026/05/22

基于 T2 (RK3568/ARM64) 设备上残留的构建脚本和工程文件推断 分析日期:2026-05-22


一、核心结论:一套 Go 代码,多平台交叉编译

极空间的软件体系采用 单一代码库 + Go 交叉编译 + 架构特定二进制资产 的策略,在 ARM (RK3568/RK3588) 和 x86 之间共享 90% 以上的代码。

┌──────────────────────────────────────────────────┐
│              同一个 Git 仓库                        │
│                                                    │
│  main.go / zvideo.go / zalbum.go / ...            │
│  (Go 源码,平台无关)                                │
│                                                    │
│  msearchd/               zaitoolkit/              │
│  ├── arm/searchd         ├── arm/*                │
│  └── amd/searchd         └── amd/*                │
│  (C/C++ 二进制,预编译分支)                         │
│                                                    │
│  build.sh <platform> <outdir>                      │
│    ├── z2/z2s → ARM64 + OpenWrt 工具链             │
│    ├── z4     → ARM64 (高端型号)                    │
│    └── default → AMD64 (x86)                       │
└──────────────────────────────────────────────────┘

二、两条构建流水线

在设备上发现两种构建入口,对应两个阶段:

build.sh — 本地开发构建

路径:/zspace/applications/services/<服务名>/build.sh

# 所有 build.sh 遵循统一模式
build.sh <platform_flag> <output_directory>

AppStoreBuild.sh — Jenkins CI 构建

路径:/data_n001/appstore/pkg/<应用名>/AppStoreBuild.sh

export PATH=/var/lib/jenkins/tools/gos/1.24/bin:$PATH
GO_BIN=/var/lib/jenkins/tools/gos/1.24/bin/go

两者关系

build.shAppStoreBuild.sh
位置系统服务目录用户应用包目录
Go 路径/usr/local/go_zspace//var/lib/jenkins/tools/gos/
用途本地开发 / 系统级服务构建CI 构建 / 应用商店分发
产物分发OTA 系统更新App Store

三、平台识别机制:设备 SN 前缀

所有 build.sh 通过传入的设备序列号前缀来决定编译目标:

# 来自 zalbumv2/build.sh
sn=$(echo $1 | tr 'A-Z' 'a-z')

if [[ "$sn" == "z02"* ]]; then   ver1="z2"    # Z2 系列
if [[ "$sn" == "t02"* ]]; then   ver1="z2"    # T2
if [[ "$sn" == "q02"* ]]; then   ver1="z2"    # Q2 系列
if [[ "$sn" == "ta21"* ]]; then  ver1="z2"    # TA21 系列
if [[ "$sn" == "z023"* ]]; then  ver1="z4"    # Z4 系列 (高端 ARM)
if [[ "$sn" == "za23"* ]]; then  ver1="z4"    # ZA23 系列

# 默认 else → x86/amd64

设备层级:

平台标识对应设备架构特征
z2Z2, Z2S, T2, Q2, TA21ARM64 (RK3568)入门/便携
z2sZ2S 特定变体ARM64 (RK3568)与 z2 编译参数相同
z4Z4, ZA23ARM64 (RK3588)高端
defaultx86 机型AMD64PC 平台

四、Go 交叉编译策略

统一模式

# ARM 平台
CGO_ENABLED=1 GOOS=linux GOARCH=arm64 \
  CXX=aarch64-openwrt-linux-g++ \
  CC=aarch64-openwrt-linux-gcc \
  go build -o $NAME

# x86 平台
CGO_ENABLED=1 GOOS=linux GOARCH=amd64 \
  go build -o $NAME

Go 版本矩阵

设备上发现 4 个 Go 版本共存,各服务按需选择:

Go 版本服务数量说明
1.20.224较老服务,稳定版本
1.22.218中间版本
1.23.314包括 zdocker
1.24.124最新服务,包括 zfilev2

每个服务锁定一个 Go 版本,不强制统一升级。这是一种务实的单仓(monorepo)管理策略。

编译优化

t.sh(测试/本地构建脚本)中有额外步骤:

# UPX 压缩二进制,减小分发体积
upx -q -1 ./$NAME

说明他们关注 ARM 设备上的存储和传输体积。


五、架构特定资产的分发

纯 Go 代码可以交叉编译,但有些依赖是 C/C++ 的,必须预编译。build.sh 在构建时 按架构选择正确的二进制文件:

案例 1:zalbumv2 (相册)

msearchd/                    zaitoolkit/
├── arm/searchd (ARM 版)     ├── arm/* (ARM 版 AI 模型)
└── amd/searchd (x86 版)     └── amd/* (x86 版 AI 模型)

Manticore Search 是 C++ 全文检索引擎,无法被 Go 交叉编译。构建时根据平台选择 arm/ 或 amd/ 目录。

案例 2:zfilev2 (文件管理)

gocryptfs_arm  vs  gocryptfs_x86     # Go 加密文件系统(但可能是 CGO 绑定)
7zz_arm        vs  7zz_x86           # 7-Zip 压缩(C++)
libgphoto2.arm.tar.gz  vs  .x86.tar.gz  # 相机连接的 C 库

模式总结

源代码仓库结构(推测):
<service>/
├── main.go              ← 平台无关 Go 代码
├── build.sh             ← 统一构建脚本
├── msearchd/            ← C/C++ 依赖
│   ├── arm/searchd      ← ARM 预编译二进制
│   └── amd/searchd      ← x86 预编译二进制
├── zaitoolkit/
│   ├── arm/*            ← ARM 模型文件
│   └── amd/*            ← x86 模型文件
└── ...

六、OpenWrt 工具链的运用

ARM 平台的 CGO 编译统一使用 OpenWrt 交叉工具链:

CXX=aarch64-openwrt-linux-g++
CC=aarch64-openwrt-linux-gcc

以及部分场景使用更具体的工具链:

# zfilev2 中用到(libgphoto2 的 CGO 编译)
CGO_CFLAGS="-I/opt/toolchain-aarch64_cortex-a53_gcc-8.2.0_glibc/..."
CGO_LDFLAGS="-L/opt/toolchain-aarch64_cortex-a53_gcc-8.2.0_glibc/..."

这暗示:


七、分发体系

OTA 系统更新

/zspace/update/pkg/
├── T020_SERVICE/     ← T2 设备的服务更新包
├── T020_SYSTEM/      ← T2 设备的系统更新包
├── Z022_SERVICE/     ← Z2 设备的服务更新包
└── Z022_SYSTEM/      ← Z2 设备的系统更新包

包名格式:<型号>_<类型>,型号和类型分离,同一服务可以为不同型号发布不同包。

完整性校验

每个服务目录都有一个 filehash.zspace.upgrade.json:

{
  "service_md5": {
    "conf/version": "1e2fb8e78fe269edd07f6f2216d46c0f",
    "go-baseset": "d9f2280fc205846c10b79bf0be4d73b2",
    "install.sh": "faa25c6c7940f930d70538c673a39726",
    ...
  }
}

72 个服务都有此文件,OTA 升级前逐文件校验 MD5,确保包完整性。

版本号体系

所有服务统一版本格式:V0.2.YYYYMMDDNN

V0.2.2026012101
    │  │        │
    │  │        └── 当日构建序号(01-99)
    │  └── 构建日期
    └── 主版本.次版本

每日从 01 开始,同一天每多构建一次 +1。这意味着他们可能 每日构建 (nightly build) 甚至更频繁。


八、部署与安装

部署工具:ztools

自研 Go 工具,用于文件分发:

/zspace/shell/tool/ztools/ztools copy_dir <source> <target>

install.sh 脚本调用它来部署文件到目标路径。

安装脚本分级

install.sh 类型占比含义
exit 0(空壳)~15%构建系统直接处理部署,install.sh 只做占位
简单 cp + systemctl~60%标准 Go 服务:复制文件 + 注册 systemd + 启动
复杂安装逻辑~25%samba (171行)、zfirewall (104行) 等需要大量系统配置的服务

九、完整的端到端推测流程

┌─────────────────────────────────────────────────────────┐
│                   Git 单仓库 (Monorepo)                    │
│                                                           │
│  services/                  apps/                        │
│  ├── go-baseset/           ├── photoAlbum/               │
│  ├── zdocker/              ├── video/                    │
│  ├── zfilev2/              ├── music/                    │
│  ├── ...                   ├── ...                       │
└────────────┬──────────────────────┬──────────────────────┘
             │                      │
    ┌────────▼────────┐    ┌───────▼──────────┐
    │  build.sh        │    │  AppStoreBuild.sh │
    │  (本地开发)       │    │  (Jenkins CI)      │
    │                  │    │                    │
    │  go_zspace/1.x   │    │  jenkins/gos/1.x   │
    └────────┬─────────┘    └───────┬────────────┘
             │                      │
    ┌────────▼──────────────────────▼──────────┐
    │          build.sh <platform> <out>        │
    │                                            │
    │  ┌──────────┐  ┌──────────┐  ┌─────────┐ │
    │  │ ARM64    │  │ ARM64    │  │ AMD64   │ │
    │  │ (z2/z2s) │  │ (z4)     │  │ (x86)   │ │
    │  │          │  │          │  │         │ │
    │  │ CC=aarch │  │ (同 z2)  │  │ 本地gcc │ │
    │  │ 64-open  │  │ 或更高   │  │         │ │
    │  │ wrt-...  │  │ 配置     │  │         │ │
    │  └────┬─────┘  └────┬─────┘  └────┬────┘ │
    │       │             │             │      │
    │       └──────┬──────┴──────┬──────┘      │
    └──────────────┼─────────────┼─────────────┘
                   │             │
          ┌────────▼──────┬──────▼────────┐
          │  OTA 更新包    │  App Store 包  │
          │  T020_SERVICE │  photoAlbum/  │
          │  Z022_SERVICE │  video/       │
          └──────┬────────┴──────┬────────┘
                 │               │
          ┌──────▼───────────────▼──────────┐
          │         用户设备                   │
          │  /zspace/applications/services/  │
          │  /var/appstore/pkg/              │
          └──────────────────────────────────┘

十、工程水平评估

做得好的

  1. Go 选型正确:一次编写,跨平台编译,ARM/x86 真正共享代码
  2. 统一构建约定:所有 build.sh 遵循相同接口 build.sh <arch> <out>,降低维护成本
  3. 完整性校验:每个服务都有 MD5 哈希清单,OTA 升级安全可靠
  4. Go 版本隔离:不强制统一升级,每个服务用自己验证过的版本
  5. 架构资产显式分离:arm/ vs amd/ 目录,一目了然

可以推敲的

  1. Go 版本碎片化:4 个版本并存,长期维护成本高。但这是 monorepo 的务实妥协
  2. C/C++ 依赖外挂:manticore、libgphoto2 等以二进制形式提交到 Git 仓库(或用 Git LFS 管理),而非从源码构建。牺牲了可复现性换取了构建速度
  3. build.sh 重复代码:每个服务的 build.sh 有 80% 相同逻辑(版本号生成、文件复制),没有抽取公共构建框架
  4. install.sh 空壳:exit 0 的 install.sh 说明部署逻辑散落在构建系统的其他地方,不够内聚

十一、关键推断

  1. 极空间几乎肯定是 Go Monorepo:所有 Go 服务在同一仓库,共享构建工具链
  2. 系统底层是 OpenWrt/Buildroot:aarch64-openwrt-linux-* 工具链表明 rootfs 构建用 OpenWrt,Go 应用层是上层建筑
  3. Jenkins 做 CI/CD:/var/lib/jenkins 路径直接暴露了 CI 系统
  4. Git LFS 管理大文件:git lfs pull 命令出现在 build.sh 中,用于管理预编译的 C/C++ 二进制
  5. 每日构建节奏:版本号按日期递增,暗示至少每天构建一次
  6. 没有 Makefile/Dockerfile:整个设备上找不到一个 Makefile(除了 PDF 解析库自带的),说明完全拥抱 Go 的构建范式,不使用传统 C/C++ 构建系统