1# 部件化编译最佳实践 2 3OpenHarmony的软件以部件作为基本功能单元,但为了组装出不同形态的产品,部件可能需要提供不同规格的版本。本文主要介绍以下几个方面的编译实践方法: 4 5- 如何通过feature裁减部件的部分功能? 6- 如何判断当前产品中是否包含某个依赖的部件? 7- 部件的inner_kits裁减规则要求 8- 部件的napi模块裁减方法 9- 如何按需配置部件的系统能力? 10 11## 1. 使用feature配置进行部件差异化配置 12 13 feature主要用于描述部件在不同产品下的差异化行为。产品在装配部件时,可以通过配置不同的feature来使用部件不同的特性集。 14 15### 1.1 产品如何配置部件的feature 16 17 当前系统有两个版本的产品配置文件格式,配置方法分别如下: 18 19- V2产品配置文件 20 21 productdefine/common/products/xxx.json目录下V2版本产品配置文件中为部件配置不同feature的示例如下: 22 23```go 24{ 25 ... 26 "parts": { 27 "subsytemName:partName": { 28 "feature": [ "{partName}_feature_A": false ] 29 } 30 } 31} 32``` 33 34- V3产品配置文件 35 36 vendor/xxx/config.json目录下V3版本产品配置文件中为部件配置不同feature的示例如下: 37 38```go 39{ 40 ... 41 "subsystems": [{ 42 "subsystem": "subsystemName", 43 "components": [{ 44 "component": "partName", 45 "features":[ "{partName}_feature_A=false" ] 46 }] 47 }] 48} 49``` 50 51### 1.2 部件开发人员如何使用feature进行部件的特性隔离 52 53 下面介绍feature的声明、定义以及使用方法。 54 55- feature的声明 56 57 在部件的bundle.json文件中通过feature_list来声明部件的feature列表,每个feature都必须以"**{部件名}_**"开头。示例如下: 58 59```go 60{ 61 "name": "@ohos/xxx", 62 "component": { 63 "name": "partName", 64 "subsystem": "subsystemName", 65 "features": [ 66 "{partName}_feature_A" 67 ] 68 } 69} 70``` 71 72 features中可以为部件声明多个feature。 73 74- feature的定义 75 76 在部件内可通过以下方式定义feature的默认值: 77 78 ```go 79 declare_args() { 80 {partName}_feature_A = true 81 } 82 ``` 83 84 该值是此部件的默认值,产品可以在部件列表中重载该feature的值。 85 86 feature需给部件内多个模块使用时,建议把feature定义在部件的全局gni文件中,各个模块的BUILD.gn中import该gni文件。 87 88- feature的使用 89 90 BUILD.gn文件中可通过以下方式进行根据feature决定部分代码或模块参与编译: 91 92 ```go 93 if ({partName}_feature_A) { 94 sources += [ "xxx.c" ] 95 } 96 97 # 某个特性引入的依赖,需要通过该feature进行隔离 98 if ({partName}_feature_A) { 99 deps += [ "xxx" ] 100 external_deps += [ "xxx" ] 101 } 102 103 # bundle.json中不支持if判断,如果bundle.json中包含的sub_component需要被裁减,可以定义group进行裁减判断 104 group("testGroup") { 105 deps = [] 106 if ({partName}_feature_A) { 107 deps += [ "xxx" ] 108 } 109 } 110 ``` 111 112 也可以通过以下方式为模块定义代码宏进行代码级差异化编译: 113 114 ```go 115 if ({partName}_feature_A) { 116 defines += ["FEATUREA_DEFINE"] 117 } 118 ``` 119 120- 可裁剪模块使用独立BUILD.gn文件 121 122 实际裁剪部件中的单个模块时,该模块的BUILD.gn不能和其它必选模块混合在同一个BUILD.gn脚本中。 123 124 ```go 125 shared_library("requiredA") { 126 deps = ["dependB"] 127 } 128 129 shared_library("optionalC") { 130 deps = ["dependD"] 131 } 132 ``` 133 134 如上图所示,由于编译扫描部件时是以BUILD.gn文件为单位的,只要requiredA模块被引用,编译时可选的optionalC以及dependD模块都会被引入并被依赖。因此,建议可选模块使用单独的BUILD.gn脚本编写。 135 136## 2. 如何判断当前产品中是否包含某个依赖的部件 137 138如果部件A/B/C/D等都依赖部件O,而部件O可被裁减;则部件A/B/C/D等都需要定义裁减部件O时的隔离feature。在这种情况下,产品配置人员裁减部件O时,还需要手动关闭部件A/B/C/D为支持裁减部件O所定义的feature开关,装配时比较麻烦。 139 140为了解决该问题,编译框架将当前产品支持的所有部件都加载到了global_parts_info全局变量中,每个部件的编译脚本中可以通过部件名称判断该部件是否被裁减,然后自动修改部件的feature默认值,实现部件feature默认值可自动跟随裁减部件而同步更新。 141 142```go 143declare_args() { 144 "{partName}_feature_A" = true 145 146 if (!defined(global_parts_info.{subsystem_O}_{partName_O})) { 147 {partName}_feature_A = false 148 } 149} 150``` 151 152如上图所示,部件A的{partName}_feature_A特性默认为true,如果部件O被裁减,则该feature自动配置为false。 153 154注意:访问global_parts_info中的部件名称中如果包含有"-"或".",需转化为"_"。global_parts_info的具体内容可查看out/preloader/productName/parts_info.json文件。 155 156## 3. inner_kits模块裁剪处理策略 157 158inner_kits是部件之间依赖的接口集合,部件内的模块及特性裁剪不能影响inner_kits接口: 159 160- 所属部件没被裁剪,但内部有部分模块被裁剪: 161 162 此场景要求inner_kits接口不能有任何缺失,确保依赖该inner_kits的外部模块可正常编译,运行时可以内部实现上有差异。 163 164- 所属部件被裁剪: 165 166 依赖该inner_kits的模块需要一起被裁剪。 167 168 169 170## 4. napi模块需支持统一裁剪方式 171 172 部分IoT无屏产品不支持应用安装,不需要编译system_kits提供JS API。因此,每个子系统的napi模块需保证可独立裁剪。其裁剪方式通过全局的support_jsapi开关进行隔离。 173 174### 4.1 产品如何配置关闭所有的jsapi模块编译 175 176 support_jsapi的默认值为true,产品配置中可通过以下方法来修改: 177 178- V2产品配置文件 179 180 productdefine/common/products/xxx.json目录下的V2版本产品配置文件配置示例如下: 181 182```go 183{ 184 "product_name": "productName", 185 "version": "2.0", 186 "product_company": "xxx", 187 "support_jsapi": false, 188 ... 189} 190``` 191 192- V3产品配置文件 193 194 vendor/xxx/config.json目录下的V3版本产品配置文件配置示例如下: 195 196```go 197{ 198 "product_name": "productName", 199 "version": "3.0", 200 "device_company": "xxx", 201 "support_jsapi": false, 202 ... 203} 204``` 205 206### 4.2 部件开发人员如何使用support_jsapi进行部件的特性隔离 207 208support_jsapi是一个全局的feature,每个部件都可以参考1.2章的方式使用进行代码隔离。 209 210```go 211group("jsapi_group") { 212 deps = [] 213 if (support_jsapi) { 214 deps += [ "real_jsapi_module" ] 215 } 216} 217``` 218## 5.如何按需配置部件的系统能力 219系统能力即SystemCapability,又称syscap,是部件向开发者提供的接口的集合。 220### 5.1 部件配置系统能力 221部件配置系统能力是为了方便某个特定部件是否要打开或关闭特定的系统能力。 222 223部件配置系统能力的位置在部件目录下的bundle.json,配置示例如下所示: 224```json 225 "component": { 226 "name": "wifi", 227 "subsystem": "communication", 228 "syscap": [ 229 "SystemCapability.Communication.WiFi.STA = true", 230 "SystemCapability.Communication.WiFi.AP = true", 231 "SystemCapability.Communication.WiFi.P2P = false", 232 "SystemCapability.Communication.WiFi.Core = false", 233 "SystemCapability.Communication.WiFi.HotspotExt" 234 ] 235 ], 236 ... 237 } 238 239``` 240在component下加入syscap这一关键字,内部配置相应的系统能力,系统能力若无赋值,则默认为true,若有赋值,则按实际值为准。若值为true,则表示该部件默认开启此系统能力,若值为false,则表明该部件默认关闭此系统能力 241 242以上配置表明,WIFI的STA、AP、和HotspotExt三个系统能力是打开的,而P2P和Core是关闭的。 243### 5.2 产品配置系统能力 244产品配置系统能力是为了方便某个特定产品是否要打开或关闭特定的系统能力,若无配置,则以部件侧的配置为准,产品配置系统能力的位置在vender/{company}/{product}/config.json。 245 246如果要对产品的系统能力进行精细化配置,可在产品配置中加入syscap关键字,并对要配置的系统能力赋值。产品侧的配置优先级大于部件系统能力默认配置,若某一个系统能力在部件侧默认配置为false,在产品侧配置为true,则这个系统能力的最终配置为true。示例如下: 247```json 248{ 249 "subsystem": "communication", 250 "components": [ 251 ... 252 { 253 "component": "wifi", 254 "features": [], 255 "syscap": [ 256 "SystemCapability.Communication.WiFi.AP = false", 257 "SystemCapability.Communication.WiFi.P2P = true", 258 "SystemCapability.Communication.WiFi.HotspotExt = false" 259 ] 260 }, 261 ... 262``` 263以上配置表明,WiFi的AP和HotspotExt系统能力是关闭的,而P2P是打开的。综合部件侧的配置,最终STA、P2P为打开系统能力,而AP、Core和HotspotExt为关闭的系统能力。 264### 5.3 部件侧配置和产品侧配置的作用 265一般来说,当产品没有特性化差异的时候,我们仅需在部件侧配置系统能力,部件侧配置的系统能力是我们的基础,只有当产品存在特性化差异,需要关闭某个默认打开的系统能力或打开某个系统默认关闭的系统能力时,我们才会需要在产品侧配置。 266 267 268## 6. 部件feature与SystemCapability的关系 2691) feature是面向南向设备装配时的部件能力差异化配置,一个部件可以为不同品类的设备提供不同的feature集合。 2702) SystemCapability是面向北向应用开发的能力呈现。 2713) 无论选择部件的多少个feature,部件对外呈现的SystemCapability不能变化;如果feature影响部件对外的SystemCapability,则需要把该feature相关的部分拆分成独立的部件提供相应的SystemCapability。 272 273