开发规范
概述
本文档将介绍Bundle的基本概念以及如何按照规范定义Bundle。
定义
OpenHarmony软件以bundle作为基本单元,从系统角度看,凡是运行在OpenHarmony上的软件都可以定义为Bundle;一般来讲,根据Bundle的应用范围,可以分为:
- 板级Bundle:如board、arch、mcu这些与设备硬件相关的Bundle。
- 系统Bundle:一组独立功能的集合,如内核、文件系统、框架等。
- 应用Bundle:直接面向用户提供服务的应用(如wifi_iot,ip_camera)。
从形式上看,Bundle是为复用而生,一切可以复用的模块都可以定义为Bundle,可以分为:
- 源代码
- 二进制
- 代码片段
- 发行版
Bundle划分原则
原则上应尽可能划分为细颗粒度的Bundle,以满足最大限度的复用。主要考虑以下几点:
- 独立性:Bundle的功能应该相对独立,支持独立编译,可以单独对外提供接口和服务;
- 耦合性:如果Bundle必须依赖其他的Bundle,才能对外提供服务,应考虑和被依赖的Bundle合并为一个Bundle。
- 相关性:如果一组Bundle共同完成一项功能,且没有被其他Bundle依赖,未来也没有被依赖的可能,则可以考虑合并为一个Bundle。
Bundle依赖
Bundle的依赖关系分为两种:必选依赖和可选依赖。
- 必选依赖:是指BundleA在完成某个功能时,必须引入BundleB,调用B的接口或服务配合才能完成。称B为A的必选依赖。
- 可选依赖:是在BundleA在完成某个功能时,可以引入BundleC,也可以引入BundleD。C和D可以相互替换,称C和D为A的可选依赖。
Bundle构成
一个Bundle包一般包含如下内容:
-
Bundle包的代码或库(src目录下的代码文件)
-
ohos_bundles文件夹(存放依赖的Bundle,安装Bundle时自动生成,无需提交到代码库)
-
Bundle包的说明文件(README.md)
-
Bundle包元数据声明文件(bundle.json)
-
开源许可文件(LICENSE)
my-bundle
|_ohos_bundles |_src |_bundle.json |_README.md |_LICENSE ```
代码文件
Bundle的代码文件和普通的代码目录没有差异。但要注意的是,Bundle中对外暴露的接口(头文件),会被其他Bundle所引用,需要单独在bundle.json的dirs中声明。
说明文件
README.md,为markdown格式的描述关于Bundle自述说明文件。(语法参考)
为了帮助他人在hpm上找到该Bundle,并更方便的使用它,在Bundle的根目录中包含一个README文件。
README文件可能包括如何安装,配置和使用Bundle包中的实例代码说明,以及可能会对用户有所帮助的任何其他信息。
每个Bundle的自述文件将显示在hpm系统的Bundle详情页面的描述中。
元数据描述文件
bundle.json文件是对当前Bundle的元数据描述,每个Bundle中必须包含一个bundle.json文件。
{
"name": "@myorg/demo-bundle",
"version": "1.0.0",
"license": "MIT",
"description": "bundle description",
"keywords": ["hos"],
"tags": ["applications", "drivers"],
"author": {"name":"","email":"","url":""},
"contributors":[{"name":"","email":"","url":""},{"name":"","email":"","url":""}],
"homepage": "http://www.foo.bar.com",
"repository": "https://git@gitee.com:foo/bar.git",
"publishAs": "code-segment",
"segment":{
"destPath":"/the/dest/path"
},
"dirs": {
"src": ["src/**/*.c"],
"headers": ["headers/**/*.h"],
"bin": ["bin/**/*.o"]
},
"scripts": {
"build": "make"
},
"envs": {},
"ohos": {
"os": "2.0.0",
"board": "hi3516",
"kernel": "liteos-a"
},
"rom": "10240",
"ram": "1024",
"dependencies": {
"@myorg/net":"1.0.0"
}
}
bundle.json文件具有如下功能:
-
name:定义Bundle的名称,放到组织下, 以@开头,/分割,如:@myorg/mybundle
-
version:定义Bundle版本号,如1.0.0,需满足semver的标准。
-
description:一句话对Bundle进行简要的描述。
-
dependencies:定义Bundle的依赖Bundle。
-
envs: 定义Bundle编译时所需要的参数,包括全局参数以及依赖所需的参数。
-
scripts:定义在当前Bundle下能够执行的命令(如编译,构建,测试,烧录等)。
-
publishAs:定义Bundle的发布类型(source:源码,binary:二进制,distribution:发行版,code-segment:代码片段)。
-
segment: 仅针对code-segment类型的Bundle,定义Bundle的目标路径(即安装后,Bundle包中包含的文件复制到的目标路径)
-
dirs:定义发布时打包的目录结构(如头文件)。
-
ram&rom:统计相关信息:预计占用ROM和RAM信息。
-
ohos:描述OpenHarmony系统版本、开发板及内核的匹配关系(多个请用英文逗号的“,”分割)。
-
定义其他扩展信息:作者,主页,代码仓库,许可协议,标签,关键字。
-
对于发行版类型,还有个base,可以定义继承自的发行版。
Bundle管理
依赖关系
生成基础bundle.json以后,需要继续添加Bundle依赖来实现更复杂的功能。此时需要知道所依赖Bundle的名称和版本号,并且把它们定义在bundle.json里面的dependencies字段中。
{
"name": "my-bundle",
"version": "1.0.0",
"dependencies": {
"net": "1.0.0"
}
}
上述示例中,my-bundleBundle依赖于net 1.0.0Bundle。在全局安装了 hpm CLI 工具之后,执行如下命令可以从远端仓库获取到依赖:
hpm install
依赖获取以后,会保存到当前Bundle根目录下到ohos_bundles文件夹中。Bundle以及依赖之间会形成一个依赖关系的树状结构。全局安装了 hpm CLI 工具之后,在Bundle根目录下执行如下命令:
username@server MINGW64 /f/showcase/demo/demo
$ hpm list
+--demo@1.0.0
| +--@huawei/media@1.0.2
| +--@demo/sport_hi3518ev300_liteos_a@1.0.0
| | +--@demo/app@4.0.1
| | | +--@demo/build@4.0.1
| | | +--@demo/arm_harmonyeabi_gcc@4.0.0
| | +--@demo/liteos_a@4.0.0
| | | +--@demo/third_party_fatfs@4.0.0
| | | +--@demo/arm_harmonyeabi_gcc@4.0.0
| | +--@demo/init@4.0.0
| | +--@demo/dist_tools@4.0.0
还可以使用可视化的形式,来查看当前Bundle的依赖关系,执行如下命令:
hpm ui
会在本地启动一个web服务(默认会打开浏览器并进入项目页),点击侧边栏的项目依赖图标,打开页面,可以看到项目的依赖Bundle列表,点击右侧按钮切换到树状视图,就可以看到依赖关系的图形化展示(如下图)。
hpm操作命令参考
Bundle的全生命周期管理,可以通过hpm命令工具进行操作,hpm的操作命令如下(详细帮助可以执行 hpm -h学习):
表 1 hpm操作命令
搜索Bundle,--json,可以以json格式输出 -type 可以设置搜索Bundle的类型,包括bundle,distribution,code-segment三种。 |
||
针对依赖的代码段(code-segment)Bundle,执行清理或还原操作(即根据segment.destPath执行拷贝/删除操作) |
||
Bundle版本
版本号命名规范
名称需要为全小写字母,中间可以使用中划线或者下划线分隔。比如 "bundle", "my_bundle"。
版本号的格式为 "主版本号.次版本号.修订号" 或 "主版本号.次版本号.修订号-先行版本号",比如 "1.0.0", "1.0.0-beta",详细规格可以参考 https://semver.org。
版本发布
为了使Bundle能被其他开发者使用,Bundle需要上传到远端仓库。Bundle上传使用如下命令:
hpm publish
命令执行以后,系统会对的整个依赖关系进行检查,下载缺失依赖Bundle。依赖检查完成后,如果发布类型为binary,系统会对整个Bundle进行编译,生成二进制文件,然后打包上传。如果使其他上传类型,则直接根据定义的打包规则进行打包,然后上传。
注意:发布Bundle需要用户账号登录,需要先拥有hpm的系统账号后,并注册组织,申请组织认证通过后,才拥有发布的权限。
发行版
发行版通常是将一系列Bundle组合起来,成为编译可以运行的OpenHarmony解决方案镜像,里面包含了多个依赖的Bundle,以及脚本,用于描述如何完整编译、链接这些Bundle。
发行版本身通常不需要包含功能实现代码,仅包含bundle.json描述(设置publishAs为distribution)和一些编译脚本组成。
因为发行版编译的过程需要系统提供环境变量,所以发行版使用scripts脚本中内置的dist命令:
{
"publishAs":"distribution",
"scripts": {
"dist": "script compile command"
}
}
编译执行使用如下命令:
hpm dist
重新定义一个发行版所具有的功能是一个复杂的过程,所以系统允许对发行版进行继承,从而在现有功能的基础上进行定制。继承发行版需要在bundle.json中定义base字段。
{
"base": {
"name": "dist_wifi_iot",
"version": "1.0.0"
}
}
上述定义表明当前Bundle继承自发行版Bundledist-wifi-iot 1.0.0。
发行版由很多的依赖Bundle组成,通过bundle.json中的dependencies段来描述,有些依赖是必须的,有些依赖则是根据可以需求增加或删除的。bundle.json中名称前带有?的依赖表示可选依赖,继承它的发行版,可以移除掉该可选Bundle,再增加别的Bundle进行替换。
{
"dependencies": {
"?my_bundle": "1.0.0"
}
}
上述声明表示my_bundle依赖可以被移除。如果想要移除my_bundle,在上层依赖方需要使用excludes关键字来进行定义
{
"excludes": [ "my_bundle" ]
}
依赖被移除后,就不会参入Bundle的构建过程。只有标记为可选的依赖才能够被移除,强行移除未被标记的依赖会出现错误提示。
环境变量说明
Bundle在编译的过程中需要依赖系统提供的环境变量来自定义输出,链接所需二进制文件等等。这里提出的环境变量均指根据需求把所需变量注入脚本执行的上下文中。所以在脚本中可以直接获取到变量的值。下面介绍当前系统存在的几种环境变量。
全局变量由bundle.json中的envs属性来定义。整个Bundle中的依赖都可以获取到全局变量定义的值。
{
"envs": {
"compileEnv": "arm"
}
}
不同Bundle在引入依赖的过程中可以传入不同的参数,从而使依赖的编译可以满足当前Bundle的需求。依赖中定义的参数可以在对应依赖脚本执行的上下文中获取到。
{
"dependencies": {
"my-bundle": {
"version": "1.0.0",
"mode": "debug"
}
}
}
Bundle在链接二进制文件的时候,需要知道二进制文件在依赖中的路径,所以依赖的路径会作为环境变量传入编译Bundle中。
传入的环境变量的格式为DEP_BundleName,BundleName为依赖的名称,例如 DEP_first_bundle。
依赖中可以定义标签,对引入的依赖进行分组。在脚本中可以根据标签,获得这一组依赖的路径。定义的标签以#开头,具体定义的方式为:
{
"dependencies": {
"#tool": {
"first-bundle": "1.0.0",
"second-bundle": "1.0.0"
},
"#drivers": {
"xx-bundle": "1.0.0",
"yy-bundle": "1.0.0"
}
}
}
系统中存在两个固定环境变量:
- DEP_OHOS_BUNDLES:表示ohos_bundles文件夹所在的路径。
- DEP_BUNDLE_BASE:表示最外层Bundle的路径。