提交 7a35d050 编写于 作者: O openharmony_ci 提交者: Gitee

!527 文档更新

Merge pull request !527 from duangavin123/master
......@@ -86,11 +86,11 @@ OpenHarmony也提供了一系列可选的系统组件,方便设备开发者按
<td class="cellrowborder" valign="top" width="35.91359135913591%" headers="mcps1.2.4.1.3 "><a name="ul157903731520"></a><a name="ul157903731520"></a><ul id="ul157903731520"><li><a href="porting/transplant-minichip.md">轻量系统芯片移植指导</a></li><li><a href="porting/transplant-smallchip.md">小型系统芯片移植指导</a></li><li><a href="porting/transplant-thirdparty.md">三方库移植指导</a></li></ul>
</td>
</tr>
<tr id="row9601737181517"><td class="cellrowborder" valign="top" width="28.472847284728473%" headers="mcps1.2.4.1.1 "><p id="p25791037131519"><a name="p25791037131519"></a><a name="p25791037131519"></a>贡献组件</p>
<tr id="row9601737181517"><td class="cellrowborder" valign="top" width="28.472847284728473%" headers="mcps1.2.4.1.1 "><p id="p25791037131519"><a name="p25791037131519"></a><a name="p25791037131519"></a>贡献Bundle</p>
</td>
<td class="cellrowborder" valign="top" width="35.61356135613561%" headers="mcps1.2.4.1.2 "><p id="p45798376158"><a name="p45798376158"></a><a name="p45798376158"></a><span id="text16579133741518"><a name="text16579133741518"></a><a name="text16579133741518"></a>OpenHarmony</span>贡献功能组件</p>
<td class="cellrowborder" valign="top" width="35.61356135613561%" headers="mcps1.2.4.1.2 "><p id="p45798376158"><a name="p45798376158"></a><a name="p45798376158"></a><span id="text16579133741518"><a name="text16579133741518"></a><a name="text16579133741518"></a>OpenHarmony</span>贡献Bundle</p>
</td>
<td class="cellrowborder" valign="top" width="35.91359135913591%" headers="mcps1.2.4.1.3 "><a name="ul957919379156"></a><a name="ul957919379156"></a><ul id="ul957919379156"><li><a href="bundles/bundles-standard-rules.md">组件开发规范</a></li><li><a href="bundles/bundles-guide.md">组件开发指南</a></li><li><a href="bundles/bundles-demo.md">组件开发示例</a></li></ul>
<td class="cellrowborder" valign="top" width="35.91359135913591%" headers="mcps1.2.4.1.3 "><a name="ul957919379156"></a><a name="ul957919379156"></a><ul id="ul957919379156"><li><a href="bundles/oem_bundle_standard_des.md">Bundle开发规范</a></li><li><a href="bundles/bundles-guide.md">Bundle开发指南</a></li><li><a href="bundles/bundles-demo.md">Bundle开发示例</a></li></ul>
</td>
</tr>
<tr id="row260193701512"><td class="cellrowborder" valign="top" width="28.472847284728473%" headers="mcps1.2.4.1.1 "><p id="p95794372155"><a name="p95794372155"></a><a name="p95794372155"></a>参考</p>
......@@ -156,11 +156,11 @@ OpenHarmony也提供了一系列可选的系统组件,方便设备开发者按
<td class="cellrowborder" valign="top" width="36.07360736073608%" headers="mcps1.2.4.1.3 "><a name="ul14724164204819"></a><a name="ul14724164204819"></a><ul id="ul14724164204819"><li><a href="porting/transplant-thirdparty.md">三方库移植指导</a></li><li><a href="porting/standard-system-porting-guide.md">标准系统芯片移植指导</a></li></ul>
</td>
</tr>
<tr id="row869853125119"><td class="cellrowborder" valign="top" width="27.872787278727873%" headers="mcps1.2.4.1.1 "><p id="p3691530511"><a name="p3691530511"></a><a name="p3691530511"></a>贡献组件</p>
<tr id="row869853125119"><td class="cellrowborder" valign="top" width="27.872787278727873%" headers="mcps1.2.4.1.1 "><p id="p3691530511"><a name="p3691530511"></a><a name="p3691530511"></a>贡献Bundle</p>
</td>
<td class="cellrowborder" valign="top" width="36.053605360536054%" headers="mcps1.2.4.1.2 "><p id="p1469115335113"><a name="p1469115335113"></a><a name="p1469115335113"></a><span id="text6691253155112"><a name="text6691253155112"></a><a name="text6691253155112"></a>OpenHarmony</span>贡献功能组件</p>
<td class="cellrowborder" valign="top" width="36.053605360536054%" headers="mcps1.2.4.1.2 "><p id="p1469115335113"><a name="p1469115335113"></a><a name="p1469115335113"></a><span id="text6691253155112"><a name="text6691253155112"></a><a name="text6691253155112"></a>OpenHarmony</span>贡献Bundle</p>
</td>
<td class="cellrowborder" valign="top" width="36.07360736073608%" headers="mcps1.2.4.1.3 "><a name="ul87045395116"></a><a name="ul87045395116"></a><ul id="ul87045395116"><li><a href="bundles/bundles-standard-rules.md">组件开发规范</a></li><li><a href="bundles/bundles-guide.md">组件开发指南</a></li><li><a href="bundles/bundles-demo.md">组件开发示例</a></li></ul>
<td class="cellrowborder" valign="top" width="36.07360736073608%" headers="mcps1.2.4.1.3 "><a name="ul87045395116"></a><a name="ul87045395116"></a><ul id="ul87045395116"><li><a href="bundles/oem_bundle_standard_des.md">Bundle开发规范</a></li><li><a href="bundles/bundles-guide.md">Bundle开发指南</a></li><li><a href="bundles/bundles-demo.md">Bundle开发示例</a></li></ul>
</td>
</tr>
<tr id="row1170153125110"><td class="cellrowborder" valign="top" width="27.872787278727873%" headers="mcps1.2.4.1.1 "><p id="p16701253195118"><a name="p16701253195118"></a><a name="p16701253195118"></a>参考</p>
......
# 组件开发指南
# Bundle开发指南
- [组件开发规范](bundles-standard-rules.md)
- [组件开发指南](bundles-guide.md)
- [组件开发指南](bundles-guide-overview.md)
- [准备工作](bundles-guide-prepare.md)
- [组件开发](bundles-guide-develop.md)
- [组件开发示例](bundles-demo.md)
- [开发规范](oem_bundle_standard_des.md)
- [开发指南](bundles-guide.md)
- [概述](bundles-guide-overview.md)
- [安装hpm命令行工具](bundles-guide-prepare.md)
- [开发Bundle](bundles-guide-develop.md)
- [开发示例](bundles-demo.md)
- [HPM介绍](bundles-demo-hpmdescription.md)
- [环境准备](bundles-demo-environment.md)
- [编译环境准备](bundles-demo-environment.md)
- [操作实例](bundles-demo-devsample.md)
# 操作实例<a name="ZH-CN_TOPIC_0000001072143838"></a>
环境准备好后,接下来本文以Hi3861平台为例,演示如何利用HPM进行组件的安装、编译和打包
环境准备好后,接下来本文以Hi3861平台为例,演示如何利用hpm进行发行版的安装、编译
1. 执行以下命令,初始化安装目录(目录名可自行设置):
1. 执行以下命令,创建目录,并根据模板dist创建一个默认工程(目录名可自行设置):
```
mkdir test3861
cd test3861
hpm init -t dist
hpm init -t dist myproduct
```
初始化成功则显示:
创建成功则显示:
```
Initialization finished.
```
2. 安装wifi\_iot发行版。
2. 安装hispark\_pegasus发行版。
```
hpm install @ohos/wifi_iot
hpm install @ohos/hispark_pegasus
```
安装成功则显示:
......@@ -31,11 +31,11 @@
>![](../public_sys-resources/icon-note.gif) **说明:**
>Hi3516平台采用下述命令:
>```
>hpm install @ohos/ip_camera_hi3516dv300
>hpm install @ohos/hispark_taurus
>```
>Hi3518平台采用下述命令:
>```
>hpm install @ohos/ip_camera_hi3518ev300
>hpm install @ohos/hispark_aries
>```
3. 编译打包
......
# 环境准备<a name="ZH-CN_TOPIC_0000001071315859"></a>
# 编译环境准备<a name="ZH-CN_TOPIC_0000001071315859"></a>
- [linux服务器](#section20979554791)
- [安装Node.js](#section9954105413153)
- [安装HPM](#section15937194904819)
- [安装HPM命令行工具](#section15937194904819)
- [安装python环境](#section1621819180417)
- [安装文件打包工具](#section77617165913)
- [安装SCons](#section20558439191516)
- [安装SCons](#section873135716233)
![](figure/3516dv300.png)
## linux服务器<a name="section20979554791"></a>
准备一台装有Ubuntu 16.04 及以上 64 位系统的linux服务器(hpm是支持windows的,但是目前OpenHarmony开源的Hi3861、Hi3516、Hi3518三个解决方案都只支持Ubuntu)。
准备一台装有Ubuntu 16.04 及以上 64 位系统的linux服务器(当前未完全支持window环境下的编译)。
将linux shell改为bash:
......@@ -25,12 +27,6 @@ ln -s bash /bin/sh
## 安装Node.js<a name="section9954105413153"></a>
>![](../public_sys-resources/icon-note.gif) **说明:**
>如果配置的源的nodejs版本太低,可以执行以下语句后再执行apt-get install:
>```
>curl -L https://deb.nodesource.com/setup_12.x | bash
>```
推荐安装 Node.js 12.x (包含 npm 6.14.4)或更高版本(推荐 12.13.0+):
```
......@@ -45,7 +41,7 @@ node --version # 查看nodejs版本
npm --version # 查看npm版本
```
## 安装HPM<a name="section15937194904819"></a>
## 安装HPM命令行工具<a name="section15937194904819"></a>
通过 Node.js 自带的 npm(使用默认的源 https://registry.npmjs.org/ )安装 hpm-cli 命令行工具:
......@@ -59,7 +55,7 @@ npm install -g @ohos/hpm-cli
hpm config
```
上述命令执行后将会显示hpm的默认配置,您可以根据自己的喜好对默认配置进行修改,以下是hpm的常用配置:
上述命令执行后将会显示hpm的默认配置,您可以根据实际情况对默认配置进行修改,以下是hpm的常用配置:
```
registry = https://hpm.harmonyos.com # hpm注册中心地址,下载组件必须
......@@ -68,7 +64,7 @@ http_proxy = http://your-proxy-server:port # 配置HTTP代理
https_proxy = http://your-proxy-server:port # 配置HTTPS代理
```
hpm-cli的命令介绍可以参考:[hpm操作命令](bundles-standard-rules.md)
hpm-cli的命令介绍可以参考:[hpm操作命令](oem_bundle_standard_des.md)
## 安装python环境<a name="section1621819180417"></a>
......@@ -115,7 +111,7 @@ sudo apt-get install mtools
>![](../public_sys-resources/icon-note.gif) **说明:**
>Hi3518和Hi3516两种平台需要安装打包工具,Hi3861平台不需要。
## 安装SCons<a name="section20558439191516"></a>
## 安装SCons<a name="section873135716233"></a>
1. 打开Linux编译服务器终端。
2. 运行如下命令,安装SCons安装包。
......@@ -131,7 +127,7 @@ sudo apt-get install mtools
```
**图 1** SCons安装成功界面,版本要求3.0.4以上<a name="fig235815252492"></a>
![](figure/SCons安装成功界面-版本要求3-0-4以上-21.png "SCons安装成功界面-版本要求3-0-4以上-21")
![](figure/SCons安装成功界面-版本要求3-0-4以上-27.png "SCons安装成功界面-版本要求3-0-4以上-27")
>![](../public_sys-resources/icon-note.gif) **说明:**
......
# HPM介绍<a name="ZH-CN_TOPIC_0000001071487274"></a>
随着OpenHarmony正式开源,HPM包管理器也应运而生。HPM全称HarmonyOS Package Manager,是OpenHarmony组件包的管理和分发工具。HPM主要是面向设备开发者,用于获取/定制OpenHarmony源码,执行安装、编译、打包、升级等操作的工具集。本文档将向开发者介绍如何使用HPM工具进行OpenHarmony组件的安装、编译、打包等操作。
HPM是OpenHarmony Bundle的管理和分发工具。HPM主要是面向OpenHarmony开发者,用于获取/定制OpenHarmony源码,执行安装依赖、编译、打包、升级等操作的工具集。本文档将向开发者介绍如何使用HPM工具进行OpenHarmonyBundle的安装、编译、打包等操作。
# 组件开发示例<a name="ZH-CN_TOPIC_0000001157479397"></a>
# 开发示例<a name="ZH-CN_TOPIC_0000001157479397"></a>
- **[HPM介绍](bundles-demo-hpmdescription.md)**
- **[环境准备](bundles-demo-environment.md)**
- **[编译环境准备](bundles-demo-environment.md)**
- **[操作实例](bundles-demo-devsample.md)**
......
# 组件开发<a name="ZH-CN_TOPIC_0000001051690861"></a>
- [创建OpenHarmony组件](#section1976410130540)
- [新建组件](#section717481119145)
- [改造组件](#section102861955201410)
- [从模板创建组件](#section15882846181510)
- [编译组件](#section136732148541)
# 开发Bundle<a name="ZH-CN_TOPIC_0000001051690861"></a>
- [创建Bundle](#section717481119145)
- [将现有工程定义为Bundle](#section102861955201410)
- [发布Bundle到HPM平台](#section1318574233211)
- [引用Bundle](#section57959284315)
- [全局安装Bundle](#section647375516313)
- [编译Bundle](#section7972161715325)
- [定义编译脚本](#section10274147111610)
- [执行编译](#section879301916172)
- [定义发行版](#section413216495619)
- [定义发行版](#section127388393326)
- [定义脚本](#section11503171219190)
- [发行](#section4694125521912)
- [烧录](#section1746331545413)
- [运行调试](#section6742131615549)
## 创建OpenHarmony组件<a name="section1976410130540"></a>
- [编译发行版](#section4694125521912)
- [烧录](#section2061514431039)
创建OpenHarmony组件有如下几种方式:
创建OpenHarmonyBundle有如下几种方式:
- 从头开发一个全新的组件。
- 将一个现有的非组件的代码改造成组件。
- hpm提供了一些组件模板方便快速创建组件。
- 从头创建一个全新的Bundle。
- 将一个现有的源码项目定义为Bundle。
## 新建组件<a name="section717481119145"></a>
## 创建Bundle<a name="section717481119145"></a>
通常情况下,[HPM网站](https://hpm.harmonyOS.com)上能找到您开发常用的组件,如果现有的组件不能完全满足开发,这时可以自己动手开发一个组件
通常情况下,[HPM网站](https://hpm.harmonyOS.com)上能找到您开发常用的Bundle,如果现有的Bundle不能完全满足开发,这时可以自己动手开发一个Bundle
如果您愿意,可以将组件发布到HPM的仓库中供其他用户使用。假设要在D:/source目录下新建一个全新的组件my-bundle:
如果您愿意,可以将Bundle发布到HPM的仓库中供其他用户使用。
可以使用hpm init 创建该组件的脚手架代码,例如,进入D:/source目录,执行如下命令:
假设要在D:/source目录下新建一个全新的Bundle:my-bundle,可以使用hpm init 创建该Bundle的脚手架代码,例如,进入D:/source目录,执行如下命令:
```
hpm init -t default -d demo my-bundle
hpm init -t default -d demo mybundle
```
会在 source 目录下生成如下文件
将使用'default' 模板 在当前目录下的demo路径下,创建一个名为mybundle的Bundle
```
mybundle
├── bundle.json # 组件元数据描述文件
├── example # 测试组件功能的示例
│ └── main.c
├── include # 组件的内部头文件
│ └── mybundle.h
├── README.md # 组件的简要说明
└── src # 组件的源代码
└─ mybundle.c
demo
├── headers # 头文件(样例)
│ └── main.h
└── src # 源代码(样例)
│ └─ main.c
├── bundle.json # 元数据声明文件
└── LICENSE # 许可协议文本
└── Makefile # 编译描述文件(样例)
└── README.md # Bundle的自述文件
```
接下来根据您的业务需要,实现组件内部的功能代码,完成代码开发后,通过git将代码(包括bundle.json文件)提交到组件代码托管仓库中(如gitee)。
接下来根据您的业务需要,实现Bundle内部的功能代码,以及编译脚本,完成代码开发后,通过git将代码(包括bundle.json文件)提交到组件代码托管仓库中(如gitee)。
>![](../public_sys-resources/icon-note.gif) **说明:**
>```
>hpm init -t {templatename} -d {dir} {name}
>```
>- -t \{templatename\} :指的是模板名称。
>- -d \{dir\}:是要创建的Bundle所存放的路径。
>- name:为要创建的Bundle名称。
hpm 除了提供了少量默认模板之外,其他模板均存储在服务器端,可以使用命令hpm search -t template 从服务器端搜索模板。
## 改造组件<a name="section102861955201410"></a>
![](figure/zh-cn_image_0000001141641532.png)
如果您已经有了代码,只是还不满足OpenHarmony的组件结构,需要改造成为hpm的组件包,只需要在当前要改造的代码目录下(例如mybundle2),执行如下命令,会提示您输入组件名称和版本。
## 将现有工程定义为Bundle<a name="section102861955201410"></a>
如果您已经有了代码工程,需要分发的HPM平台,只需要在当前工程目录下(例如mybundle2),执行如下命令,会引导您输入组件名称和版本等信息。
```
hpm init
```
1. 输入名称后回车(如mybundle2)。
2. 输入版本后(如1.0.0)回车,在当前组件目录下会生成一个bundle.json文件。
3. 打开bundle.json文件再添加其他的描述,这时候他已经是一个具备可发布的组件了
2. 接下来依次输入版本、描述等信息后,会在当前目录下会生成一个bundle.json文件。
3. 也可以打开bundle.json文件
```
$ hpm init
Your bundle will be created in dirname E:\demo\mybundle2
Your bundle will be created in directory ~\demo\mybundle2
? bundle name mybundel2
? version 1.0.0
Init finished!
...
Initialization finished.
```
1. 打开bundle.json文件修改其他信息(如作者,代码仓库,代码目录,命令脚本,依赖组件等),如下
1. 打开bundle.json文件修改其他信息(如作者,代码仓库,代码目录,命令脚本,依赖组件等),如下(仅示意)
```
{
"name": "mybundle2",
"version": "1.0.0",
"publishAs": "source",
"publishAs": "code-segment",
"dirs":{
".":[
"README.md"
],
"src":[
"test.c"
],
"header":[
"header/test.h"
],
"src/common":[
"src/common/foobar.txt"
]
".":["README.md"],
"src":["test.c"],
"header":["header/test.h" ],
"src/common":["src/common/foobar.txt"]
},
"scripts": {
"build": "make -${args}"
"build": "make -${args}"
},
"dependencies": {
"@ohos/cjson": "^1.0.0",
"@ohos/": "^1.2.0"
"@ohos/cjson": "^1.0.0",
"@ohos/foobar": "^1.2.0"
}
}
```
## 从模板创建组件<a name="section15882846181510"></a>
## 发布Bundle到HPM平台<a name="section1318574233211"></a>
hpm 除了提供了默认模板 default和simple两个简单的模板之外,其他模板均存储在服务器端
要在发布Bundle到HPM,你需要先具备账号,并创建组织,创建组织的条件及详细步骤请参考hpm网站上的帮助说明
可以使用命令hpm search -t template 从服务器端搜索模板
完成账号申请和组织创建(或者加入一个现有的组织)后,您需要根据个人的邀请码(在HPM网站的个人中心页查看),在本机生成公钥,并在HPM网站的个人中心配置
![](figure/zh-cn_image_0000001051452177.png)
```
hpm config set loginUser {your-invitation-code}
hpm gen-keys
```
生成的文件将会存放在 \~\\Users\\yourname\\.hpm\\key 下,将公钥文件\(publicKey\_your-accout.pem\)中内容拷贝到 HPM 个人中心的 SSH 公钥中。
根据description简要中的描述,找到适合的模板,基于模板可以快速创建一个组件的脚手架,执行如下初始化命令(指定-t -d 参数)。
完成上述操作后,你就具备了在您的组织内发布Bundle的权限了。
在bundle所在目录,执行命令hpm publish,将会完成组件的打包发布操作。
```
hpm init -t {templatename} -d dir name
hpm publish
```
- \{templatename\} :指的是模板名称。
- -d 后面的参数dir:是要创建的组件所存放的路径。
- name:为要创建的组件名称。
>![](../public_sys-resources/icon-note.gif) **说明:**
>- 为避免Bundle名称冲突,发布的Bundle的名称需限定在组织范围内,即命名为@org\_name/bundle\_name的格式。
>- 你的账号也必须是org\_name内的成员,才可以发布或更新组织内的Bundle。
>- 发布的组件,需要通过安全及内容审核,才能正式生效。
## 引用Bundle<a name="section57959284315"></a>
通常开发一个项目,需要引用其他的组件以加快特定功能的开发,可以采用安装依赖的方式。
首先去HPM网站,根据关键字去搜索满足您的需求的组件,找到合适的组件后,将其引入到您的工程。
## 编译组件<a name="section136732148541"></a>
在您的bundle工程中(工程目录中必须包含bundle.json文件)执行如下命令:
```
$ hpm install @scope/the_bundle
```
引用的bundle将会被安装到你的工程所在的目录的 ohos\_bundle下
```
project
├── ohos_bundle
│ └── scope
│ └─ the_bundle # <---引用的组件将会出现在这
└── src
│ └─ main.c
├── bundle.json # 元数据声明文件
└── LICENSE
└── Makefile
└── README.md
```
打开bundle.json文件,可以看到bundle已经被引入到您的工程的依赖中。
```
{
"dependencies": {
"@scope/the_bundle": "^1.0.0"
}
}
```
完成代码开发后,需要对组件进行编译。hpm提供了命令集成的能力,您可以选择任意的适合项目的编译工具(如make,gcc,gn等等)。只需在当前项目的bundle.json文件中定义scripts脚本中的build命令,就可以通过执行hpm build执行编译。
您也可以一次性在此文件中编辑多个Bundle的依赖
```
{
"dependencies": {
"@scope/the_bundle1": "^1.0.0",
"@scope/the_bundle2": "^2.0.0",
"@scope/the_bundle3": "^3.0.0",
"@scope/the_bundle4": "^1.1.0"
}
}
```
再执行hpm install命令,将会一次性将所有未安装的Bundle一次性全部下载并安装完成。
## 全局安装Bundle<a name="section647375516313"></a>
如果引用的Bundle是多个项目共用的组件(如编译工具链),你可以全局安装
在您的bundle工程中(工程目录中必须包含bundle.json文件)执行如下命令:
```
$ hpm install -g @scope/the_tool
```
引用的bundle将会被安装到你在hpm config中设置的globalRepo所指定的目录下:
```
~\.hpm\global
│ └── scope
│ └─ the_tool # <---引用的组件将会出现在这
```
>![](../public_sys-resources/icon-note.gif) **说明:**
>- 在项目安装的Bundle,在执行hpm编译命令时可以通过引用环境变量 DEP\_SCOPE\_bundle\_name,例如:
>通过 hpm i @opensource/gn 安装后,可以编辑bundle.json中的编译脚本,如下:
>```
>"scripts": {
> "build": "${DEP_OPENSOURCE_gn}/gn --version"
> },
>```
>然后就可以通过执行hpm build将调用gn的功能。
>- 在全局安装的Bundle,可以通过设置系统环境变量,直接调用,或者hpm config set key value的方式,通过 $\{key\}/tool\_name 的方式 引用,例如:
>```
>hpm i -g @ohos/opensource/gn
>hpm config BUILD_SYS_GN ~/.hpm/global/ohos_bundles/opensource/gn
>```
>可以编辑bundle.json中的编译脚本,如下:
>```
>"scripts": {
> "build": "${BUILD_SYS_GN}/gn --version"
> },
>```
>然后就可以通过执行hpm build将调用gn的功能。
## 编译Bundle<a name="section7972161715325"></a>
完成代码开发后,如果Bundle的代码是可以独立编译的,可以配置编译工具和脚本以完成二进制的生成。
hpm具备命令集成的能力,您可以选择任意的适合项目所采用的语言编译工具(如make,gcc,gn等等)。只需在当前项目的bundle.json文件中定义scripts脚本中的build命令,就可以通过执行hpm build执行编译。
## 定义编译脚本<a name="section10274147111610"></a>
......@@ -172,37 +277,54 @@ hpm build
在完成一系列的编译动作后,显示build succeed。检查编译的输出结果:
![](figure/zh-cn_image_0000001051770876.png)
![](figure/zh-cn_image_0000001188041297.png)
## 定义发行版<a name="section127388393326"></a>
## 定义发行版<a name="section413216495619"></a>
发行版的元数据文件中定义了其依赖的Bundles,以及如何编译、链接这些bundles,生成镜像文件。
发行版是将一组组件组合起来的,编译生成可以运行的OpenHarmony解决方案,里面包含了较多依赖的组件,以及以脚本形式描述如何完整编译、链接这些组件。
示例如下(以下示例的编译命令dist,采用hb编译框架描述)
## 定义脚本<a name="section11503171219190"></a>
bundle.json中定义
bundle.json中定义如下(示例)
```
{
"name": "my_dist",
"version": "1.0.0",
"name": "@your/dist_name",
"version": "2.2.0",
"publishAs": "distribution",
"description": "describe it",
"scripts": {
"dist": "make -${args}"
},
"base": {
"name": "dist-bundle",
"version": "1.0.0"
},
"config_hb": "hb set -root $DEP_BUNDLE_BASE",
"dist": "PATH=/root/.local/bin:${DEP_OHOS_gn}:${DEP_OHOS_ninja}/ninja:${DEP_OHOS_llvm}/llvm/bin:${DEP_OHOS_hc_gen}/hc-gen:${PATH} && ./scripts/dist.sh"
},
"envs": {
"args": "x86"
},
"debug": false
},
"dirs": {
"scripts": "scripts/*"
},
"dependencies": {
}
"@ohos/build_lite": "2.2.0",
"@ohos/gn": "1.1.1",
"@ohos/llvm": "1.1.1",
"@ohos/hc_gen": "1.1.0",
"@ohos/ninja": "1.1.0",
......
},
"ohos": {
"os": "2.2-Beta",
"board": "hi3516",
"kernel": "liteos-a"
},
"keywords": [ "hispark", "hi3516" ],
"repository": "https://gitee.com/openharmony/your-project",
"license": "Apache V2"
}
```
## 发行<a name="section4694125521912"></a>
## 编译发行版<a name="section4694125521912"></a>
在当前发行版根目录下,执行如下命令。
......@@ -210,7 +332,7 @@ bundle.json中定义
hpm dist
```
hpm-cli工具会自动执行编译,打包操作,将根据scripts定义的dist脚本生成镜像文件,如:
hpm-cli工具会自动执行编译,生成镜像文件,如:
```
out
......@@ -218,23 +340,23 @@ out
|-xx.file
```
## 烧录<a name="section1746331545413"></a>
## 烧录<a name="section2061514431039"></a>
发行版的编译结果可以烧录到设备中运行,例如使用hiburn工具进行烧录。在发行版的bundle.json文件配置烧录参数。
```
"scripts": {
"flash": "{$DEP_HIBURN}/hiburn"
"flash": "{$DEP_HIBURN}/hiburn"
},
```
配置烧录相关的参数(参考烧录工具的说明进行配置)。
设置烧录命令行工具的所在路径,配置烧录相关的参数(参考烧录工具的说明进行配置)。
```
hpm config set DEP_HIBURN {hiburn_path}
hpm run flash
```
## 运行调试<a name="section6742131615549"></a>
将发行版的镜像烧录到设备中后,就可以启动运行调试了,由于运行调试和具体的开发板和IDE调试工具相关,此处不再详细描述。
>![](../public_sys-resources/icon-note.gif) **说明:**
>上述仅描述如何定义bundle.json的样例,烧录工具取决于实际开发板所需的工具。
# 概述<a name="ZH-CN_TOPIC_0000001051452100"></a>
本章节将简要介绍如何开发OpenHarmony组件和发行版,并通过命令行工具方式完成组件创建、开发、编译、烧录、调试等开发过程。
- 一个组件(bundle)通常和一个代码仓库对应,在代码的基础上增加bundle.json、README文件、LICENSE描述文件。
- 一个发行版(distribution)是由多个组件构成的。发行版中集合了一个完整系统的各种组件(如驱动、内核、框架、应用),可以用于设备的烧录。
**表 1** 组件和发行版的差异对比
<a name="table6287133615412"></a>
<table><thead align="left"><tr id="row17288183614415"><th class="cellrowborder" valign="top" width="16.24162416241624%" id="mcps1.2.4.1.1"><p id="p528818361545"><a name="p528818361545"></a><a name="p528818361545"></a>异同点</p>
</th>
<th class="cellrowborder" valign="top" width="33.31333133313331%" id="mcps1.2.4.1.2"><p id="p1288836247"><a name="p1288836247"></a><a name="p1288836247"></a>组件</p>
</th>
<th class="cellrowborder" valign="top" width="50.44504450445044%" id="mcps1.2.4.1.3"><p id="p112885362418"><a name="p112885362418"></a><a name="p112885362418"></a>发行版</p>
</th>
</tr>
</thead>
<tbody><tr id="row1728813361848"><td class="cellrowborder" valign="top" width="16.24162416241624%" headers="mcps1.2.4.1.1 "><p id="p2010613564815"><a name="p2010613564815"></a><a name="p2010613564815"></a>应用场景</p>
</td>
<td class="cellrowborder" valign="top" width="33.31333133313331%" headers="mcps1.2.4.1.2 "><p id="p1910555184818"><a name="p1910555184818"></a><a name="p1910555184818"></a>面向功能特性开发</p>
</td>
<td class="cellrowborder" valign="top" width="50.44504450445044%" headers="mcps1.2.4.1.3 "><p id="p13871955484"><a name="p13871955484"></a><a name="p13871955484"></a>面向系统开发</p>
</td>
</tr>
<tr id="row676745614472"><td class="cellrowborder" valign="top" width="16.24162416241624%" headers="mcps1.2.4.1.1 "><p id="p1028816365414"><a name="p1028816365414"></a><a name="p1028816365414"></a>内容</p>
</td>
<td class="cellrowborder" valign="top" width="33.31333133313331%" headers="mcps1.2.4.1.2 "><p id="p428812361042"><a name="p428812361042"></a><a name="p428812361042"></a>功能或特性的实现代码或二进制库</p>
</td>
<td class="cellrowborder" valign="top" width="50.44504450445044%" headers="mcps1.2.4.1.3 "><p id="p328817366417"><a name="p328817366417"></a><a name="p328817366417"></a>依赖的组件清单及编译构建脚本</p>
</td>
</tr>
<tr id="row95114356"><td class="cellrowborder" valign="top" width="16.24162416241624%" headers="mcps1.2.4.1.1 "><p id="p184894513517"><a name="p184894513517"></a><a name="p184894513517"></a>完整程度</p>
</td>
<td class="cellrowborder" valign="top" width="33.31333133313331%" headers="mcps1.2.4.1.2 "><p id="p1951741155"><a name="p1951741155"></a><a name="p1951741155"></a>操作系统的一部分</p>
</td>
<td class="cellrowborder" valign="top" width="50.44504450445044%" headers="mcps1.2.4.1.3 "><p id="p20521542512"><a name="p20521542512"></a><a name="p20521542512"></a>一个完整操作系统版本</p>
</td>
</tr>
<tr id="row13581419518"><td class="cellrowborder" valign="top" width="16.24162416241624%" headers="mcps1.2.4.1.1 "><p id="p859171059"><a name="p859171059"></a><a name="p859171059"></a>编译后结果</p>
</td>
<td class="cellrowborder" valign="top" width="33.31333133313331%" headers="mcps1.2.4.1.2 "><p id="p259201355"><a name="p259201355"></a><a name="p259201355"></a>组件包</p>
</td>
<td class="cellrowborder" valign="top" width="50.44504450445044%" headers="mcps1.2.4.1.3 "><p id="p459414519"><a name="p459414519"></a><a name="p459414519"></a>系统镜像</p>
</td>
</tr>
</tbody>
</table>
**图 1** 组件和发行版的构成<a name="fig85033524124"></a>
![](figure/组件0924.png)
- [Bundle](#section196713235514)
- [Distribution](#section155387501033)
本章节将介绍OpenHarmony中的Bundle相关概念以及如何定义Bundle,并以一个示例说明如何使用hpm命令行工具完成Bundle的创建、开发、编译、发布、安装使用的全过程。
## Bundle<a name="section196713235514"></a>
Bundle是OpenHarmony中一个用来表示分发单元的术语,等同于包,一个Bundle中通常包含以下内容:
- 被分发的二进制文件(二进制类型)
- 被分发的源代码文件(源代码/代码片段类型)
- 编译脚本(发行版类型需要)
- 自身的说明文件
- bundle.json:元数据声明(名称,版本,依赖等)
- LICENSE:许可协议文本
- README.md:自述文件
- CHANGELOG.md:变更日志(可选)
>![](../public_sys-resources/icon-note.gif) **说明:**
>Bundle的类型可以分为二进制,源代码,代码片段,模板,插件,发行版等。一个Bundle可以依赖其他的Bundles,依赖关系为有向无环图
一个Bundle被发布到HPM服务器(https://hpm.harmonyos.com)后,另外一些开发者就可以通过hpm包管理器下载安装使用 。
一个Bundle在命名空间内拥有唯一的名称(命名格式为:@scope/name),可以进行独立的版本演进。
## Distribution<a name="section155387501033"></a>
Distribution是OpenHarmony的发行版,是一个完整的操作系统版本,集合了各种Bundle(驱动,内核,框架,应用等),也通过Bundle在HPM平台分发。
>![](../public_sys-resources/icon-note.gif) **说明:**
>发行版的元数据中仅描述了依赖的Bundles以及如何编译该发行版的编译脚本,并不包含发行版的二进制镜像。下载发行版后,需要在本地将依赖的Bundles下载下来,安装编译后才能得到可用于烧录的系统镜像文件。
>发行版可以继承,即在一个既有的发行版的基础上,通过增加/删除Bundle形成新的发行版,以实现发行版的定制。
**图 1** 组Bundle和Distribution的关系<a name="fig85033524124"></a>
![](figure/组件和发行版的构成-英文.png)
# 准备工作<a name="ZH-CN_TOPIC_0000001051770836"></a>
# 安装hpm命令行工具<a name="ZH-CN_TOPIC_0000001051770836"></a>
- [硬件要求](#section98535485518)
- [安装Node.js和hpm命令行工具](#section106591616205311)
- [更改hpm的配置(可选)](#section71821165412)
- [下载OpenHarmony代码](#section102338221707)
- [安装开发依赖的组件](#section19233183315020)
- [安装](#section14480912380)
- [配置hpm(可选)](#section138983413013)
- [下载OpenHarmony代码](#section669905815300)
## 硬件要求<a name="section98535485518"></a>
要进行Bundle的开发,需要安装包管理器hpm(HarmonyOS Package Manager),这是一个基于Node.js开发的跨平台的命令行工具,所以要运行hpm,需要先安装Node.js,然后可以npm 来安装hpm。
- 准备设备开发的开发板(如Hi3861、Hi3516DV300、Hi3518EV300)
- 主机电脑(Windows工作台)
- Linux服务器
**图 1** 硬件环境连接关系<a name="fig113816181847"></a>
![](figure/硬件环境连接关系.png "硬件环境连接关系")
## 安装Node.js和hpm命令行工具<a name="section106591616205311"></a>
## 安装<a name="section14480912380"></a>
1. 安装Node.js。
......@@ -42,43 +33,41 @@
```
## 更改hpm的配置(可选)<a name="section71821165412"></a>
## 配置hpm(可选)<a name="section138983413013"></a>
安装完hpm-cli命令行工具后,执行以下命令可以查看hpm配置:
安装完hpm-cli命令行工具后,如果需要更改配置信息(如代理,shell),执行以下命令可以查看hpm配置:
```
hpm config
```
上述命令执行后将会显示hpm的默认配置,您可以根据自己的喜好对默认配置进行修改,以下是hpm的常用配置:
上述命令执行后将会显示hpm的默认配置,您可以根据自己需要对默认配置进行修改,以下是hpm的常用配置:
```
registry = https://hpm.harmonyos.com/hpm/registry/api # hpm注册中心地址,下载组件必须
login = https://hpm.harmonyos.com/hpm/auth/pk # hpm处理登录地址,发布组件必须
loginUser = {your-account} # 配置hpm登录账号,发布组件必须
shellPath = C:\WINDOWS\System32\cmd.exe # hpm命令执行使用的shell
globalRepo = C:\Users\yourname\.global # 配置全局安装的组件存放路径
http_proxy = http://your-proxy-server:port # 配置HTTP代理
https_proxy = http://your-proxy-server:port # 配置HTTPS代理
registry = https://hpm.harmonyos.com
### login Settings
# loginUser = invitation_code
#### Path Settings
shellPath = C:\WINDOWS\System32\cmd.exe
# shellPath = C:\Program Files\Git\bin\sh.exe
# globalRepo = C:\Users\username\.hpm\global
#### Network Settings
# no_proxy = *.server.com
# http_proxy = http://user:pwd@proxy_server:port
# https_proxy = http://user:pwd@proxy_server:port
# strictSsl = true
#### Other Settings
# privateSupport = true|false
# ignoreBundles = @ohos/llvm,@ohos/gn,
# OSPlatform = Auto|linux|darwin|win32
```
hpm-cli的命令介绍可以参考:[hpm操作命令](bundles-guide-overview.md)
## 下载OpenHarmony代码<a name="section102338221707"></a>
## 下载OpenHarmony代码<a name="section669905815300"></a>
参考[《源码获取》](../get-code/sourcecode-acquire.md)
## 安装开发依赖的组件<a name="section19233183315020"></a>
hpm包管理器将常用开发开发工具(如烧录,编译,压缩等)也发布成了组件。可以通过如下命令方式进行安装,执行完该命令后,系统会自动将开发依赖的工具下载安装,且这些组件只需全局安装一次。
```
hpm i -g @ohos/llvm
hpm i -g @ohos/ninja
hpm i -g @ohos/gn
hpm i -g @ohos/hc_gen
hpm i -g @ohos/sysroot
```
这是一组开发工具的组件包(如包含gn,ninja等工具),有了这些开发态的组件,就可以进行常规的源码组件的开发了。
# 组件开发指南<a name="ZH-CN_TOPIC_0000001157319417"></a>
# 开发指南<a name="ZH-CN_TOPIC_0000001157319417"></a>
- **[概述](bundles-guide-overview.md)**
- **[准备工作](bundles-guide-prepare.md)**
- **[安装hpm命令行工具](bundles-guide-prepare.md)**
- **[组件开发](bundles-guide-develop.md)**
- **[开发Bundle](bundles-guide-develop.md)**
# 组件开发指南<a name="ZH-CN_TOPIC_0000001111039520"></a>
# HPM bundle<a name="ZH-CN_TOPIC_0000001111039520"></a>
- **[组件开发规范](bundles-standard-rules.md)**
- **[组件开发规范](oem_bundle_standard_des.md)**
- **[组件开发指南](bundles-guide.md)**
- **[开发指南](bundles-guide.md)**
- **[组件开发示例](bundles-demo.md)**
- **[开发示例](bundles-demo.md)**
......@@ -26,7 +26,7 @@ OpenHarmony是由开放原子开源基金会(OpenAtom Foundation)孵化及
## 源码获取概述<a name="section12763342204"></a>
本文档将介绍如何获取OpenHarmony源码并说明OpenHarmony的源码目录结构。OpenHarmony的代码以[组件](../bundles/bundles-standard-rules.md)的形式开放,开发者可以通过如下其中一种方式获取:
本文档将介绍如何获取OpenHarmony源码并说明OpenHarmony的源码目录结构。OpenHarmony的代码以[组件](../bundles/oem_bundle_standard_des.md)的形式开放,开发者可以通过如下其中一种方式获取:
- **获取方式1**:从代码仓库获取。通过repo或git工具从代码仓库中下载,此方式可获取最新代码。
- **获取方式2**:通过HPM包管理器获取。在[HPM](https://hpm.harmonyos.com)网站,查找满足需求的开源发行版,直接下载(或者定制后下载),再通过hpm-cli命令工具将所需的组件及工具链下载、安装到本地。
......
# 内核使用指南
- [轻量和小型系统内核](kernel-lite.md)
- [轻量系统内核](kernel-lite-mini.md)
- [内核概述](kernel-lite-mini-m.md)
- [基础内核](kernel-lite-mini-basic.md)
- [中断管理](kernel-lite-mini-basic-interrupt.md)
- [基本概念](kernel-lite-mini-basic-interrupt-concept.md)
- [开发指导](kernel-lite-mini-basic-interrupt-guide.md)
- [任务管理](kernel-lite-mini-basic-task.md)
- [基本概念](kernel-lite-mini-basic-task-basic.md)
- [开发指导](kernel-lite-mini-basic-task-guide.md)
- [内存管理](kernel-lite-mini-basic-memory.md)
- [基本概念](kernel-lite-mini-basic-memory-basic.md)
- [静态内存](kernel-lite-mini-basic-memory-static.md)
- [动态内存](kernel-lite-mini-basic-memory-dynamic.md)
- [内核通信机制](kernel-lite-mini-basic-ipc.md)
- [事件](kernel-lite-mini-basic-ipc-event.md)
- [基本概念](kernel-lite-mini-basic-ipc-event-guide.md)
- [开发指导](kernel-lite-mini-basic-ipc-event-basic.md)
- [互斥锁](kernel-lite-mini-basic-ipc-mutex.md)
- [基本概念](kernel-lite-mini-basic-ipc-mutex-basic.md)
- [开发指导](kernel-lite-mini-basic-ipc-mutex-guide.md)
- [消息队列](kernel-lite-mini-basic-ipc-queue.md)
- [基本概念](kernel-lite-mini-basic-ipc-queue-basic.md)
- [开发指导](kernel-lite-mini-basic-ipc-queue-guide.md)
- [信号量](kernel-lite-mini-basic-ipc-sem.md)
- [基本概念](kernel-lite-mini-basic-ipc-sem-basic.md)
- [开发指导](kernel-lite-mini-basic-ipc-sem-guide.md)
- [时间管理](kernel-lite-basic-mini-time.md)
- [基本概念](kernel-lite-mini-basic-time-basic.md)
- [开发指导](kernel-lite-mini-basic-time-guide.md)
- [软件定时器](kernel-lite-mini-basic-soft.md)
- [基本概念](kernel-lite-mini-basic-soft-basic.md)
- [开发指导](kernel-lite-mini-basic-soft-guide.md)
- [扩展组件](kernel-lite-mini-extend.md)
- [C++支持](kernel-lite-mini-extend-support.md)
- [CPU占用率](kernel-lite-mini-extend-cpup.md)
- [基本概念](kernel-lite-mini-extend-cpup-basic.md)
- [开发指导](kernel-lite-mini-extend-cpup-guide.md)
- [文件系统](kernel-lite-mini-extend-file.md)
- [FAT](kernel-lite-mini-extend-file-fat.md)
- [LittleFS](kernel-lite-mini-extend-file-lit.md)
- [基本概念](kernel-lite-mini-extend-file-lit-basic.md)
- [开发指导](kernel-lite-mini-extend-file-lit-guide.md)
- [内核调测](kernel-lite-mini-inner.md)
- [内存调测](kernel-lite-mini-inner-debug.md)
- [内存信息统计](kernel-lite-mini-inner-debug-mes.md)
- [内存泄漏检测](kernel-lite-mini-inner-debug-det.md)
- [踩内存检测](kernel-lite-mini-inner-debug-cet.md)
- [异常调测](kernel-lite-mini-inner-exception.md)
- [Trace调测](kernel-lite-mini-inner-trace.md)
- [附录](kernel-lite-mini-app.md)
- [内核编码规范](kernel-lite-mini-app-code.md)
- [基本数据结构](kernel-lite-mini-app-data.md)
- [双向链表](kernel-lite-mini-app-data-list.md)
- [标准库支持](kernel-lite-mini-app-lib.md)
- [CMSIS支持](kernel-lite-mini-app-lib-cmsis.md)
- [POSIX支持](kernel-lite-mini-app-lib-posix.md)
- [小型系统内核](kernel-lite-small.md)
- [基础内核](kernel-lite-small-basic.md)
- [进程](kernel-lite-small-process.md)
- [线程](kernel-lite-small-thread.md)
- [内存](kernel-lite-small-memory.md)
- [网络](kernel-lite-small-net.md)
- [文件系统](kernel-lite-small-file.md)
- [VFS](kernel-lite-small-file-vfs.md)
- [NFS](kernel-lite-small-file-nfs.md)
- [RAMFS](kernel-lite-small-file-ramfs.md)
- [FAT](kernel-lite-small-file-fat.md)
- [JFFS2](kernel-lite-small-file-jffs.md)
- [标准库](kernel-lite-small-lib.md)
- [标准库](kernel-lite-small-lib-standard.md)
- [与Linux标准库的差异](kernel-lite-small-lib-differ.md)
- [调测](kernel-lite-small-shell.md)
- [Shell介绍](kernel-lite-small-shell-des.md)
- [Shell命令开发指导](kernel-lite-small-shell-guide.md)
- [Shell命令编程实例](kernel-lite-small-shell-sample.md)
- [Shell命令使用详解](kernel-lite-small-shell-cmd.md)
- [系统命令](kernel-lite-small-shell-cmd-sys.md)
- [cpup](kernel-lite-small-shell-cmd-sys-cpup.md)
- [date](kernel-lite-small-shell-cmd-sys-date.md)
- [dmesg](kernel-lite-small-shell-cmd-sys-demsg.md)
- [exec](kernel-lite-small-shell-cmd-sys-exec.md)
- [free](kernel-lite-small-shell-cmd-sys-free.md)
- [help](kernel-lite-small-shell-cmd-sys-help.md)
- [hwi](kernel-lite-small-shell-cmd-sys-hwi.md)
- [kill](kernel-lite-small-shell-cmd-sys-kill.md)
- [log](kernel-lite-small-shell-cmd-sys-log.md)
- [memcheck](kernel-lite-small-shell-cmd-sys-mem.md)
- [oom](kernel-lite-small-shell-cmd-sys-oom.md)
- [pmm](kernel-lite-small-shell-cmd-sys-pmm.md)
- [reset](kernel-lite-small-shell-cmd-sys-reset.md)
- [sem](kernel-lite-small-shell-cmd-sys-sem.md)
- [stack](kernel-lite-small-shell-cmd-sys-stack.md)
- [su](kernel-lite-small-shell-cmd-sys-su.md)
- [swtmr](kernel-lite-small-shell-cmd-sys-swymr.md)
- [systeminfo](kernel-lite-small-shell-cmd-sys-sys.md)
- [task](kernel-lite-small-shell-cmd-sys-task.md)
- [uname](kernel-lite-small-shell-cmd-sys-uname.md)
- [vmm](kernel-lite-small-shell-cmd-sys-vmm.md)
- [watch](kernel-lite-small-shell-cmd-sys-watch.md)
- [文件命令](kernel-lite-small-shell-cmd-file.md)
- [cat](kernel-lite-small-shell-cmd-file-cat.md)
- [cd](kernel-lite-small-shell-cmd-file-cd.md)
- [chgrp](kernel-lite-small-shell-cmd-file-chgrp.md)
- [chmod](kernel-lite-small-shell-cmd-file-chmod.md)
- [chown](kernel-lite-small-shell-cmd-file-chown.md)
- [cp](kernel-lite-small-shell-cmd-file-cp.md)
- [format](kernel-lite-small-shell-cmd-file-format.md)
- [ls](kernel-lite-small-shell-cmd-file-is.md)
- [lsfd](kernel-lite-small-shell-cmd-file-isfd.md)
- [mkdir](kernel-lite-small-shell-cmd-file-mkdir.md)
- [mount](kernel-lite-small-shell-cmd-file-mount.md)
- [partinfo](kernel-lite-small-shell-cmd-file-part.md)
- [partition](kernel-lite-small-shell-cmd-file-partion.md)
- [pwd](kernel-lite-small-shell-cmd-file-pwd.md)
- [rm](kernel-lite-small-shell-cmd-file-rm.md)
- [rmdir](kernel-lite-small-shell-cmd-file-rmdir.md)
- [statfs](kernel-lite-small-shell-cmd-file-sta.md)
- [sync](kernel-lite-small-shell-cmd-file-sync.md)
- [touch](kernel-lite-small-shell-cmd-file-touch.md)
- [writeproc](kernel-lite-small-shell-cmd-file-write.md)
- [umount](kernel-lite-small-shell-cmd-file-umount.md)
- [网络命令](kernel-lite-small-shell-cmd-net.md)
- [arp](kernel-lite-small-shell-cmd-net-arp.md)
- [dhclient](kernel-lite-small-shell-cmd-net-dh.md)
- [dns](kernel-lite-small-shell-cmd-net-dns.md)
- [ifconfig](kernel-lite-small-shell-cmd-net-ipc.md)
- [ipdebug](kernel-lite-small-shell-cmd-net-ipd.md)
- [netstat](kernel-lite-small-shell-cmd-net-net.md)
- [ntpdate](kernel-lite-small-shell-cmd-net-ntp.md)
- [ping](kernel-lite-small-shell-cmd-net-ping.md)
- [ping6](kernel-lite-small-shell-cmd-net-ping6.md)
- [telnet](kernel-lite-small-shell-cmd-net-tel.md)
- [tftp](kernel-lite-small-shell-cmd-net-tftp.md)
- [魔法键使用方法](kernel-lite-small-shell-cmd-mag.md)
- [用户态异常信息说明](kernel-lite-small-shell-cmd-abn.md)
- [轻量系统内核](kernel-mini.md)
- [内核概述](kernel-mini-overview.md)
- [基础内核](kernel-mini-basic.md)
- [中断管理](kernel-mini-basic-interrupt.md)
- [基本概念](kernel-mini-basic-interrupt-concept.md)
- [开发指导](kernel-mini-basic-interrupt-guide.md)
- [任务管理](kernel-mini-basic-task.md)
- [基本概念](kernel-mini-basic-task-basic.md)
- [开发指导](kernel-mini-basic-task-guide.md)
- [内存管理](kernel-mini-basic-memory.md)
- [基本概念](kernel-mini-basic-memory-basic.md)
- [静态内存](kernel-mini-basic-memory-static.md)
- [动态内存](kernel-mini-basic-memory-dynamic.md)
- [内核通信机制](kernel-mini-basic-ipc.md)
- [事件](kernel-mini-basic-ipc-event.md)
- [基本概念](kernel-mini-basic-ipc-event-basic.md)
- [开发指导](kernel-mini-basic-ipc-event-guide.md)
- [互斥锁](kernel-mini-basic-ipc-mutex.md)
- [基本概念](kernel-mini-basic-ipc-mutex-basic.md)
- [开发指导](kernel-mini-basic-ipc-mutex-guide.md)
- [消息队列](kernel-mini-basic-ipc-queue.md)
- [基本概念](kernel-mini-basic-ipc-queue-basic.md)
- [开发指导](kernel-mini-basic-ipc-queue-guide.md)
- [信号量](kernel-mini-basic-ipc-sem.md)
- [基本概念](kernel-mini-basic-ipc-sem-basic.md)
- [开发指导](kernel-mini-basic-ipc-sem-guide.md)
- [时间管理](kernel-basic-mini-time.md)
- [基本概念](kernel-mini-basic-time-basic.md)
- [开发指导](kernel-mini-basic-time-guide.md)
- [软件定时器](kernel-mini-basic-soft.md)
- [基本概念](kernel-mini-basic-soft-basic.md)
- [开发指导](kernel-mini-basic-soft-guide.md)
- [扩展组件](kernel-mini-extend.md)
- [C++支持](kernel-mini-extend-support.md)
- [CPU占用率](kernel-mini-extend-cpup.md)
- [基本概念](kernel-mini-extend-cpup-basic.md)
- [开发指导](kernel-mini-extend-cpup-guide.md)
- [动态加载](kernel-mini-extend-dynamic-loading.md)
- [基本概念](kernel-mini-extend-dynamic-loading-basic.md)
- [开发指导](kernel-mini-extend-dynamic-loading-guide.md)
- [文件系统](kernel-mini-extend-file.md)
- [FAT](kernel-mini-extend-file-fat.md)
- [LittleFS](kernel-mini-extend-file-lit.md)
- [基本概念](kernel-mini-extend-file-littlefs-basic.md)
- [开发指导](kernel-mini-extend-file-littlefs-guide.md)
- [内核调测](kernel-memory-inner.md)
- [内存调测](kernel-mini-memory-debug.md)
- [内存信息统计](kernel-mini-memory-debug-mes.md)
- [内存泄漏检测](kernel-mini-imemory-debug-det.md)
- [踩内存检测](kernel-mini-memory-debug-cet.md)
- [异常调测](kernel-mini-memory-exception.md)
- [Trace调测](kernel-mini-memory-trace.md)
- [附录](kernel-mini-app.md)
- [内核编码规范](kernel-mini-appx-code.md)
- [基本数据结构](kernel-mini-appx-data.md)
- [双向链表](kernel-mini-appx-data-list.md)
- [标准库支持](kernel-mini-appx-lib.md)
- [CMSIS支持](kernel-mini-appx-lib-cmsis.md)
- [POSIX支持](kernel-mini-appx-lib-posix.md)
- [小型系统内核](kernel-small.md)
- [内核概述](kernel-small-overview.md)
- [内核启动](kernel-small-start.md)
- [内核态启动](kernel-small-start-kernel.md)
- [用户态启动](kernel-small-start-user.md)
- [基础内核](kernel-small-basics.md)
- [中断及异常处理](kernel-small-basic-interrupt.md)
- [进程管理](kernel-small-basic-process.md)
- [进程](kernel-small-basic-process-process.md)
- [线程](kernel-small-basic-process-thread.md)
- [调度器](kernel-small-basic-process-scheduler.md)
- [内存管理](kernel-small-basic-memory.md)
- [堆内存管理](kernel-small-basic-memory-heap.md)
- [物理内存管理](kernel-small-basic-memory-physical.md)
- [虚拟内存管理](kernel-small-basic-memory-virtual.md)
- [虚实映射](kernel-small-basic-inner-reflect.md)
- [内核通信机制](kernel-small-basic-trans.md)
- [事件](kernel-small-basic-trans-event.md)
- [信号量](kernel-small-basic-trans-semaphore.md)
- [互斥锁](kernel-small-basic-trans-mutex.md)
- [消息队列](kernel-small-basic-trans-queue.md)
- [读写锁](kernel-small-basic-trans-rwlock.md)
- [用户态快速互斥锁](kernel-small-basic-trans-user-mutex.md)
- [信号](kernel-small-basic-trans-user-signal.md)
- [时间管理](kernel-small-basic-time.md)
- [软件定时器](kernel-small-basic-softtimer.md)
- [原子操作](kernel-small-basic-atomic.md)
- [扩展组件](kernel-small-bundles.md)
- [系统调用](kernel-small-bundles-system.md)
- [动态加载与链接](kernel-small-bundles-linking.md)
- [虚拟动态共享库](kernel-small-bundles-share.md)
- [轻量级进程间通信](kernel-small-bundles-ipc.md)
- [文件系统](kernel-small-bundles-fs.md)
- [虚拟文件系统](kernel-small-bundles-fs-virtual.md)
- [支持的文件系统](kernel-small-bundles-fs-support.md)
- [FAT](kernel-small-bundles-fs-support-fat.md)
- [JFFS2](kernel-small-bundles-fs-support-jffs2.md)
- [NFS](kernel-small-bundles-fs-support-nfs.md)
- [Ramfs](kernel-small-bundles-fs-support-ramfs.md)
- [Procfs](kernel-small-bundles-fs-support-procfs.md)
- [适配新的文件系统](kernel-small-bundles-fs-new.md)
- [调测与工具](kernel-small-debug.md)
- [Shell](kernel-small-debug-shell.md)
- [Shell介绍](kernel-small-debug-shell-overview.md)
- [Shell命令开发指导](kernel-small-debug-shell-guide.md)
- [Shell命令编程实例](kernel-small-debug-shell-build.md)
- [Shell命令使用详解](kernel-small-debug-shell-details.md)
- [系统命令](kernel-small-debug-shell-cmd.md)
- [cpup](kernel-small-debug-shell-cmd-cpup.md)
- [date](kernel-small-debug-shell-cmd-date.md)
- [dmesg](kernel-small-debug-shell-cmd-dmesg.md)
- [exec](kernel-small-debug-shell-cmd-exec.md)
- [free](kernel-small-debug-shell-cmd-free.md)
- [help](kernel-small-debug-shell-cmd-help.md)
- [hwi](kernel-small-debug-shell-cmd-hwi.md)
- [kill](kernel-small-debug-shell-cmd-kill.md)
- [log](kernel-small-debug-shell-cmd-log.md)
- [memcheck](kernel-small-debug-shell-cmd-memcheck.md)
- [oom](kernel-small-debug-shell-cmd-oom.md)
- [pmm](kernel-small-debug-shell-cmd-pmm.md)
- [reset](kernel-small-debug-shell-cmd-reset.md)
- [sem](kernel-small-debug-shell-cmd-sem.md)
- [stack](kernel-small-debug-shell-cmd-stack.md)
- [su](kernel-small-debug-shell-cmd-su.md)
- [swtmr](kernel-small-debug-shell-cmd-swtmr.md)
- [systeminfo](kernel-small-debug-shell-cmd-sysinfo.md)
- [task](kernel-small-debug-shell-cmd-task.md)
- [uname](kernel-small-debug-shell-cmd-uname.md)
- [vmm](kernel-small-debug-shell-cmd-vmm.md)
- [watch](kernel-small-debug-shell-cmd-watch.md)
- [文件命令](kernel-small-debug-shell-file.md)
- [cat](kernel-small-debug-shell-file-cat.md)
- [cd](kernel-small-debug-shell-file-cd.md)
- [chgrp](kernel-small-debug-shell-file-chgrp.md)
- [chmod](kernel-small-debug-shell-file-chmod.md)
- [chown](kernel-small-debug-shell-file-chown.md)
- [cp](kernel-small-debug-shell-file-cp.md)
- [format](kernel-small-debug-shell-file-format.md)
- [ls](kernel-small-debug-shell-file-ls.md)
- [lsfd](kernel-small-debug-shell-file-lsfd.md)
- [mkdir](kernel-small-debug-shell-file-mkdir.md)
- [mount](kernel-small-debug-shell-file-mount.md)
- [partinfo](kernel-small-debug-shell-file-partinfo.md)
- [partition](kernel-small-debug-shell-file-partition.md)
- [pwd](kernel-small-debug-shell-file-pwd.md)
- [rm](kernel-small-debug-shell-file-rm.md)
- [rmdir](kernel-small-debug-shell-file-rmdir.md)
- [statfs](kernel-small-debug-shell-file-statfs.md)
- [sync](kernel-small-debug-shell-file-sync.md)
- [touch](kernel-small-debug-shell-file-touch.md)
- [writeproc](kernel-small-debug-shell-file-write.md)
- [umount](kernel-small-debug-shell-file-umount.md)
- [网络命令](kernel-small-debug-shell-net.md)
- [arp](kernel-small-debug-shell-net-arp.md)
- [dhclient](kernel-small-debug-shell-net-dhclient.md)
- [dns](kernel-small-debug-shell-net-dns.md)
- [ifconfig](kernel-small-debug-shell-net-ifconfig.md)
- [ipdebug](kernel-small-debug-shell-net-ipdebug.md)
- [netstat](kernel-small-debug-shell-net-netstat.md)
- [ntpdate](kernel-small-debug-shell-net-ntpdate.md)
- [ping](kernel-small-debug-shell-net-ping.md)
- [ping6](kernel-small-debug-shell-net-ping6.md)
- [telnet](kernel-small-debug-shell-net-telnet.md)
- [tftp](kernel-small-debug-shell-net-tftp.md)
- [魔法键使用方法](kernel-small-debug-shell-magickey.md)
- [用户态异常信息说明](kernel-small-debug-shell-error.md)
- [Trace](kernel-small-debug-trace.md)
- [进程调测](kernel-small-debug-process.md)
- [CPU占用率](kernel-small-debug-process-cpu.md)
- [内存调测](kernel-small-debug-memory.md)
- [内存信息统计](kernel-small-debug-memory-info.md)
- [内存泄漏检测](kernel-small-debug-memory-leak.md)
- [踩内存检测](kernel-small-debug-memory-corrupt.md)
- [其他内核调测手段](kernel-small-debug-other.md)
- [临终遗言](kernel-small-debug-trace-other-lastwords.md)
- [常见问题定位方法](kernel-small-debug-trace-other-faqs.md)
- [附录](kernel-small-apx.md)
- [基本数据结构](kernel-small-apx-structure.md)
- [双向链表](kernel-small-apx-dll.md)
- [位操作](kernel-small-apx-bitwise.md)
- [标准库](kernel-small-apx-library.md)
- [标准系统内核](kernel-standard.md)
- [Linux内核概述](kernel-standard-des.md)
- [OpenHarmony开发板Patch使用指导](kernel-standard-patch.md)
- [Linux内核编译与构建指导](kernel-standard-build.md)
- [Linux内核概述](kernel-standard-overview.md)
- [OpenHarmony开发板Patch使用指导](kernel-standard-patch.md)
- [Linux内核编译与构建指导](kernel-standard-build.md)
\ No newline at end of file
# 时间管理<a name="ZH-CN_TOPIC_0000001078876462"></a>
- **[基本概念](kernel-lite-mini-basic-time-basic.md)**
- **[基本概念](kernel-mini-basic-time-basic.md)**
- **[开发指导](kernel-lite-mini-basic-time-guide.md)**
- **[开发指导](kernel-mini-basic-time-guide.md)**
# 附录<a name="ZH-CN_TOPIC_0000001123948061"></a>
- **[内核编码规范](kernel-lite-mini-app-code.md)**
- **[基本数据结构](kernel-lite-mini-app-data.md)**
- **[标准库支持](kernel-lite-mini-app-lib.md)**
# 事件<a name="ZH-CN_TOPIC_0000001078716886"></a>
- **[基本概念](kernel-lite-mini-basic-ipc-event-guide.md)**
- **[开发指导](kernel-lite-mini-basic-ipc-event-basic.md)**
# 内核通信机制<a name="ZH-CN_TOPIC_0000001124573873"></a>
- **[事件](kernel-lite-mini-basic-ipc-event.md)**
- **[互斥锁](kernel-lite-mini-basic-ipc-mutex.md)**
- **[消息队列](kernel-lite-mini-basic-ipc-queue.md)**
- **[信号量](kernel-lite-mini-basic-ipc-sem.md)**
# 内存管理<a name="ZH-CN_TOPIC_0000001078876454"></a>
- **[基本概念](kernel-lite-mini-basic-memory-basic.md)**
- **[静态内存](kernel-lite-mini-basic-memory-static.md)**
- **[动态内存](kernel-lite-mini-basic-memory-dynamic.md)**
# 基础内核<a name="ZH-CN_TOPIC_0000001123863157"></a>
- **[中断管理](kernel-lite-mini-basic-interrupt.md)**
- **[任务管理](kernel-lite-mini-basic-task.md)**
- **[内存管理](kernel-lite-mini-basic-memory.md)**
- **[内核通信机制](kernel-lite-mini-basic-ipc.md)**
- **[时间管理](kernel-lite-basic-mini-time.md)**
- **[软件定时器](kernel-lite-mini-basic-soft.md)**
# 扩展组件<a name="ZH-CN_TOPIC_0000001123863139"></a>
- **[C++支持](kernel-lite-mini-extend-support.md)**
- **[CPU占用率](kernel-lite-mini-extend-cpup.md)**
- **[文件系统](kernel-lite-mini-extend-file.md)**
# 内核调测<a name="ZH-CN_TOPIC_0000001123763653"></a>
- **[内存调测](kernel-lite-mini-inner-debug.md)**
- **[异常调测](kernel-lite-mini-inner-exception.md)**
- **[Trace调测](kernel-lite-mini-inner-trace.md)**
# 快速入门<a name="ZH-CN_TOPIC_0000001124066549"></a>
- [搭建开发环境](#section157851447151716)
- [获取OpenHarmony源码](#section381985201816)
- [获取示例工程源码](#section204717216181)
- [编译运行](#section9772514181917)
OpenHarmony LiteOS-M内核的编译构建系统是一个基于gn和ninja的组件化构建系统,支持按组件配置、裁剪和拼装,按需构建出定制化的产品。编译构建系统的详细信息可以参考[考编译构建概](../subsystems/subsys-build-mini-lite.md#section10958256161119)。本文主要介绍如何基于gn和ninja编译LiteOS-M工程。
## 搭建开发环境<a name="section157851447151716"></a>
在搭建各个开发板环境前,需要完成OpenHarmony系统基础环境搭建。系统基础环境主要是指OpenHarmony的编译环境和开发环境,详细介绍请参考官方站点[搭建系统基础环境](../quick-start/quickstart-lite-env-setup-des.md)。开发者需要根据环境搭建文档,完成下述软件的安装:Python3.7+、gn、ninja、hb。对于LiteOS-M内核,还需要安装ARM GCC编译工具链。
## 获取OpenHarmony源码<a name="section381985201816"></a>
开发者需要在Linux服务器上通过Git克隆获取OpenHarmony最新源码,详细的源码获取方式,请见[源码获取](../get-code/sourcecode-acquire.md)。获取OpenHarmony完整仓代码后,假设克隆目录为\~/openHarmony。
## 获取示例工程源码<a name="section204717216181"></a>
以开发板Nucleo-F767Zi为例,演示如何编译运行OpenHarmony LiteOS-M内核工程。在本地目录,执行下述命令克隆示例代码。
```
git clone https://gitee.com/harylee/nucleo_f767zi.git
```
假设克隆到的代码目录为\~/nucleo\_f767zi。 执行如下命令把代码目录的device、vendor目录复制到openHarmony工程的相应目录。
```
cp -r ~/nucleo_f767zi/device/st ~/openHarmony/device/st
cp -r ~/nucleo_f767zi/vendor/st ~/openHarmony/vendor/st
```
关于示例代码目录的说明,可以参考资料站点[板级目录规范](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/porting/%E7%A7%BB%E6%A4%8D%E6%A6%82%E8%BF%B0-0.md#section6204129143013)。如果需要自行移植开发板,请参考[板级系统移植](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/porting/%E6%9D%BF%E7%BA%A7%E7%B3%BB%E7%BB%9F%E7%A7%BB%E6%A4%8D.md)
## 编译运行<a name="section9772514181917"></a>
编译运行前,把交叉编译工具链bin目录配置到PATH环境变量中或者在device/st/nucleo\_f767zi/liteos\_m/config.gni文件中把board\_toolchain\_path配置项设置为交叉编译工具链bin目录。 在OpenHarmony根目录,执行hb set设置产品路径,选择nucleo\_f767zi产品,然后执行hb build开启编译。如下:
```
user@dev:~/OpenHarmony$ hb set
[OHOS INFO] Input code path: # 直接按回车,然后选择nucleo_f767zi产品即可
OHOS Which product do you need? nucleo_f767zi@st
user@dev:~/OpenHarmony$ hb build
```
最终的镜像生成在\~/openHarmony/out/nucleo\_f767zi/目录中,通过STM32 ST-LINK Utility软件将镜像文件下载至单板查看运行效果。
# 轻量系统内核<a name="ZH-CN_TOPIC_0000001124663064"></a>
- **[内核概述](kernel-lite-mini-m.md)**
- **[基础内核](kernel-lite-mini-basic.md)**
- **[扩展组件](kernel-lite-mini-extend.md)**
- **[内核调测](kernel-lite-mini-inner.md)**
- **[附录](kernel-lite-mini-app.md)**
# 基础内核<a name="ZH-CN_TOPIC_0000001111199438"></a>
- **[进程](kernel-lite-small-process.md)**
- **[线程](kernel-lite-small-thread.md)**
- **[内存](kernel-lite-small-memory.md)**
- **[网络](kernel-lite-small-net.md)**
# FAT<a name="ZH-CN_TOPIC_0000001052170495"></a>
- [概述](#section17906101815113)
- [注意事项](#section781233610116)
- [开发指导](#section26081559713)
## 概述<a name="section17906101815113"></a>
FAT文件系统是File Allocation Table(文件配置表)的简称,FAT文件系统有FAT12、FAT16、FAT32。FAT文件系统将硬盘分为MBR区、DBR区、FAT区、DIR区、DATA区等5个区域。
FAT文件系统支持多种介质,特别在可移动存储介质(U盘、SD卡、移动硬盘等)上广泛使用。可以使嵌入式设备和Windows、Linux等桌面系统保持很好的兼容性,方便用户管理操作文件。
OpenHarmony内核的FAT文件系统具有代码量和资源占用小、可裁切、支持多种物理介质等特性,并且与Windows、Linux等系统保持兼容,支持多设备、多分区识别等功能。
OpenHarmony内核支持硬盘多分区,可以在主分区以及逻辑分区上创建FAT文件系统。同时OpenHarmony内核也可以识别出硬盘上其他类型的文件系统。
## 注意事项<a name="section781233610116"></a>
- 最多支持同时打开的fatfs文件(文件夹)数为512。
- 以可写方式打开一个文件后,未close前再次打开会失败。多次打开同一文件,必须全部使用只读方式。长时间打开一个文件,没有close时数据会丢失,必须close才能保存。
- FAT文件系统中,单个文件不能大于4G。
- 当有两个SD卡插槽时,卡0和卡1不固定,先插上的为卡0,后插上的为卡1。
- 当多分区功能打开,存在多分区的情况下,卡0注册的设备节点/dev/mmcblk0\(主设备\)和/dev/mmcblk0p0\(次设备\)是同一个设备,禁止对主设备进行操作。
- FAT文件系统的读写指针没有分离,所以以O\_APPEND(追加写)方式打开文件后,读指针也在文件尾,读文件前需要用户手动置位。
- FAT文件系统的stat及lstat函数获取出来的文件时间只是文件的修改时间。暂不支持创建时间和最后访问时间。微软FAT协议不支持1980年以前的时间。
- open打开一个文件,参数有O\_TRUNC时,会将文件中的内容清空。
- FAT文件系统支持的操作有:open, close, read, write, seek, sync, opendir, closedir, readdir, rewinddir, readdir\_r, statfs, remove, unlink, mkdir, rmdir, rename, stat, stat64, seek64, fallocate, fallocate64, truncate, truncate64,mount, umount。
- 为避免SD卡使用异常和内存泄漏,SD卡使用过程中拔卡,用户必须先关闭正处于打开状态的文件和目录,之后umount挂载节点。
- 在format操作之前,若fat文件系统已挂载,需确保所有目录及文件全部关闭,否则format会失败。
- FAT支持只读属性挂载:
- 当mount函数的入参为MS\_RDONLY时,FAT将开启只读属性,所有的带有写入的接口,如write、mkdir、unlink,以及通过非O\_RDONLY属性打开的文件,将均被拒绝,并传出EACCESS错误码(format接口除外)。
- 当mount函数的入参为MS\_NOSYNC时,FAT不会主动将cache的内容写回存储器件。FAT的如下接口(open、close、 unlink、rename、mkdir、rmdir、truncate)不会自动进行sync操作,速度可以提升,但是需要上层主动调用sync来进行数据同步,否则下电可能会数据丢失。
- FAT文件系统有定时刷cache功能。在menuconfig中开启LOSCFG\_FS\_FAT\_CACHE\_SYNC\_THREAD选项,打开后系统会创建一个任务刷cache,默认每隔5秒检查cache中脏数据块比例,超过80%时进行sync操作,将cache中的脏数据全部写回磁盘。任务优先级、刷新时间间隔以及脏数据块比例的阈值可分别通过接口LOS\_SetSyncThreadPrio、 LOS\_SetSyncThreadInterval和LOS\_SetDirtyRatioThreshold设置。
- 当前cache的默认大小为16个块,每个块256个扇区。
## 开发指导<a name="section26081559713"></a>
**设备识别**
- 在ffconf.h文件中配置FF\_MULTI\_PARTITION为1,可使用多分区功能。
- 在ffconf.h文件中配置FF\_VOLUMES大于2时,可使用多设备功能。
多设备、多分区功能开启后,系统对于插上的sd卡自动识别,自动注册设备节点如上图所示。mmcblk0和mmcblk1为卡0和卡1,是独立的主设备,mmcblk0p0、mmcblk0p1为卡0的两个分区,可作为分区设备使用。在有分区设备存在的情况下,禁止使用主设备。
可以使用 partinfo命令查看所识别的分区信息。
```
OHOS # partinfo /dev/mmcblk0p0
part info :
disk id : 0
part_id in system: 0
part no in disk : 0
part no in mbr : 1
part filesystem : 0C
part dev name : mmcblk0p0
part sec start : 8192
part sec count : 31108096
```
**FAT文件系统的挂载**
运行命令:
```
OHOS # mount /dev/mmcblk0p0 /vs/sd vfat
```
将从串口得到如下回应信息,表明挂载成功。
```
OHOS # mount /dev/mmcblk0p0 /vs/sd vfat
mount ok
```
**FAT文件系统的卸载**
运行命令:
```
OHOS # umount /vs/sd
```
将从串口得到如下回应信息,表明卸载成功。
```
OHOS # umount /vs/sd
umount ok
```
# NFS<a name="ZH-CN_TOPIC_0000001052170493"></a>
- [概述](#section18322139164413)
- [注意事项](#section532912331467)
- [开发指导](#section166873374711)
## 概述<a name="section18322139164413"></a>
NFS是Network File System(网络文件系统)的缩写。它最大的功能是可以通过网络,让不同的机器、不同的操作系统彼此分享其他用户的文件。因此,用户可以简单地将它看做是一个文件系统服务,在一定程度上相当于Windows环境下的共享文件夹。
NFS客户端用户,能够将网络远程的NFS服务端分享的目录挂载到本地端的机器中,运行程序和共享文件,但不占用当前的系统资源,所以,在本地端的机器看起来,远程服务端的目录就好像是自己的一个磁盘一样。
## 注意事项<a name="section532912331467"></a>
- 当前NFS文件不支持权限控制,请在创建NFS目录和文件时使用777权限。
- 当前NFS文件不支读阻塞和写阻塞。
- 当前NFS文件不支持信号功能。
- 当前NFS文件系统mount路径长度(不包含IP的长度)不超过255个字符,超过时返回ENAMETOOLONG错误。
- 当前NFS文件支持的操作有:open, close, read, write, seek, dup, dup2, sync, opendir, closedir, readdir, readdir\_r, rewinddir, scandir, statfs, remove, unlink, mkdir, rmdir, rename, stat, stat64, seek64, mmap, mount, umount。
- 当前NFS支持TCP和UDP两种传输层协议,默认使用TCP。
- open打开一个文件,参数有O\_TRUNC时,必须同时拥有写的权限,才会将文件中的内容清空。
- 在文件未关闭的情况下,rename\(\)函数重命名A为B之后,不会改变文件fd。
- NFS功能目前处于beta测试阶段,可能存在功能不稳定的情况,建议您不要用于正式商用产品当中。
## 开发指导<a name="section166873374711"></a>
1. **搭建NFS服务器**
这里以Ubuntu操作系统为例,说明服务器端设置步骤。
1. 安装NFS服务器软件。
设置好Ubuntu系统的下载源,保证网络连接好的情况下执行:
```
sudo apt-get install nfs-kernel-server
```
2. 创建用于挂载的目录并设置完全权限
```
mkdir /home/sqbin/nfs
sudo chmod 777 /home/sqbin/nfs
```
3. 设置和启动NFS server。
修改NFS配置文件/etc/exports,添加如下一行:
```
/home/sqbin/nfs *(rw,no_root_squash,async)
```
其中/home/sqbin/nfs是NFS共享的根目录。
执行以下命令启动NFS server:
```
sudo /etc/init.d/nfs-kernel-server start
```
执行以下命令重启NFS server:
```
sudo /etc/init.d/nfs-kernel-server restart
```
2. **设置单板为NFS客户端**
本指导中的NFS客户端指运行OpenHarmony内核的设备。
1. 硬件连接设置。
OpenHarmony内核设备连接到NFS服务器的网络。设置两者IP,使其处于同一网段。比如,设置NFS服务器的IP为10.67.212.178/24,设置OpenHarmony内核设备IP为10.67.212.3/24,注意:此IP为内网私有IP地址,用户使用时有差异,以用户实际IP为准。
OpenHarmony内核设备上的IP信息可通过ifconfig命令查看。
2. 启动网络,确保单板到NFS服务器之间的网络通畅。
启动以太网或者其他类型网络,使用ping命令检查到服务器的网络是否通畅。
```
OHOS # ping 10.67.212.178
[0]Reply from 10.67.212.178: time=1ms TTL=63
[1]Reply from 10.67.212.178: time=0ms TTL=63
[2]Reply from 10.67.212.178: time=1ms TTL=63
[3]Reply from 10.67.212.178: time=1ms TTL=63
--- 10.67.212.178 ping statistics ---
4 packets transmitted, 4 received, 0 loss
```
客户端NFS初始化,运行命令:
```
OHOS # mkdir /nfs
OHOS # mount 10.67.212.178:/home/sqbin/nfs /nfs nfs 1011 1000
```
将从串口得到如下回应信息,表明初始化NFS客户端成功。
```
OHOS # mount 10.67.212.178:/home/sqbin/nfs /nfs nfs 1011 1000
Mount nfs on 10.67.212.178:/home/sqbin/nfs, uid:1011, gid:1000
Mount nfs finished.
```
该命令将服务器10.67.212.178上的/home/sqbin/nfs目录mount在OpenHarmony内核设备上的/nfs上。
>![](../public_sys-resources/icon-note.gif) **说明:**
>本例默认nfs server已经配置可用,即示例中服务器10.67.212.178上的/home/sqbin/nfs已配置可访问。
mount命令的格式为:
```
mount <SERVER_IP:SERVER_PATH> <CLIENT_PATH> nfs
```
其中“SERVER\_IP“表示服务器的IP地址;“SERVER\_PATH“表示服务器端NFS共享目录路径;“CLIENT\_PATH“表示设备上的NFS路径。
如果不想有NFS访问权限限制,请在Linux命令行将NFS根目录权限设置成777:
```
chmod -R 777 /home/sqbin/nfs
```
至此,NFS客户端设置完毕。NFS文件系统已成功挂载。
3. **利用NFS共享文件**
在NFS服务器下新建目录dir,并保存。在OpenHarmony内核下运行ls命令:
```
OHOS # ls /nfs
```
则可从串口得到如下回应:
```
OHOS # ls /nfs
Directory /nfs:
drwxr-xr-x 0 u:0 g:0 dir
```
可见,刚刚在NFS服务器上新建的dir目录已同步到客户端\(OpenHarmony内核系统\)的/nfs目录,两者保持同步。
同样地,在客户端\(OpenHarmony内核系统\)上创建文件和目录,在NFS服务器上也可以访问,读者可自行体验。
**平台差异性:**
目前,NFS客户端仅支持NFS v3部分规范要求,因此对于规范支持不全的服务器,无法完全兼容。在开发测试过程中,建议使用Linux的NFS server,因为其对NFS支持很完善。
# RAMFS<a name="ZH-CN_TOPIC_0000001052810480"></a>
- [概述](#section7216205735619)
- [注意事项](#section970375615711)
- [开发指导](#section18433111125812)
## 概述<a name="section7216205735619"></a>
RAMFS是一个可动态调整大小的基于RAM的文件系统。RAMFS没有后备存储源。向RAMFS中进行的文件写操作也会分配目录项和页缓存,但是数据并不写回到任何其他存储介质上,掉电后数据丢失。
RAMFS文件系统把所有的文件都放在 RAM 中,所以读/写操作发生在RAM中,可以用RAMFS来存储一些临时性或经常要修改的数据,例如/tmp和/var目录,这样既避免了对存储器的读写损耗,也提高了数据读写速度。
OpenHarmony内核的RAMFS是一个简单的文件系统,它是基于RAM的动态文件系统的一种缓冲机制。
OpenHarmony内核的RAMFS基于虚拟文件系统层(VFS\),不能格式化。
## 注意事项<a name="section970375615711"></a>
- RAMFS文件系统的读写指针没有分离,所以以O\_APPEND(追加写)方式打开文件后,读指针也在文件尾,读文件前需要用户手动置位。
- RAMFS只能挂载一次,一次挂载成功后,后面不能继续挂载到其他目录。
- RAMFS文件数量受信号量资源限制,不能超过LOSCFG\_BASE\_IPC\_SEM\_LIMIT。
- open打开一个文件,参数有O\_TRUNC时,会将文件中的内容清空。
- RAMFS文件系统支持的操作有:open, close, read, write, seek, opendir, closedir, readdir, readdir\_r, rewinddir, sync, statfs, remove, unlink, mkdir, rmdir, rename, stat, stat64, seek64, mmap, mount, umount。
- RAMFS属于调测功能,默认配置为关闭,正式产品中禁止使用该功能。
## 开发指导<a name="section18433111125812"></a>
RAMFS的挂载和卸载可以在如下两种方式中任选其一:
- 使用代码挂载和卸载完成RAMFS文件系统的初始化和去初始化。
1. 调用mount函数完成RAMFS文件系统的初始化。
```
void ram_fs_init(void) {
int swRet;
swRet = mount(NULL, RAMFS_DIR, "ramfs", 0, NULL);
if (swRet != 0) {
dprintf("mount ramfs err %d\n", swRet);
return;
}
dprintf("Mount ramfs finished.\n");
}
```
调用初始化函数,随后在OpenHarmony内核系统启动时可以看到如下显示,表示RAMFS文件系统已初始化成功:
```
Mount ramfs finished
```
2. 卸载。调用去初始化函数,随后在OpenHarmony内核系统可以看到如下显示,表示RAMFS文件系统已卸载:
```
void ram_fs_uninit(void) {
int swRet;
swRet = umount(RAMFS_DIR);
if (swRet != 0) {
dprintf("Umount ramfs err %d\n", swRet);
return;
}
dprintf("Umount ramfs finished.\n");
}
```
- 使用命令行的方式完成RAMFS文件系统的挂载和卸载 。
1. 使用mount命令完成RAMFS文件系统的挂载,将从串口得到如下回应信息,表明挂载成功。
```
OHOS # mount 0 /ramfs ramfs
mount ok
```
2. 使用umount命令完成卸载,将从串口得到如下回应信息,表明卸载成功。
```
OHOS # umount /ramfs
umount ok
```
# VFS<a name="ZH-CN_TOPIC_0000001051451779"></a>
- [概述](#section132540468341)
- [基本概念](#section229417111227)
- [运作机制](#section18114182834215)
- [注意事项](#section18311145173712)
- [开发指导](#section422619258380)
- [编程实例](#section180311121420)
- [结果验证](#section16772334714)
## 概述<a name="section132540468341"></a>
## 基本概念<a name="section229417111227"></a>
VFS是Virtual File System(虚拟文件系统)的缩写,它不是一个实际的文件系统,而是一个异构文件系统之上的软件粘合层,为用户提供统一的类Unix文件操作接口。
由于不同类型的文件系统接口不统一,若系统中有多个文件系统类型,访问不同的文件系统就需要使用不同的非标准接口。而通过在系统中添加VFS层,提供统一的抽象接口,屏蔽了底层异构类型的文件系统的差异,使得访问文件系统的系统调用不用关心底层的存储介质和文件系统类型,提高开发效率。VFS和各个具体文件系统的关系如下:
**图 1** VFS和各个文件系统的关系<a name="fig633144419295"></a>
![](figure/VFS和各个文件系统的关系.png "VFS和各个文件系统的关系")
OpenHarmony内核中,VFS框架是通过在内存中的树结构来实现的,树的每个结点都是一个inode结构体。设备注册和文件系统挂载后会根据路径在树中生成相应的结点。VFS最主要是两个功能:
- 查找节点。
- 统一调用(标准)。
## 运作机制<a name="section18114182834215"></a>
通过VFS层,可以使用标准的Unix文件操作函数(如open、read、write等)来实现对不同介质上不同文件系统的访问。
VFS框架内存中的inode树结点有三种类型:
- 虚拟结点:作为VFS框架的虚拟文件,保持树的连续性,如/usr、/usr/bin。
- 设备结点:/dev目录下,对应一个设备,如/dev/mmcblk0。
- 挂载点:挂载具体文件系统,如/vs/sd、/mnt。
**图 2** 文件系统树形结构<a name="fig1648112392612"></a>
![](figure/文件系统树形结构.png "文件系统树形结构")
## 注意事项<a name="section18311145173712"></a>
- VFS下的所有文件系统,创建的目录名和文件名最多只可以有255个字节,能支持的全路径长度最长为259字节,超过这个路径长度的文件和目录无法创建。
- 目前仅有jffs2文件系统支持完整的权限控制。
- inode\_find\(\)函数调用后会使查找到的inode节点连接数+1,调用完成后需要调用inode\_release\(\)使连接数-1,所以一般inode\_find\(\)要和inode\_release\(\)配套使用。
- 设备分为字符设备和块设备,为了块设备上的文件系统系统数据安全,需挂载相应文件系统后通过文件系统接口操作数据。
- los\_vfs\_init\(\)只能调用一次,多次调用将会造成文件系统异常。
- 目前OpenHarmony内核所有的文件系统中的文件名和目录名中只可以出现“-” 与“\_”两种特殊字符,使用其他特殊字符可能造成的后果不可预知,请谨慎为之。
- OpenHarmony内核支持open\(\)+O\_DIRECTORY的方法获取目录数据信息。
- 挂载点必须为空目录,不能重复挂载至同一挂载点或挂载至其他挂载点下的目录或文件,错误挂载可能损坏设备及系统。
- open打开一个文件时,参数O\_RDWR、O\_WRONLY、O\_RDONLY互斥,只能出现一个,若出现2个或以上作为open的参数,文件读写操作会被拒绝,并返回EACCESS错误码,禁止使用。
- OpenHarmony内核文件系统在umount操作之前,需确保所有目录及文件全部关闭,否则umount会失败。如果强制umount,可能导致包括但不限于文件系统损坏、设备损坏等问题。
- SD卡移除前,需确保所有目录及文件全部关闭,并进行umount操作。如果强制拔卡,可能导致包括但不限于SD数据丢失、SD卡损坏等问题。
## 开发指导<a name="section422619258380"></a>
**开发流程**
推荐驱动开发人员使用VFS框架来注册/卸载设备,即调用register\_driver\(\)、register\_blockdriver\(\)接口生成设备结点,应用层使用open\(\)、read\(\)操作设备(字符设备)文件来调用驱动。
**文件描述符**
本系统中,进程的文件描述符最多有256个(File和Socket描述符合并统计),系统文件描述符共640个,系统文件描述符规格:
- File描述符,普通文件描述符,系统总规格为512。
- Socket描述符,系统总规格为128。
**VFS支持的操作**
open, close, read, write, seek, ioctl, fcntl, mmap, sync, dup, dup2, truncate, opendir, closedir, readdir, rewinddir, mount, umount, statfs, unlink, remove, mkdir, rmdir, rename, stat, utime, seek64, fallocate, fallocate64, truncate64, chmod, chown。
>![](../public_sys-resources/icon-note.gif) **说明:**
>- 当前只提供修改jffs2文件以及vfs设备节点属性的接口,各个系统对只读等属性有各自的处理方式。
>- 在OpenHarmony内核中属性并不冲突(可以任意修改)。
>- 在OpenHarmony内核中只读属性文件/目录不允许被删除。
>- 在OpenHarmony内核中只读属性文件/目录允许rename。
>- 只读文件不允许以O\_CREAT、O\_TRUNC,以及有含有写的权限的方式打开。
>- 在OpenHarmony内核中设置的系统文件加上隐藏属性,在Windows中只能通过命令行找到(在显示,不显示隐藏文件的属性情况下都不能看到)。
## 编程实例<a name="section180311121420"></a>
```
/* 说明:展示创建目录,和遍历目录的操作 */
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
int main()
{
int ret;
char *dirname = "/test";
char *pathname0 = "/test/test0";
char *pathname1 = "/test/test1";
char *pathname2 = "/test/test2";
struct dirent **namelist;
int num;
ret = mkdir(dirname, 0777);
if ((ret < 0) && (errno != EEXIST)) {
printf("mkdir failed. path=%s, errno=%d\n", dirname, errno);
goto EXIT;
}
ret = mkdir(pathname0, 0777);
if ((ret < 0) && (errno != EEXIST)) {
printf("mkdir failed. path=%s, errno=%d\n", pathname0, errno);
goto EXIT0;
}
ret = mkdir(pathname1, 0777);
if ((ret < 0) && (errno != EEXIST)) {
printf("mkdir failed. path=%s, errno=%d\n", pathname1, errno);
goto EXIT1;
}
ret = mkdir(pathname2, 0777);
if ((ret < 0) && (errno != EEXIST)) {
printf("mkdir failed. path=%s, errno=%d\n", pathname2, errno);
goto EXIT2;
}
num = scandir(dirname, &namelist, NULL, alphasort);
if (num < 0) {
perror("scandir");
} else {
while (num--) {
printf("%s\n", namelist[num]->d_name);
free(namelist[num]);
}
free(namelist);
}
printf("fs_demo exit.\n");
return 0;
EXIT2:
remove(pathname2);
EXIT1:
remove(pathname1);
EXIT0:
remove(pathname0);
EXIT:
remove(dirname);
return 0;
}
```
## 结果验证<a name="section16772334714"></a>
```
OHOS # test2
test1
test0
fs_demo exit.
```
# 文件系统<a name="ZH-CN_TOPIC_0000001051611726"></a>
OpenHarmony轻内核支持的文件系统有:VFS(虚拟文件系统)、NFS、RAMFS、FAT、JFFS2。
**各个文件系统功能概述:**
**表 1** 文件系统功能概述
<a name="table6330194819415"></a>
<table><thead align="left"><tr id="row6331184864111"><th class="cellrowborder" valign="top" width="11.559999999999999%" id="mcps1.2.3.1.1"><p id="p17644161411438"><a name="p17644161411438"></a><a name="p17644161411438"></a>文件系统</p>
</th>
<th class="cellrowborder" valign="top" width="88.44%" id="mcps1.2.3.1.2"><p id="p116441414184312"><a name="p116441414184312"></a><a name="p116441414184312"></a>功能特点概述</p>
</th>
</tr>
</thead>
<tbody><tr id="row371213562318"><td class="cellrowborder" valign="top" width="11.559999999999999%" headers="mcps1.2.3.1.1 "><p id="p37130569316"><a name="p37130569316"></a><a name="p37130569316"></a>VFS</p>
</td>
<td class="cellrowborder" valign="top" width="88.44%" headers="mcps1.2.3.1.2 "><p id="p1771335615316"><a name="p1771335615316"></a><a name="p1771335615316"></a>VFS是Virtual File System(虚拟文件系统)的缩写,它不是一个实际的文件系统,而是一个异构文件系统之上的软件粘合层,为用户提供统一的类Unix文件操作接口。</p>
</td>
</tr>
<tr id="row189255844219"><td class="cellrowborder" valign="top" width="11.559999999999999%" headers="mcps1.2.3.1.1 "><p id="p1564481494319"><a name="p1564481494319"></a><a name="p1564481494319"></a>NFS</p>
</td>
<td class="cellrowborder" valign="top" width="88.44%" headers="mcps1.2.3.1.2 "><p id="p764561414434"><a name="p764561414434"></a><a name="p764561414434"></a>NFS是Network File System(网络文件系统)的缩写。它最大的功能是可以通过网络,让不同的机器、不同的操作系统彼此分享其他用户的文件。</p>
</td>
</tr>
<tr id="row17332194820411"><td class="cellrowborder" valign="top" width="11.559999999999999%" headers="mcps1.2.3.1.1 "><p id="p2064561415435"><a name="p2064561415435"></a><a name="p2064561415435"></a>RAMFS</p>
</td>
<td class="cellrowborder" valign="top" width="88.44%" headers="mcps1.2.3.1.2 "><p id="p12646614204320"><a name="p12646614204320"></a><a name="p12646614204320"></a>RAMFS是一种基于RAM的文件系统。RAMFS文件系统把所有的文件都放在RAM中,所以读/写操作发生在RAM中,避免了对存储器的读写损耗,也提高了数据读写速度。RAMFS是基于RAM的动态文件系统的一种存储缓冲机制。</p>
</td>
</tr>
<tr id="row16332174894116"><td class="cellrowborder" valign="top" width="11.559999999999999%" headers="mcps1.2.3.1.1 "><p id="p1864571410433"><a name="p1864571410433"></a><a name="p1864571410433"></a>FAT</p>
</td>
<td class="cellrowborder" valign="top" width="88.44%" headers="mcps1.2.3.1.2 "><p id="p364511141434"><a name="p364511141434"></a><a name="p364511141434"></a>FAT文件系统是File Allocation Table(文件配置表)的简称,有FAT12、FAT16、FAT32。在可移动存储介质(U盘、SD卡、移动硬盘等)上多使用FAT文件系统,使设备与Windows、Linux等桌面系统之间保持很好的兼容性。</p>
</td>
</tr>
<tr id="row1880218157414"><td class="cellrowborder" valign="top" width="11.559999999999999%" headers="mcps1.2.3.1.1 "><p id="p19645814144312"><a name="p19645814144312"></a><a name="p19645814144312"></a>JFFS2</p>
</td>
<td class="cellrowborder" valign="top" width="88.44%" headers="mcps1.2.3.1.2 "><p id="p8645161454314"><a name="p8645161454314"></a><a name="p8645161454314"></a>JFFS2是Journalling Flash File System Version 2(日志文件系统)的缩写,是MTD设备上的日志型文件系统。主要应用于对NOR_FLASH闪存的文件管理。<span id="text236315521580"><a name="text236315521580"></a><a name="text236315521580"></a>OpenHarmony</span>内核的JFFS2支持多分区。</p>
</td>
</tr>
</tbody>
</table>
- **[VFS](kernel-lite-small-file-vfs.md)**
- **[NFS](kernel-lite-small-file-nfs.md)**
- **[RAMFS](kernel-lite-small-file-ramfs.md)**
- **[FAT](kernel-lite-small-file-fat.md)**
- **[JFFS2](kernel-lite-small-file-jffs.md)**
# 与Linux标准库的差异<a name="ZH-CN_TOPIC_0000001053240737"></a>
- [进程](#section249218475301)
- [内存](#section55731513163117)
- [与Linux mmap的差异](#section1943551142314)
- [代码举例](#section16947155092514)
- [文件系统](#section1746965493115)
- [信号](#section1198254310333)
- [Time](#section0833419133414)
本章节描述了OpenHarmony内核承载的标准库与Linux标准库之间存在的关键差异。更多差异详见C库API文档说明。
## 进程<a name="section249218475301"></a>
1. OpenHarmony用户态**进程**优先级只支持静态优先级且用户态可配置的优先级范围为10\(最高优先级\)-31\(最低优先级)。
2. OpenHarmony用户态**线程**优先级只支持静态优先级且用户态可配置的优先级范围为0\(最高优先级\)-31\(最低优先级)。
3. OpenHarmony进程调度策略只支持SCHED\_RR, 线程调度策略支持SCHED\_RR和SCHED\_FIFO。
## 内存<a name="section55731513163117"></a>
## 与Linux mmap的差异<a name="section1943551142314"></a>
mmap接口原型为:void \*mmap \(void \*addr, size\_t length, int prot, int flags, int fd, off\_t offset\)
其中,参数fd的生命周期实现与Linux glibc存在差异。具体体现在,glibc在成功调用mmap进行映射后,可以立即释放fd句柄。在OpenHarmony内核中,不允许用户在映射成功后立即关闭相关fd,只允许在取消映射munmap后再进行fd的close操作。如果用户不进行fd的close操作,操作系统将在进程退出时对该fd进行回收。
## 代码举例<a name="section16947155092514"></a>
Linux目前支持的情况如下:
```
int main(int argc, char *argv[])
{
int fd;
void *addr = NULL;
...
fd = open(argv[1], O_RDONLY);
if (fd == -1){
perror("open");
exit(EXIT_FAILURE);
}
addr = mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, offset);
if (addr == MAP_FAILED) {
perror("mmap");
exit(EXIT_FAILURE);
}
close(fd); /* OpenHarmony does not support closing fd immediately after the mapping is successful. */
...
exit(EXIT_SUCCESS);
}
```
OpenHarmony支持的情况如下:
```
int main(int argc, char *argv[])
{
int fd;
void *addr = NULL;
...
fd = open(argv[1], O_RDONLY);
if (fd == -1) {
perror("open");
exit(EXIT_FAILURE);
}
addr = mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, offset);
if (addr == MAP_FAILED) {
perror("mmap");
exit(EXIT_FAILURE);
}
...
munmap(addr, length);
close(fd); /* Close fd after the munmap is canceled. */
exit(EXIT_SUCCESS);
}
```
## 文件系统<a name="section1746965493115"></a>
**系统目录**:用户无权限修改系统目录和设备挂载目录。包含/dev,/proc,/app,/bin,/data,/etc,/lib,/system,/usr目录。
**用户目录**:用户可以在该目录下进行文件创建、读写,但**不能进行设备挂载**。用户目录指/storage目录。
**系统目录****用户目录**之外,用户可以自行创建文件夹进行设备的挂载。但是要注意,已挂载的文件夹及其子文件夹不允许重复或者嵌套挂载,非空文件夹不允许挂载。
## 信号<a name="section1198254310333"></a>
- 信号默认行为不支持STOP、CONTINUE、COREDUMP功能。
- 无法通过信号唤醒正在睡眠状态(举例:进程调用sleep函数进入睡眠)的进程。原因:信号机制无唤醒功能,当且仅当进程被CPU调度运行时才能处理信号内容。
- 进程退出后会发送SIGCHLD给父进程,发送动作无法取消。
- 信号仅支持1-30号信号,接收方收到多次同一信号,仅执行一次回调函数。
## Time<a name="section0833419133414"></a>
OpenHarmony当前时间精度以tick计算,系统默认10ms/tick。sleep、timeout系列函数时间误差<=20ms。
# 标准库<a name="ZH-CN_TOPIC_0000001111039548"></a>
- **[标准库](kernel-lite-small-lib-standard.md)**
- **[与Linux标准库的差异](kernel-lite-small-lib-differ.md)**
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册