OpenHarmony 3.0移植实战:从vendor配置到内核编译的深度解析
移植OpenHarmony到新硬件平台是一项充满挑战的工作,尤其是当遇到各种编译错误和配置问题时。本文将从一个实战角度出发,分享在移植过程中遇到的典型问题及其解决方案,帮助开发者少走弯路。
1. vendor目录结构与初始配置
移植OpenHarmony的第一步是创建正确的vendor目录结构。这个目录包含了产品特定的配置和构建规则,是整个移植工作的基础。
1.1 创建产品目录
在vendor下创建产品目录时,需要注意几个关键点:
vendor/ └── xingyun/ └── t113_nand/ ├── BUILD.gn ├── config.json └── hals/BUILD.gn是最基础的构建文件,初始内容可以很简单:
group("t113_nand") { }但要注意group名称应与目录名保持一致,这是OpenHarmony构建系统的约定。
1.2 配置config.json
config.json是产品定义的核心文件,包含了产品的基本信息和子系统配置。一个典型的初始配置如下:
{ "product_name": "xingyun_t113_nand_board", "ohos_version": "OpenHarmony 3.0", "device_company": "xingyunelec", "board": "t113_nand_linux", "kernel_type": "linux", "kernel_version": "5.4", "subsystems": [], "third_party_dir": "//third_party", "product_adapter_dir": "//vendor/xingyun/t113_nand/hals" }这里有几个关键字段需要注意:
device_company必须对应device目录下的公司名称目录board必须对应device/company目录下的板级目录kernel_version需要与实际使用的内核版本严格一致
2. device目录配置与内核版本问题
在完成vendor配置后,需要在device目录下创建对应的板级支持包(BSP)。
2.1 设备目录结构
典型的设备目录结构如下:
device/ └── xingyunelec/ └── t113_nand_linux/ ├── BUILD.gn └── sdk_linux/ └── config.gniconfig.gni文件包含了工具链和编译选项的关键配置:
kernel_type = "linux" kernel_version = "5.4" board_cpu = "cortex-a7" board_arch = "" board_toolchain = "" board_toolchain_path = "" board_toolchain_prefix = "" board_toolchain_type = "clang" board_cflags = [ "-mfloat-abi=softfp", "-mfpu=neon-vfpv4", ] board_cxx_flags = [ "-mfloat-abi=softfp", "-mfpu=neon-vfpv4", ]2.2 内核版本冲突问题
一个常见的陷阱是内核版本冲突。即使你在config.json中指定了kernel_version=5.4,系统可能仍然尝试编译5.10内核。这是因为:
- 构建系统会首先读取build/ohos/kernel/kernel.gni中的默认值
- 如果没有在subsystems中明确指定内核组件,系统会使用默认版本
解决方案是在config.json的subsystems中添加内核组件:
{ "subsystem": "kernel", "components": [ { "component": "linux_5_4", "features":[] } ] }3. 内核组件注册与编译规则
当添加了内核组件后,可能会遇到"Component not found"错误。这是因为需要在构建系统中注册新的内核组件。
3.1 添加内核组件定义
在build/lite/components/kernel.json中添加新的内核组件定义:
{ "component": "linux_5_4", "description": "linux 5.4", "optional": "false", "dirs": ["kernel/linux/build"], "targets": ["//kernel/linux/build:linux_kernel"], "rom": "", "ram": "", "output": ["uImage_hi3516dv300_smp"], "features": [], "adapted_board": ["t113_nand_linux"], "adapted_kernel": ["linux"], "deps": { "components": [], "third_party": [] } }3.2 修改内核构建脚本
需要修改kernel/linux/build/BUILD.gn,确保变量传递正确:
command = "./kernel_module_build.sh ${outdir} ${build_type} ${clang_dir} ${product_path_rebase} ${board_name} ${kernel_version}"4. 内核patch与配置问题
内核编译过程中最常见的两类问题是patch应用失败和配置缺失。
4.1 patch文件路径问题
内核编译时会自动应用patch文件,但如果路径不正确会导致失败。关键点:
- patch文件路径由DEVICE_NAME变量决定
- 需要在kernel_module_build.sh中设置正确的DEVICE_NAME:
if [ "$5" == "t113_nand_linux" ];then export DEVICE_NAME=t113_nand_linux fi- patch文件应放置在特定目录结构下:
kernel/linux/patches/ └── linux-5.4/ └── t113_nand_linux_patch/ ├── hdf.patch ├── t113_nand_linux.patch └── t113_nand_linux_small.patch4.2 内核配置文件缺失
编译时会提示找不到默认配置文件,如:
Can't find default configuration "arch/arm/configs/t113_nand_linux_small_defconfig"!解决方案是从内核源码中复制现有配置:
cp sun8iw20p1smp_auto_nand_defconfig ../../../../config/linux-5.4/arch/arm/configs/t113_nand_linux_small_defconfig5. 内核镜像生成问题
即使内核编译通过,也可能无法生成所需的uImage文件,报错:
multiple (or no) load addresses: This is incompatible with uImages Specify LOADADDR on the commandline to build an uImage5.1 添加LOADADDR参数
需要在kernel.mk中为特定设备添加LOADADDR参数:
ifeq ($(DEVICE_NAME),t113_nand_linux) $(hide) $(KERNEL_MAKE) -C $(KERNEL_SRC_TMP_PATH) ARCH=$(KERNEL_ARCH) $(KERNEL_CROSS_COMPILE) -j64 uImage LOADADDR=0x40008000 else $(hide) $(KERNEL_MAKE) -C $(KERNEL_SRC_TMP_PATH) ARCH=$(KERNEL_ARCH) $(KERNEL_CROSS_COMPILE) -j64 uImage endifLOADADDR的值需要根据具体硬件的内存布局确定,0x40008000是一个常见的起始地址。
5.2 内核编译验证
成功编译后,应该能在输出目录中找到以下文件:
out/t113_nand_linux/xingyun_t113_nand_board/kernel/linux-5.4/arch/arm/boot/uImage这个uImage文件就是最终生成的内核镜像,可以烧写到目标设备上运行。