当前位置: 首页 > news >正文

OpenHarmony构建系统-GN与子系统、部件、模块理论与实践

理论

OpenHarmony源码体系

        OpenHarmony的源码架构基于模块化设计,为了方便系统的功能的增加和裁剪,设计了基于GN构建的模块系统。整个模块可从大到小划分为产品(product)、领域/子系统集(domain)、子系统(sub system)、部件(component)、模块/组件(module)、特性(feature)几个部分,这种模块化的树状编译框架,非常方便根据目标产品硬件资源的大小进行灵活的裁剪,从而实现统一OS,弹性部署的目标。

OpenHarmony系统架构

一个产品可以包含1~n个子系统(subsystem),一个子系统可以包含1~n个部件(component),一个部件可以包含1~n个模块(module),不同产品的中的相同部件可以编译不同的特性(feature),子系统集(domain)在源代码一级根目录有体现。

由于以上的特性,OpenHarmony只需要通过gn的配置实现无需删减代码达到裁剪系统的目的,提高系统整体稳定性。

产品(product)

产品解决方案为基于开发板的完整产品,主要包含产品对OS的适配、部件拼装配置、启动配置和文件系统配置等。源码路径为:/vender/{产品解决方案厂商}/{产品名称},使用命令tree -L 级数,如果tree -L 4

vender└──── company                          # 产品解决方案厂商,如:hihope├──── product                   # 产品名称,如:rk3568│      ├──── init_configs│      │      ├──── etc         # init启动进程配置(可选,仅linux内核需要)│      │      └──── init.cfg    # 系统服务启动配置│      ├──── hals               # 产品解决方案OS适配│      ├──── BUILD.gn           # 产品编译脚本│      ├──── config.json        # 产品配置文件│      └──── fs.yml             # 文件系统打包配置├──── ...

/vender/{产品解决方案厂商}/{产品名称}/init+configs/etc文件夹中包含rcS脚本、Sxxx脚本和fstab脚本。init进程在启动系统服务前执行这些脚本,执行流程为rcS—>fstab—>Sxxx,Sxxx脚本中的内容与开发板和产品需求有关,主要包含

产品配置规则:/vender/{产品解决方案厂商}/{产品名称}/config.json文件中可以配置产品所需系统的子系统,其中的inherit字段可以继承事先定义好的样板模板,模板位于productdefine/common目录下

领域/子系统集(domain)

OpenHarmony技术架构中有四大子系统集:“系统基本能力子系统集”、“基础软件服务子系统集”、“增强软件服务子系统集”、“硬件服务子系统集”。四大子系统不会直接出现在编译选项或者参数中,而是有对应的一级源代码文件夹:

“系统基本能力子系统集”对应源码foundation文件夹;“基础软件服务子系统集”和“硬件服务子系统集”对应源码base文件夹;“增强软件服务子系统集”对应源码domains文件夹。

├──applications                              # 应用程序
├──arkcompiler                               # ark编译器
├──base                                      # “基础软件服务子系统集”和“硬件服务子系统集”
├──build                                     # 编译目录
├──build.py -> build/lite/build.py           # 软链接
├──build.sh -> build/build_scripts/build.sh  # 软链接,标准系统编译入口
├──commonlibrary                             # 通用库
├──developtools                              # 开发工具
├──device                                    # 芯片相关
├──docs                                      # 文档md文件目录
├──domains                                   # 增强软件服务子系统集
├──drivers                                   # 驱动文件
├──foundation                                # “系统基本能力子系统集”
├──ide                                       # ide
├──interface                                 # 接口
├──kernel                                    # 内核,liteos-m,liteos-a,linux,uniproton
├──napi_generator                            # 代码生成工具
├──prebuilts                                 # 编译工具路径
├──productdefine                             # 产品定义
├──qemu-run -> vendor/ohemu/common/qemu-run  # qemu模拟器运行脚本
├──test                                      # 测试用例
├──third_party                               # 三方库
└──vendor                                    # 产品源码

子系统(SubSystem)

子系统是一个逻辑概念,它具体由对应的部件构成。在多设备部署场景下,支持根据实际需求裁剪某些非必要的子系统或部件。在build/subsystem_config.json中定义。

部件(component)

部件是对子系统的进一步拆分,可复用的软件单元,每一个部件单独存放一个文件夹,它包含源码、配置文件、资源文件和编译脚本;能独立构建,以二进制方式集成,具备独立验证能力的二进制单元。部件由对应源码文件夹下的bundle.json文件进行定义。

{"name": "@ohos/sensor_lite",                         # HPM部件英文名称,格式"@组织/部件名称""description": "Obtaining sensor data",              # 部件功能一句话描述"version": "3.1",                                    # 版本号,版本号与OpenHarmony版本号一致"license": "Apache License 2.0","publishAs": "code-segment",                         # HPM包的发布方式,当前默认都为code-segment"segment": {"destPath": "base/sensors/sensor_lite"             # 发布类型为code-segment时为必填项,定义发布类型code-segment的源码路径},"dirs": { "base/sensors/sensor_lite"                         # HPM包的目录结构,字段必填内容可以留空},"scripts":{},                                        # HPM包定义需要执行的脚本,字段必填,值非必填"licensePath": "COPYING","readmePath": {"en": "README.rst"},"component": {"name": "sensor_lite",                             # 部件名称"subsystem": "sensors",                            # 部件所属子系统"syscap": [],                                      # 部件为应用提供的系统能力"features": [],                                    # 部件对外的可配置特性列表,一般与build中sub_component对应,可供产品配置"adapted_system_type": [ "mini", small, standard], # 轻量(mini) 小型(small)和标准(standard),可以是多个"rom": "92KB",                                     # 部件ROM估值"ram": "~200KB",                                   # 部件RAM估值"deps": {"components": [                                  # 部件依赖的其他部件"hilog_lite","ipc","samgr_lite",],"third_party": [ "bounds_checking_function" ]    # 部件依赖的三方开源软件"hisysevent_config": []                          # 部件HiSysEvent打点配置文件编译入口},"build": {                                         # 编译相关配置"sub_component": ["//base/sensors/sensor_lite/services:sensor_service","//base/sensors/sensor_lite/frameworks:sensor_lite"    ],                                               # 部件编译入口配置"inner_kits": [],                                # 部件对外暴露的接口,用于其它部件或者模块进行引用"test": ["//base/sensors/sensor_lite/interfaces/kits/native:unittest"]                                                # 部件测试用例编译入口}}
}

路径规则为:{领域/子系统集}/{子系统}/{部件},部件目录树规则如下:

component├── interfaces│    ││    ├── innerkits          # 系统内接口,部件间使用│    ││    └── kits               # 应用接口,应用开发者使用├── frameworks              # framework实现├── services                # service实现└── BUILD.gn                # 部件编译脚本

模块(module)

模块就是编译子系统的一个编译目标,部件也可以是编译目标。模块属于哪个部件,在gn文件中由part_name指定。

ohos_shared_library("ace_napi") {        # ace_napi为模块名,同时也是编译目标deps = [ ":ace_napi_static" ]        # 模块的依赖,被依赖的对象即使没有被subsystem显式包含,也会被编译public_configs = [ ":ace_napi_config" ] # 模块配置参数,比如cflagif(!is_cross_platform_build) {public_deps = [ "//third_party/libuv:uv" ]}subsystem_name = "arkui"              # 模块所属部件所属子系统名称part_name = "napi"                    # 模块所属部件名称,一个模块只能属于一个部件
}

特性(feature)

特性是部件用于体现不同产品之间的差异。通常不同特性可以定义不同编译宏或者代码,从而影响到源代码中define的特性。


如vender/hihope/rk3568_mini_system/config.json中配置了dsoftbus

{"subsystem": "communication","components": [{ "component": "dsoftbus", "features":["dsoftbus_get_devicename=false"] }]
}

 在/foundation/communication/dsoftbus/bundle.json中features下配置有dsoftbus_get_devicename

"features": ["dsoftbus_feature_conn_p2p","dsoftbus_feature_conn_legacy","dsoftbus_feature_disc_ble","dsoftbus_feature_conn_br","dsoftbus_feature_conn_ble","dsoftbus_feature_lnn_net","dsoftbus_feature_trans_udp_stream","dsoftbus_feature_trans_udp_file","dsoftbus_get_devicename","dsoftbus_feature_product_config_path","dsoftbus_feature_lnn_wifiservice_dependence","dsoftbus_feature_protocol_newip","dsoftbus_feature_ex_kits","dsoftbus_feature_wifi_notify"
],

在foundation/communication/dsoftbus/core/adapter/core_adapter.gni中通过判断dsoftbus_get_devicename属性从而走向不同的逻辑

...
if (!dsoftbus_get_devicename) {         # 通过判断走不同的逻辑bus_center_core_adapter_src += [ 
"$dsoftbus_root_path/core/adapter/bus_center/src/lnn_settingdata_event_monitor_virtual.cpp"]bus_center_core_adapter_inc +=[ "$dsoftbus_root_path/core/adapter/bus_center/include" ]
} else {bus_center_core_adapter_src += [ "$dsoftbus_root_path/core/adapter/bus_center/src/lnn_settingdata_event_monitor.cpp" ]bus_center_core_adapter_inc += ["$dsoftbus_root_path/adapter/common/bus_center/include","$dsoftbus_root_path/core/adapter/bus_center/include",]...

实践

本节以添加一个自定义的部件为例,描述如何编译部件,编译库、编译可执行文件等。

单一任务部件

实例部件compdemo1由模块demo1model_bin模块组成,该模块的编译目标为一个可执行程序。

示例部件compdemo1完整目录结构如下

my_test└── componentdemo1├── BUILD.gn├── bundle.json├── include│    └── model1.h└── src└── model1.c

1.编写gn脚本/my_test/componentdemo1/BUILD.gn

import("//build/ohos.gni")             # 导入编译模板,编译环境等依赖
ohos_executable("demo1model1_bin"){     # 可执行模块sources = [                        # 模块源码"src/model1.c"]include_dirs = [                   # 模块依赖头文件"include"]cflags = []cflags_c = []cflags_cc = []ldflags = []configs = []deps = []                          # 部件内部依赖external_deps = []                 # 跨部件的依赖,格式为"部件名:模块名"part_name = "compdemo1"            # 模块所属部件名称install_enable = true              # 是否安装(缺省默认不安装)
}注:复制代码时需要删除#及注释,否则无法编译通过

2.对应src下创建model1.c文件,include下创建model1.h文件,文件内容如下,其实现了一个简单的打印

.model1.h

#ifndef MODEL_1_H
#define MODEL_1_H
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endifvoid HelloPrint();#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif
#endif

model1.c

#include <stdio.h>
#include "model.h"int main(int argc, char **argv)
{HelloPrint();return 0;
}void HelloPrint()
{printf("This component dir is /my_test/componentdemo1, mycomptest->compdemo1->demo1model1_bin\n");
}

3.编写/my_test/componentdemo1/bundle.json

{"name": "@ohos/compdemo1","description": "compdemo1 services","version": "3.1","license": "Apache License 2.0","publishAs": "code-segment","segment": {"destPath": "my_test/componentdemo1"},"dirs": {},"scripts": {},"component": {"name": "compdemo1","subsystem": "mycomptest","syscap": [],"features": [],"adapted_system_type": [ "mini", "small", "standard" ],"rom": "10KB","ram": "10KB",    "deps": {"components": [],"third_party": [],"hisysevent_config": []},"build": {"sub_component": ["//my_test/componentdemo1:demo1model1_bin"],"inner_kits": [],"test": []}}}

注:此处bundle.json中的"name": "@ohos/compdemo1"和"component": {中的"name": "compdemo1"对应BUILD.gn文件部件名称"part_name"对应的值;"sub_component": ["//my_test/componentdemo1:demo1model1_bin"]对应BUILD.gn中ohos_executable("demo1model1_bin")的值。

4.在/build/subsystem_config.json文件最后增加如下内容

  ,"mycomptest": {"path": "my_test","name": "mycomptest"}...
}# 注:以上...}代表内容放在文件最后一级}下

  注:subsystem_config.json文件此处的"subsystem": "mycomptest"为bundle.json中的"subsystem": "mycomptest"。

5. 在/vender/{产品解决方案厂商}/{产品名称}/config.json文件最后增加如下内容,如rk3568芯片则路径为:/vendor/hihope/rk3568/config.json

    ,{"subsystem":"mycomptest","components": [{ "component": "compdemo1","features": []}]}...]
}注:以上...]}代表以上内容放在文件中最后一级数组中

注:config.json文件中此处的"subsystem":"mycomptest"为subsystem_config.json文件中的"name": "mycomptest";"component": "compdemo1"为BUILD.gn中的part_name = "compdemo1"。

6.编译

可以使用整编命令

./build.sh --product-name rk3568 --no-prebuilt-sdk

也可以使用“–build-target 模块名"单独编译,编译命令如下:

./build.sh  --product-name rk3568 --build-target demo1model1_bin --ccache

还可以编译模块所在的部件:

./build.sh --product-name rk3568 --build-target compdemo1 --ccache

7.烧录到设备后,输入模块命令即可打印

demo1model1_bin

组合任务部件

示例部件compdemo2由demo2model1_lib模块、demo2model2_bin模块和demo2model3_config模块组成,demo2model1_lib模块的编译目标为一个动态库,demo2model2_bin模块的目标为一个可执行程序,demo2model2_conf模块的目标为一个etc配置文件。

示例部件compdemo2的完整目录结构如下

my_test/componentdemo2├── a│    ├── BUILD.gn│    ├── include│    │    └── model1.h│    └── src│         └── model1.cpp├── b│    ├── BUILD.gn│    ├── include│    │    └── model2.h│    └── src│         └── model2.cpp├── c│    ├── BUILD.gn│    └── src│         └── model3.conf├── BUILD.gn└── bundle.json

demo2model1_lib模块编写

1.编写/my_test/componentdemo2/a/BUILD.gn

import("//build/ohos.gni")
config("demo2model1_lib_config"){include_dirs = [ "include" ]
}
ohos_shared_library("demo2model1_lib"){sources = ["include/model1.h","src/model1.cpp"]public_configs = [ ":demo2model1_lib_config" ]deps = []external_deps = []part_name = "compdemo2"
}

2.对应src下创建model1.c文件,include下创建model1.h文件,文件内容如下

model1.h

#ifndef MODEL_1_H
#define MODEL_1_H
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endifvoid HelloPrintModel1();#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif
#endif

 model1.cpp

#include <stdio.h>
#include "model1.h"int main(int argc, char **argv)
{HelloPrintModel1();return 0;
}void HelloPrintModel1()
{printf("This component dir is /my_test/componentdemo2/a mycomptest->compdemo1->demo2model1_lib\n");
}

3.编写/my_test/componentdemo2/b/BUILD.gn

import("//build/ohos.gni")
ohos_executable("demo2model2_bin"){sources = ["src/model2.cpp"]include_dirs = ["include"]deps = [ "../a:demo2model1_lib" ]external_deps = []part_name = "compdemo2"install_enable = true
}

 4.对应src下创建model2.c文件,include下创建model2.h文件,文件内容如下

model2.h

#ifndef MODEL_2_H
#define MODEL_2_H
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endifvoid HelloPrintModel2();#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif
#endif

model2.cpp

#include <stdio.h>
#include "model2.h"
#include "model1.h"int main(int argc, char **argv)
{HelloPrintModel2();return 0;
}void HelloPrintModel2()
{printf("This component dir is /my_test/componentdemo2/b mycomptest->compdemo1->demo2model2_bin begin\n");HelloPrintModel1();printf("This component dir is /my_test/componentdemo2/b mycomptest->compdemo1->demo2model2_bin end\n");
}

5.编写/my_test/componentdemo2/c/BUILD.gn

import("//build/ohos.gni")
ohos_prebuilt_etc("demo2model3_conf"){source = "src/model3.conf"relative_install_dir = "init"      # 模块安装相对路径,相对于system/etc;此时路径为system/etc/init下,如果有module_install_dir配置时,该配置不生效。part_name = "compdemo2"
}注:复制代码时#备注需要全部删除,否则无法编译通过

 6.对应src下创建model3.conf文件,文件内容示例如下

var_a=1
var_b=2

7.编写/my_test/componentdemo2/BUILD.gn

import("//build/ohos.gni")
group("compdemo2_group"){deps = ["a:demo2model1_lib","b:demo2model2_bin","c:demo2model3_conf",]
}

注:dps数组中的添加格式:目录名:模块名

8.编写/my_test/componentdemo2/bundle.json

{"name": "@ohos/compdemo2","description": "compdemo2 services","version": "3.1","license": "Apache License 2.0","publishAs": "code-segment","segment": {"destPath": "my_test/componentdemo2"},"dirs": {},"scripts": {},"component": {"name": "compdemo2","subsystem": "mycomptest","syscap": [],"features": [],"adapted_system_type": [ "mini", "small", "standard" ],"rom": "10KB","ram": "10KB",    "deps": {"components": [],"third_party": [],"hisysevent_config": []},"build": {"sub_component": ["//my_test/componentdemo2:compdemo2_group"],"inner_kits": [],"test": []}}}

注:此处"sub_component": ["//my_test/componentdemo2:compdemo2_group"]对应BUILD.gn中group("compdemo2_group")的值。 

9..在/build/subsystem_config.json文件最后增加如下内容

  ,"mycomptest": {"path": "my_test","name": "mycomptest"}...
}# 注:以上...}代表内容放在文件最后一级}下

 注:subsystem_config.json文件此处的"subsystem": "mycomptest"为bundle.json中的"subsystem": "mycomptest"。

10. 在/vender/{产品解决方案厂商}/{产品名称}/config.json文件最后增加如下内容,如rk3568芯片则路径为:/vendor/hihope/rk3568/config.json

    ,{"subsystem":"mycomptest","components": [{ "component": "compdemo2","features": []}]}...]
}注:以上...]}代表以上内容放在文件中最后一级数组中

注:config.json文件中此处的"subsystem":"mycomptest"为subsystem_config.json文件中的"name": "mycomptest";"component": "compdemo2"为BUILD.gn中的part_name = "compdemo2"。

 11.编译

可以使用整编命令

./build.sh --product-name rk3568 --no-prebuilt-sdk

也可以使用“–build-target 模块名"单独编译,编译命令如下:

./build.sh  --product-name rk3568 --build-target demo2model1_bin --ccache

还可以编译模块所在的部件:

./build.sh --product-name rk3568 --build-target compdemo2 --ccache

7.烧录到设备后,输入模块命令即可打印

后记:以上模块烧录后生成文件所在目录为:

模块类型生成文件目录
ohos_shared_library/system/lib
ohos_executable/system/bin
ohos_prebuilt_etc/system/etc/


http://www.mrgr.cn/news/91966.html

相关文章:

  • (新)01前缀和来临!优点多多!
  • 贪心算法
  • 代码随想录刷题day28|(栈与队列篇:栈)232.用栈实现队列
  • 深搜专题2:组合问题
  • 顺序表和STL——vector【 复习笔记】
  • Deepseek R1 和其他的大模型 共同辅助决策交通出行方案
  • java网络编程
  • Python项目源码34:网页内容提取工具1.0(Tkinter+requests+html2text)
  • QT 基础知识点
  • CLion配置源码阅读工具SourceTrail 阅读GCC
  • Linux基本指令(三)+ 权限
  • pipeline 使用git parameter插件实现动态选择分支构造
  • Windows辉煌的发展历程
  • 数据结构、算法和STL简介 【复习笔记】
  • 【Akashic Records】THE EGG
  • 正确清理C盘空间
  • bind()函数的概念和使用案例
  • windows11那些事
  • HTML项目一键打包工具:HTML2EXE 最新版
  • socket()函数的概念和使用案例