构建系统设计
项目提供两个构建入口:scripts/build.sh(Linux 构建,build.sh + CMake 混合架构)与 scripts/build_ohos.sh(OHOS 构建,基于 OpenHarmony 标准构建体系)。本文说明两者的内部设计。
概述
两种构建形态
同一份代码支持两种构建形态,在 repo init 时通过 groups 选择(详见目录结构):
| 形态 | 构建入口 | 构建体系 | 说明 |
|---|---|---|---|
| Linux 构建 | scripts/build.sh |
CMake | 产出 Linux 应用与 BSP 镜像,不含 OpenHarmony 社区代码(repo init -g linux) |
| OHOS 构建 | scripts/build_ohos.sh |
OpenHarmony 标准构建(GN) | 依赖 ohos/ 社区代码与 ohos_adapt/ 适配层,产出 OHOS 镜像(默认 group 全量下载) |
Linux 构建分层
Linux 构建系统由六层组成,每层有明确的边界和职责:
| 层 | 位置 | 职责 |
|---|---|---|
| 构建入口 | scripts/build.sh |
加载配置、预处理、启动编译构建 |
| SDK 层 | sdk/ |
SDK 处理、BSP/MPP 编译 |
| 第三方层 | open_source/ |
各库自带编译构建文件,由 Kconfig 控制 |
| 组件层 | components/ |
adapter / hiai / network / media |
| 应用层 | apps/<BOARD>/ |
references / samples / solutions,每个应用带 app.defconfig配置文件 |
| 配置层 | **/Kconfig + configs/ |
menuconfig菜单配置,kconfig2*.py转换Kconfig符号为编译构建工具变量 |
flowchart TD
A["app.defconfig → .config"] --> B["kconfig2*.py → .config.cmake"]
B --> C[CMake configure]
C --> D["SDK: BSP + MPP 编译"]
C --> E["第三方库 → 组件 → 应用"]
D --> F["SDK"]
E --> G["_build/bin/ + lib/ + third_party/"]
build.sh 只做调度:加载 defconfig、触发 SDK 准备、调用编译构建工具。
配置数据流
配置单向流动,不可逆转:
.config 比 .config.cmake 新时,build.sh 自动重新转换。禁止手动编辑 .config.cmake——它是派生文件,下次转换会覆盖。
CMake 侧加载顺序:
SDK 版本由 CONFIG_SDK_VERSION(Kconfig → .config → sdk/build.cmake)统一决定。
变量命名规则:
| 前缀 | 作用域 | 示例 |
|---|---|---|
ENABLE_OS_* |
open_source/ 第三方库 |
ENABLE_OS_OPENSSL |
ENABLE_SDK_OS_* |
open_source/ SDK 补充包(仅 prepare 阶段读取) |
ENABLE_SDK_OS_LINUX |
ENABLE_COMP_* |
components/ 组件 |
ENABLE_COMP_ADAPTER |
ENABLE_DRV_* |
components/adapter/ 驱动 |
ENABLE_DRV_LCD_ST7789V |
ENABLE_SDK_BUILD_* |
SDK 构建选项 | ENABLE_SDK_BUILD_BSP |
架构分层
open_source 层
open_source/ 下的源码包由根 CMakeLists.txt 统一驱动,通过 ENABLE_OS_* 开关按需引入。各库自带 CMakeLists.txt,独立完成解压、patch、ExternalProject 编译。
| 库 | 构建方式 | CMake 导入目标 |
|---|---|---|
| openssl | ./Configure |
third_party::openssl |
| curl | autoconf ./configure |
third_party::curl |
| libdrm | meson + ninja | third_party::libdrm |
| lvgl | CMake | third_party::lvgl |
| cjson | 源码内联 | — |
| mqtt | Makefile + patch | third_party::mqtt |
应用自动发现
apps/<BOARD>/ 下子目录中有 .c 或 .cpp 源文件即自动创建 CMake 目标,无需修改任何 CMakeLists.txt。三类应用按目的区分:
| 目录 | 定位 |
|---|---|
samples/ |
组件能力的单点功能案例 |
references/ |
准产品的核心功能案例 |
solutions/ |
产品的完整功能案例 |
构建操作
构建
# 默认构建(从 .target 读取上次的目标)
bash scripts/build.sh build
# 指定目标应用
bash scripts/build.sh build --target cv610_ev_board samples framework_media
# 指定并行数
bash scripts/build.sh build -j 8
# 清理重建
bash scripts/build.sh distclean
bash scripts/build.sh build
--target 的三个参数对应 apps/<BOARD>/<APP_TYPE>/<APP_NAME>/ 路径,会自动加载该目录下的 app.defconfig 并写入 .target 文件。不指定 --target 时从 .target 读取上次的目标。
menuconfig
交互式菜单按模块层级组织,方向键移动、空格切换开关,保存退出后 .config 和 .config.cmake 自动更新。
构建产物
构建产物位于 _build/:
_build/
├── bin/ # 应用可执行文件
├── lib/ # 组件静态库
├── third_party/ # 第三方库
├── sdk/ # SDK 安装目录
└── install/ # 烧录镜像(CONFIG_BUILD_INSTALL=y 时生成)
| 产物 | 说明 |
|---|---|
bin/ |
应用可执行文件,最终烧录到板端的主体 |
lib/ |
组件静态库(adapter/hiai/media/network),中间产物 |
third_party/ |
第三方库编译结果,被组件和应用链接 |
sdk/ |
SDK 解压与编译产物(uImage、u-boot、rootfs、.ko) |
install/ |
仅 CONFIG_BUILD_INSTALL=y 时生成,含打包好的烧录镜像 |
SDK 编译
SDK 编译分为 BSP(内核/uboot/rootfs)和 MPP(驱动模块)两部分,由 sdk/build.cmake 触发。
BSP 与 MPP
SDK 编译在 build 时触发,分为两部分:
| 部分 | 产物 | 检测条件 |
|---|---|---|
| BSP | uImage、uboot、rootfs | SDK包发布目录下uImage 存在则跳过 |
| MPP | .ko 内核模块 |
每次强制重新编译 |
相关 Kconfig 开关:
| 符号 | 默认 | 作用 |
|---|---|---|
SDK_BUILD_BSP |
y | 编译 BSP。关闭后跳过内核/uboot/rootfs 编译,SDK_BSP_DEBUG 也随之禁用,应用层仍可正常编译 |
SDK_BSP_DEBUG |
y | y=开发模式(UART 控制台/telnetd/tftp),n=发布模式 |
SDK_BUILD_MPP |
n | 编译 MPP 驱动(SDK 预编译 .ko 通常可直接用) |
BSP 使用
编译时机与跳过逻辑:
BSP 编译产物为 uImage(内核镜像)、u-boot、rootfs。build.cmake 在 SDK 包发布目录下递归检测 uImage,存在则跳过 BSP 编译:
- 首次构建:SDK 解压后无 uImage,自动触发 BSP 编译(含 kernel、u-boot、rootfs,耗时较长)
- 后续构建:uImage 已存在,跳过 BSP,仅做 CMake 层增量编译
- 强制重建 BSP:
bash scripts/build.sh distclean删除构建目录,下次构建重新编译全部(含 BSP)
跳过 BSP 编译:
关闭 CONFIG_SDK_BUILD_BSP 可跳过 BSP,但会同时禁用 depends on SDK_BUILD_BSP 的驱动选项(如 sensor、LCD 等需随内核编译的 out-of-tree 驱动)。仅在已有预编译镜像、仅需编译应用层时使用。
补充:
- 应用 Patch:应用可通过自身目录下的
patch/apply_patches.sh修改 SDK 源码(u-boot、linux 内核等),详见下文 Patch 机制 - 内核模块选项:应用可通过
bsp_make_opts文件向内核/uboot 编译传递自定义选项,由build.cmake自动读取 - 部分源码不开源,使用预编译的二进制文件如wifi驱动。
Patch 机制
板仓公共patch在apps/<board>/bsp/patch/目录下,会优先于应用patch执行。
部分应用需修改 SDK 源码(u-boot、linux、BSP Makefile、DTS、GSL 等)以实现自定义功能或优化性能。build.cmake 在 BSP 编译前从 .target 文件推导目标应用,拼出 apps/<board>/<type>/<name>/patch/ 路径,执行 apply_patches.sh。
完整流程
bash scripts/build.sh build 内部执行顺序:
--target→ 写入.target,定位app.defconfig(应用的 Kconfig 默认配置,优先级最低,会被menuconfig修改和后续--target覆盖)- 扫描目标应用目录下的
Kconfig→ 生成Kconfig.apps - kconfiglib 加载 defconfig(读
Kconfig+Kconfig.apps)→ 写入.config - prepare:SDK 解压 + open_source 预拷贝(幂等)
.config转换成.config.cmake- SDK patch → BSP 编译→ MPP 编译
- CMake configure(
cmake -B _build) - CMake build(第三方库 → 组件 → 应用)
OHOS 构建
OHOS 构建由 scripts/build_ohos.sh 驱动:在 OpenHarmony 标准构建(ohos/build.sh,GN 体系)的外层完成 SDK 准备、补丁应用、配置转换与产物后处理,最终产出 OHOS 镜像。
前置条件
- 代码需以 OHOS 形态下载:
repo init使用默认 group(含ohos/社区代码与ohos_adapt/适配层,详见目录结构)。 sdk/Hi3516CV610/SDK 已随repo sync落地(hisupport SDK需将Hi3516CV610_SDK_V1.0.2.0.tgz放入sdk/,脚本自动解压)。
命令用法
./scripts/build_ohos.sh --target <BOARD> <APP_TYPE> <APP_NAME> [--sdk-type hispark|hisupport] [--shell busybox|toybox] [ohos-args...]
# 示例
bash scripts/build_ohos.sh --target cv610_ev_board references factory_demo/ws73_lcd --sdk-type hispark --shell busybox --product-name=ipcamera_hispark_hi3516cv610_linux --ccache --no-prebuilt-sdk
| 选项 | 说明 |
|---|---|
--target BOARD APP_TYPE APP_NAME |
指定目标应用,定位 app.defconfig,与 Linux 构建一致 |
--sdk-type |
SDK 类型:hispark/ hisupport |
--shell |
rootfs shell:busybox(默认)/ toybox |
| 其余参数 | 原样透传给 OpenHarmony build.sh(如 --product-name、--gn-args build_xts=true --cccache 等);--product-name 默认 ipcamera_hispark_hi3516cv610_linux |
构建流程
build_ohos.sh 内部按阶段依次执行:
| 阶段 | 内容 |
|---|---|
| prepare | LFS 拉取;SDK 解压/变体补丁;应用 ohos_adapt/patch/ 下的 OHOS 补丁(按 SDK 类型区分 2D_/2B_ 变体,marker 幂等,切换 SDK 类型时自动反打旧补丁);拷贝 device/soc/vendor overlay;解压交叉编译工具链;应用案例 oh_product/ overlay |
| app BSP | 与 Linux 构建的 Patch 机制同构:两级补丁(板级 apps/<board>/bsp/patch/ + 案例 patch/apply_patches.sh);通过 bsp_make_opts 只读通道派生 APP_DEFCONFIG/APP_NAND_ENV/UBI_SIZE 等变量;以案例 defconfig 覆盖 OHOS 内核 defconfig(首次备份原版,幂等) |
| SDK 编译 | 编译 busybox、u-boot(含案例 env nand_env.bin 覆盖,marker 记录 env 来源,案例切换时强制重建) |
| OHOS 构建 | 生成 sdk_config.gni(SDK 类型/路径/工具链);由 scripts/ohos/defconfig_to_gni.py 将 app.defconfig 转换为 app.gni(应用配置进入 GN 体系);调用 ohos/build.sh 完成 OpenHarmony 标准构建 |
| 后处理 | busybox 模式下将 busybox 安装进 rootfs(替换 toybox 链接与二进制)并重新生成 rootfs 镜像;rootfs 产物名与烧录表(nand_burn_table.xml)对齐 |
配置转换
OHOS 构建复用 Linux 构建的 app.defconfig,通过转换脚本进入 GN 体系,不在 GN 侧重复维护配置:
app.defconfig ──(defconfig_to_gni.py)──▶ app.gni(应用配置)
SDK 类型/路径 ──(build_ohos.sh 生成)──▶ sdk_config.gni(SDK 参数)
与 Linux 构建的差异
| 差异点 | Linux 构建 | OHOS 构建 |
|---|---|---|
| 构建体系 | CMake | OpenHarmony GN |
| 配置流向 | app.defconfig → .config → .config.cmake |
app.defconfig → app.gni / sdk_config.gni |
| OHOS 代码 | 不需要(-g linux 下载) |
必需(默认 group 下载) |
| 内核/uboot | sdk/build.cmake 编译 BSP |
build_ohos.sh 编译 u-boot,内核由 OHOS 标准构建编译 |
| rootfs | CMake 打包 | OpenHarmony 标准构建 + busybox 后处理 |
命令参考
build.sh 常用命令格式与选项速查,设计原理见上文各节。
命令格式
子命令可省略,默认值为 build。
子命令
| 子命令 | 说明 |
|---|---|
build |
配置并编译 |
menuconfig |
启动 Kconfig TUI 交互式配置 |
build 选项
--target BOARD APP_TYPE APP_NAME
指定目标应用,自动加载案例的配置。
| 参数 | 说明 | 示例 |
|---|---|---|
BOARD |
apps/ 下的板卡目录 |
cv610_ev_board |
APP_TYPE |
应用分类 | references / samples / solutions |
APP_NAME |
应用名称 | capture_picture |
解析配置的路径:apps/<BOARD>/<APP_TYPE>/<APP_NAME>/app.defconfig
支持选项:
| 选项 | 说明 |
|---|---|
--jobs N |
并行编译数,默认取 CPU 核心数 |
-DKEY=VALUE |
传递的变量,如 -DAPP_VARIANT=FINGERTIP。可重复使用 |
menuconfig
# 从 Kconfig 默认值启动配置
bash scripts/build.sh menuconfig
# 加载 app.defconfig 作为初始配置后启动
bash scripts/build.sh menuconfig --target cv610_ev_board samples framework_media
menuconfig 子命令启动 TUI,退出TUI后自动将 .config 转换为 .config.cmake。