From 2b2696b6bb30265b5d2e3afdbf76c7a156e40062 Mon Sep 17 00:00:00 2001 From: xxlight Date: Mon, 1 Aug 2022 09:46:57 +0800 Subject: [PATCH] =?UTF-8?q?docs:openharmony/docs=E4=BB=93=E4=B8=8B?= =?UTF-8?q?=E7=BC=96=E8=AF=91=E6=9E=84=E5=BB=BA=E6=96=87=E6=A1=A3=E6=95=B4?= =?UTF-8?q?=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: xxlight Change-Id: Iacdef000e71b742a5a1c3a4896f73e71687a0932 --- .../subsystems/figures/Ninja_Trace.png | Bin 0 -> 124376 bytes ...4\345\273\272\346\241\206\346\236\266.png" | Bin 0 -> 7397 bytes .../figures/compilation_process.png | Bin 0 -> 20700 bytes .../figures/dependency_classification.png | Bin 0 -> 19348 bytes .../figures/module_addition_process.png | Bin 0 -> 28413 bytes ...bsystem_component_module_relationships.png | Bin 0 -> 13765 bytes .../device-dev/subsystems/subsys-build-FAQ.md | 84 ++ .../device-dev/subsystems/subsys-build-all.md | 332 ++++++ .../subsystems/subsys-build-chip_solution.md | 95 ++ .../subsystems/subsys-build-component.md | 160 +++ .../subsystems/subsys-build-feature.md | 70 ++ ...build-gn-coding-style-and-best-practice.md | 1026 ++++++++--------- .../subsys-build-gn-hap-compilation-guide.md | 2 +- .../subsystems/subsys-build-mini-lite.md | 949 --------------- .../subsystems/subsys-build-module.md | 505 ++++++++ .../subsystems/subsys-build-product.md | 337 ++++++ .../subsystems/subsys-build-reference.md | 143 +++ .../subsystems/subsys-build-standard-large.md | 807 ------------- .../subsystems/subsys-build-subsystem.md | 32 + zh-cn/device-dev/subsystems/subsys-build.md | 13 +- 20 files changed, 2283 insertions(+), 2272 deletions(-) create mode 100644 zh-cn/device-dev/subsystems/figures/Ninja_Trace.png create mode 100644 "zh-cn/device-dev/subsystems/figures/OpenHarmony\347\274\226\350\257\221\346\236\204\345\273\272\346\241\206\346\236\266.png" create mode 100644 zh-cn/device-dev/subsystems/figures/compilation_process.png create mode 100644 zh-cn/device-dev/subsystems/figures/dependency_classification.png create mode 100644 zh-cn/device-dev/subsystems/figures/module_addition_process.png create mode 100644 zh-cn/device-dev/subsystems/figures/product_subsystem_component_module_relationships.png create mode 100644 zh-cn/device-dev/subsystems/subsys-build-FAQ.md create mode 100644 zh-cn/device-dev/subsystems/subsys-build-all.md create mode 100644 zh-cn/device-dev/subsystems/subsys-build-chip_solution.md create mode 100644 zh-cn/device-dev/subsystems/subsys-build-component.md create mode 100644 zh-cn/device-dev/subsystems/subsys-build-feature.md delete mode 100644 zh-cn/device-dev/subsystems/subsys-build-mini-lite.md create mode 100644 zh-cn/device-dev/subsystems/subsys-build-module.md create mode 100644 zh-cn/device-dev/subsystems/subsys-build-product.md create mode 100644 zh-cn/device-dev/subsystems/subsys-build-reference.md delete mode 100644 zh-cn/device-dev/subsystems/subsys-build-standard-large.md create mode 100644 zh-cn/device-dev/subsystems/subsys-build-subsystem.md diff --git a/zh-cn/device-dev/subsystems/figures/Ninja_Trace.png b/zh-cn/device-dev/subsystems/figures/Ninja_Trace.png new file mode 100644 index 0000000000000000000000000000000000000000..6444208247d4d737940845395d3e71da0bf8b481 GIT binary patch literal 124376 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 z%0A!l>En0h6v>^aTCJ6Ea?_@fbeY`wedR~2IhP>)NW%hr8keic;0ZrjaYZqgVrxh@ zw01L*I<5;x-XH^(T{%qYA>Zc#iof|YJ(na#x>9CVl2ffT>cwSgsyB~NuJD=If$*h}CY4Ba}_0qG4ca}V5< zWk*C;8K=)V{A4PlZI(*$)SyG3`FfCiTZu?$X&Dha02(ZFO5)kD{{p%npGcwW0Mpma zo)Qn#F+eWBS1Z7tVMImO-vY zd57db%=q}Ko$Ez*U^L5^-RE_WM6<)HWoqcA2#rMRqN$H|?-(#0g%rg~*T5rW6H;{u zOEu^!idgNHo*ICZ6K)lBR<4@p)+LMK(j#r_vb37!d?gbg6Yu3W_6n$Uj|Ozt5Y9*a z_ygx;60$yl)2Nzca#5M{P^+{$J2om&t(Cv_Zor_`4f@e+OaC`4huJyjT%>Q}E+S*) zui;%>GSU%+=(B3*v;jIR|AFU;iumg|(ao33seFTNoVC!9xy{E@e_jd)! zzbmL3;Jb1@+`7b<%(b1<+lzczR(%uz!3^dF4<%kM`#ymP-Z808Wv-il8{!C~9hNJ4 z0vE5$);Z0LEamI9(q%tBtTgss)e&YhvkBY<5bs2`-LRj3KNr{WfGlLrJ8m7Nw`?e@ahP&&Aj&RU@X zqI&*r=z*;%YSj8E@Z$^VCF(0sQ7_nxmsDDDT)>yd)r*#Gt9d}3T6Ur-cNgiTLN(}k zr@9SO(Nx6DyH~^C3AlCfbRBlpg9BSti)<(dqVh%*H%G>Hg>*7&k(c@7m7Df+gXk*T z=~tH}T3re?K}}@U%x@Ha*F99h`!y!?i5{!*J@uOY1Z6ZNj7DO#_loZByrKLmTlc1R zPYr#ztga0U=luiK-EIE0+>q{KyNC%hkLHT#Kozw#{fNcNp5h6g&<}q>mt-wiRMj&vk@UE1H53T-Qez}3x?F^9Yw0xF zMVX=nQ@3mzDU2;&BJ>MD|n~X%fZu_ zL2Zk8-JE)UTuVuv@N>t9oCa`cB=KNjdCCIwsEQQu{X@&)j%8!WD^M*-u!`bgQAq=m z8I=Dae3$rF4Lox$GIvnFQF|Fu=|Lcg@u`;I;~gu-K${=c6Xp z4;N241>REf78AC{@vJ5CTb2215sxHWsO%Ol#V6_P5@H8uf?M8cVWSah{3=!VZ<9tk zKjZQxc-Ei~qbUAO=+HolL_8yGJHA5<(A-HAIcKxtYpr5L%^AQTJfh5DpA{}g`SjsCU!M@qFX zljML&d02KQ7OD#ZL_1%E*hb46NBmv8nVo{dte!$5Pc7NF=~3WgHSm0f63dbU07~)T zR``=Br{TN3WyCRHuZYg)XNFnwvf2mtfCm?{cUVdtv~w2UDm6B54Csb=E+Izzye#s* zZ58>gDa?y1ea|mbG*j!A;}S46$q)cWAQb5Y_VrpHKwH=!6Lang$s7cFgze;>Lbeg) z;@4XA6w8HlvtM}bwY1h}6zlczRV=+C*F!;dc%9Cv_$GP$1ar4-7);-#)kqm|Cw?6t zL0h~DP*SJOOh4(hz*jHiA6Parzp%F|AE47vH2pUNVhO3Eip=Aq<-N!PE~fGwsHn^t z#0^da+1_p{ZLs^;h?~yDTYlDN31C$Vs=kI-FCyviY0J5Fq-PONA0b+{% zCVleU!uN2B|k;A9dDDed15xB)m#w*tTrliO?^=(@IMwevD0*86W&t6Xt zKEztDe%YvKgI^zGJwz zcu8Ci@&6(1&BLK?|Nj3XX+t8CwJ2KTk|OJnwYmyzc2iMyvS*kX>MF`IAr#q(vW$I% zF)bLfj-81q+gN4{W-~Kp{NC#NEcgApm+$xZ9)~|1s_Ag<=kxV=K2H*dqq^70_a1Qg zs8`vE^Xd{H4!&fmk~CV_)0TsOwTzwWG68_zzz_JoVrCUqEd zlCXBFzdQ8AwZiN_dOnB5G${t;ux34|8Ksz#it*feAoe$JF^OjDEja&@kmN8vaTa(x zJz#%nbO4!&vT}tmDc_vP_V-9{Ko1|#BkuE{+N}QhcWx+i*21ZAAdDh)T?{yKA@-p2hO%*TPsLEt>JE2D8 z@C5bz$@JoOAn;znC(rHUqgrn6>UM_P^Nq;+TvZoa?HA=eG}NTS+|_`UBaQif1+pjA zPGT)!VQm{RZ`h58y%EVeKf0AGq=?-wJwiL{d%q+b8yj#wL}N*m9~qOyP83tiUYo~M zwb{1W{S|TseMW8njT8}tHd$(MqXspq>Uhgutm=_?M_4wH zyjl2Z$BW2QhL8fF^w;_+ZTOz~!j(z!zSd(4JVBN39e(g zx2rQNtz}oYYJ;gkd+Lm5O=k_Moz-(%4se?%^m{=%859CHL!(8pEi+y@`dP$iY>G|f z|0F{Icg=!p5dv90TJIh7xm0LBD?a$By;dc7E?K3n+@Kn96d0XxJYO6^HALEHB$+Ouy|o(j&SHFWcT4!( zQo1g>LXOyh7eBJ9{fY?rskI4A+@wkNEf{J_&^4M&zLp>Gv%0D4ZIuU&9kT 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 literal 0 HcmV?d00001 diff --git a/zh-cn/device-dev/subsystems/figures/compilation_process.png b/zh-cn/device-dev/subsystems/figures/compilation_process.png new file mode 100644 index 0000000000000000000000000000000000000000..fd64610a17c3e27fa01dca049c226dd8bdbafae9 GIT binary patch literal 20700 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 literal 0 HcmV?d00001 diff --git a/zh-cn/device-dev/subsystems/figures/module_addition_process.png b/zh-cn/device-dev/subsystems/figures/module_addition_process.png new file mode 100644 index 0000000000000000000000000000000000000000..c2e8fff89e80747d7c3d1de804face9bae2ef149 GIT binary patch literal 28413 zcmdSBXH=70)GiuCMYbX;3QAR!Vxc2Q2|=n#wW4A`B~qlR5CVY^6adOb z2_YyVuqmNQq=YCSEhGU#2oOTf8+7k)pL_nC`{#~ve>gIXZ`Ql!Tyw28pJzVPXnR{r zk-sGW0)apxXU~{j0D(5m0Dl~}Z3VumoPQqxd=*SW(n;VjCr%48b!M$WHLOBZe)()5tXmgak5b&|d ztXL5E5RmT^0D;0ly8){}#$nswz{f%32z}sV*Fh5*;A7jayq&q+#u4jiW<6CGLiYmz&jlY4Meyypl-tZ!@yl&xKEvw)0PSewU^WYsI z+TlKdgS(iM#1v8Va^v|QHtE`D>)CilYu}rTY0o=tbjf?oS1&t2_mPVzE1ihZU`f!R zX|bR&sK4}@SkrKv?ufFKj@O)O!Og!7C|o+CfWwYApg&>U2f4@D3x$Dh_;s9IXtfKy z5HAOzi+~H)3V0^@@9RTW7M7ia!X^MCmA_ZsY0D48G3q&W51SV|Z=hJ;9<-@ozOW5J z+LpkpK7}qf%30)vE>4~I9oE2WIj{WfFzzD9xf((gH1-4hv)Ak1J^OO}(skeO8u*i| z6^g6*UV(w9>e&Lh8i3#aD$ENd!%0Dn@zZ51^9g9{VnKH)z>!-H_myZx=!Yd9>=Ven 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 ble?xWLHD`aow+p78_e9)`bdGX(~bWEILLS~ literal 0 HcmV?d00001 diff --git a/zh-cn/device-dev/subsystems/figures/product_subsystem_component_module_relationships.png b/zh-cn/device-dev/subsystems/figures/product_subsystem_component_module_relationships.png new file mode 100644 index 0000000000000000000000000000000000000000..926799f40a3ff9b8a00156c75fed6f137d8766e2 GIT binary patch literal 13765 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 F{Xg@TZ{z>~ literal 0 HcmV?d00001 diff --git a/zh-cn/device-dev/subsystems/subsys-build-FAQ.md b/zh-cn/device-dev/subsystems/subsys-build-FAQ.md new file mode 100644 index 0000000000..27b6c0f60d --- /dev/null +++ b/zh-cn/device-dev/subsystems/subsys-build-FAQ.md @@ -0,0 +1,84 @@ +# 常见问题 + +## 常见编译问题和解决方法 + +### 编译构建过程中,提示“usr/sbin/ninja: invalid option -- w” + +- **现象描述:** 编译失败,提示“usr/sbin/ninja: invalid option -- w”。 + +- **可能原因:** 编译环境中ninja版本太低,不支持--w选项。 + +- **解决办法:** 卸载环境中ninja和gn,按照[获取工具](../../device-dev/get-code/gettools-ide.md)。 + +### 编译构建过程中,提示“/usr/bin/ld: cannot find -lncurses” + +- **现象描述:** 编译失败,提示“/usr/bin/ld: cannot find -lncurses”。 + +- **可能原因:** 编译环境ncurses库缺失。 + +- **解决办法:** + + ```shell + sudo apt-get install lib32ncurses5-dev + ``` + +### 编译构建过程中,提示“line 77: mcopy: command not found” + +- **现象描述:** 编译失败,提示“line 77: mcopy: command not found”。 + +- **可能原因:** 编译环境未安装mcopy。 + +- **解决办法:** + + ```shell + sudo apt-get install dosfstools mtools + ``` + +### 编译构建过程中,提示“riscv32-unknown-elf-gcc: error trying to exec 'cc1': execvp: No such file or directory” + +- **现象描述:** 编译失败,提示“riscv32-unknown-elf-gcc: error trying to exec 'cc1': execvp: No such file or directory”。 + +- **可能原因:** 当前用户对riscv编译器路径下的文件访问权限不够。 + +- **解决办法:** 查询gcc_riscv32所在目录。 + + ```shell + which riscv32-unknown-elf-gcc + ``` + + 使用chmod命令修改目录权限为755。 + +### 编译构建过程中,提示“No module named 'Crypto'” + +- **现象描述:** 编译失败,提示“No module named 'Crypto'”。 + +- **可能原因:** python3未安装Crypto。 + +- **解决办法:** + + 1. 查询Python版本号。 + + ```shell + python3 --version + ``` + + 2. 需使用python3.9.2以上版本,然后安装pycryptodome。 + + ```shell + sudo pip3 install pycryptodome + ``` + +### 编译构建过程中,提示“xx.sh : xx unexpected operator” + +- **现象描述:** 编译失败:“xx.sh [: xx unexpected operator”。 + +- **可能原因:** 编译环境shell不是bash。 + +- **解决办法:** + + ```shell + sudo rm -rf /bin/sh + sudo ln -s /bin/bash /bin/sh + ``` + + diff --git a/zh-cn/device-dev/subsystems/subsys-build-all.md b/zh-cn/device-dev/subsystems/subsys-build-all.md new file mode 100644 index 0000000000..f298495244 --- /dev/null +++ b/zh-cn/device-dev/subsystems/subsys-build-all.md @@ -0,0 +1,332 @@ +# 编译构建指导 + +## 概述 + +OpenHarmony编译子系统是以GN和Ninja构建为基座,对构建和配置粒度进行部件化抽象、对内建模块进行功能增强、对业务模块进行功能扩展的系统,该系统提供以下基本功能: + +- 以部件为最小粒度拼装产品和独立编译。 +- 支持轻量、小型、标准三种系统的解决方案级版本构建,以及用于支撑应用开发者使用IDE开发的SDK开发套件的构建。 +- 支持芯片解决方案厂商的灵活定制和独立编译。 + +### 适用范围 + +本指导适用于轻量、小型、标准三种系统。[芯片解决方案配置规则](subsys-build-chip_solution.md#芯片解决方案配置规则)与[新增并编译芯片解决方案](subsys-build-chip_solution.md#新增并编译芯片解决方案)主要和轻量系统、小型系统相关,其他内容都是通用的。 + +### 基本概念及包含关系 + + +在了解编译构建子系统的能力前,应了解如下基本概念: + +- 平台:开发板和内核的组合,不同平台支持的子系统和部件不同。 +- 产品:产品是包含一系列部件的集合,编译后产品的镜像包可以运行在不同的开发板上。 +- 子系统:OpenHarmony整体遵从分层设计,从下向上依次为:内核层、系统服务层、框架层和应用层(详见[OpenHarmony技术架构](https://gitee.com/openharmony#技术架构))。系统功能按照“系统 > 子系统 > 部件”逐级展开,在多设备部署场景下,支持根据实际需求裁剪某些非必要的子系统或部件。子系统是一个逻辑概念,它具体由对应的部件构成。 +- 部件:对子系统的进一步拆分,可复用的软件单元,它包含源码、配置文件、资源文件和编译脚本;能独立构建,以二进制方式集成,具备独立验证能力的二进制单元。需要注意的是下文中的芯片解决方案本质是一种特殊的部件。 +- 模块:模块就是编译子系统的一个编译目标,部件也可以是编译目标。 +- 特性:特性是部件用于体现不同产品之间的差异。 +- GN:Generate Ninja的缩写,用于产生Ninja文件。 +- Ninja:Ninja是一个专注于速度的小型构建系统。 +- hb:OpenHarmony的命令行工具,用来执行编译命令。 + +基于以上概念,编译子系统通过配置来实现编译和打包,该子系统主要包括:模块、部件、子系统、产品。 + +**图1** 产品、子系统、部件和模块间关系 + +![产品子系统部件模块关系](figures/product_subsystem_component_module_relationships.png) + +图1体现了编译子系统的各部分关系,主要体现为: + +- 子系统是某个路径下所有部件的集合,一个部件只能属于一个子系统。 +- 部件是模块的集合,一个模块只能归属于一个部件。 +- 通过产品配置文件配置一个产品包含的部件列表,部件不同的产品配置可以复用。 +- 部件可以在不同的产品中实现有差异,通过变体或者特性feature实现。 +- 模块就是编译子系统的一个编译目标,部件也可以是编译目标。 + +### 运作机制 + +编译构建可以编译产品、部件和模块,但是不能编译子系统。编译构建流程如下图所示,主要分设置和编译两步: + +**图2** 编译构建流程 + +![编译流程](figures/compilation_process.png) + +1. hb set: 设置要编译的产品。 + +2. hb build: 编译产品、开发板或者部件。编译主要过程如下: + + 1. 读取编译配置:根据产品选择的开发板,读取开发板config.gni文件内容,主要包括编译工具链、编译链接命令和选项等。 + 2. 调用GN:调用gn gen命令,读取产品配置生成产品解决方案out目录和Ninja文件。 + 3. 调用Ninja:调用ninja -C out/board/product启动编译。 + 4. 系统镜像打包:将部件编译产物打包,设置文件属性和权限,制作文件系统镜像。 + +### 约束限制 + +编译环境目前主要支持Ubuntu18.04和Ubuntu20.04(Ubuntu22.04暂不支持)。 + +### 环境配置 + +安装编译所需的程序包。 安装命令: + +- 安装方式一:使用脚本,在当前工程目录执行 + ```shell + ./build/build_scripts/env_setup.sh + ``` + +- 安装方式二:apt-get和pip3 install命令安装 + ```shell + apt-get update -y + apt-get install -y apt-utils binutils bison flex bc build-essential make mtd-utils gcc-arm-linux-gnueabi u-boot-tools python3.9.2 python3-pip git zip unzip curl wget gcc g++ ruby dosfstools mtools default-jre default-jdk scons python3-distutils perl openssl libssl-dev cpio git-lfs m4 ccache zlib1g-dev tar rsync liblz4-tool genext2fs binutils-dev device-tree-compiler e2fsprogs git-core gnupg gnutls-bin gperf lib32ncurses5-dev libffi-dev zlib* libelf-dev libx11-dev libgl1-mesa-dev lib32z1-dev xsltproc x11proto-core-dev libc6-dev-i386 libxml2-dev lib32z-dev libdwarf-dev + apt-get install -y grsync xxd libglib2.0-dev libpixman-1-dev kmod jfsutils reiserfsprogs xfsprogs squashfs-tools pcmciautils quota ppp libtinfo-dev libtinfo5 libncurses5 libncurses5-dev libncursesw5 libstdc++6 gcc-arm-none-eabi vim ssh locales doxygen + # python需要安装以下模块,repo文件在上一章节约束与限制的源码获取中得到。 + chmod +x /usr/bin/repo + pip3 install --trusted-host https://repo.huaweicloud.com -i https://repo.huaweicloud.com/repository/pypi/simple requests setuptools pymongo kconfiglib pycryptodome ecdsa ohos-build pyyaml prompt_toolkit==1.0.14 redis json2html yagmail python-jenkins + pip3 install esdk-obs-python --trusted-host pypi.org + pip3 install six --upgrade --ignore-installed six + #还需要安装llvm,hc-gen,gcc_riscv32,Ninja,node-v14.15.4-linux-x64,GN,如果用户使用的shell环境不是bash或者zsh的配置,则需要配置以下环境变量: + # export PATH=/home/tools/llvm/bin:$PATH + # export PATH=/home/tools/hc-gen:$PATH + # export PATH=/home/tools/gcc_riscv32/bin:$PATH + # export PATH=/home/tools/ninja:$PATH + # export PATH=/home/tools/node-v12.20.0-linux-x64/bin:$PATH + # export PATH=/home/tools/gn:$PATH + # export PATH=~/.local/bin:$PATH + ``` + + ![icon-note.gif](public_sys-resources/icon-note.gif)**注意**:上述安装ohos-build的过程中会安装编译工具hb,但有时会出现hb安装不成功的情况,若安装不成功,则按照[hb安装](../../device-dev/quick-start/quickstart-lite-env-setup.md#安装hb)重新安装。 + + +## 配置规则 + +为了实现芯片解决方案、产品解决方案与OpenHarmony是解耦的、可插拔的,子系统、产品、部件、芯片解决方案、模块和特性需遵循一定的规则,具体配置规则见如下链接: + +- [产品配置规则](subsys-build-product.md#产品配置规则) +- [子系统配置规则](subsys-build-subsystem.md#子系统配置规则) +- [部件配置规则](subsys-build-component.md#部件配置规则) +- [模块配置规则](subsys-build-module.md#模块配置规则) +- [芯片解决方案配置规则](subsys-build-chip_solution.md#芯片解决方案配置规则) +- [特性配置规则](subsys-build-feature.md#特性配置规则) + +## 编译构建使用指导 + +### 目录结构 + +```shell + +/build # 编译构建主目录 + +├── __pycache__ +├── build_scripts/ # 编译相关的python脚本 +├── common/ +├── config/ # 编译相关的配置项 +├── core +│ ├── gn/ # 编译入口BUILD.gn配置 + └── build_scripts/ +├── docs +gn_helpers.py* +lite/ # hb和preloader入口 +misc/ +├── ohos # OpenHarmony编译打包流程配置 +│ ├── kits # kits编译打包模板和处理流程 +│ ├── ndk # ndk模板和处理流程 +│ ├── notice # notice模板和处理流程 +│ ├── packages # 版本打包模板和处理流程 +│ ├── sa_profile # sa模板和处理流程 +│ ├── sdk # sdk模板和处理流程,包括sdk中包含的模块配置 +│ └── testfwk # 测试相关的处理 +├── ohos.gni* # 汇总了常用的gni文件,方便各个模块一次性import +├── ohos_system.prop +├── ohos_var.gni* +├── prebuilts_download.sh* +├── print_python_deps.py* +├── scripts/ +├── subsystem_config.json +├── subsystem_config_example.json +├── templates/ # c/c++编译模板定义 +├── test.gni* +├── toolchain # 编译工具链配置 +├── tools # 常用工具 +├── version.gni +├── zip.py* + +``` + + + +### 编译命令 + +首先,在源码根目录下执行prebuilts脚本进行预编译,安装编译器及二进制工具。 + +```shell +bash build/prebuilts_download.sh +``` + +接着,使用命令行方式或hb方式执行编译命令。 + +1.命令行方式 + +- 代码根目录下执行全量版本的编译命令: + + ```shell + ./build.sh --product-name {product_name} + ``` + + {product_name}为当前版本支持的平台。比如:hispark_taurus_standard等。 + + 编译完成后,结果镜像保存在 out/{device_name}/packages/phone/images/ 目录下。 + +- 编译命令支持选项:./build.sh + + ```shell + -h, --help # 显示帮助信息并退出 + --source-root-dir=SOURCE_ROOT_DIR # 指定路径 + --product-name=PRODUCT_NAME # 指定产品名 + --device-name=DEVICE_NAME # 指定装置名称 + --target-cpu=TARGET_CPU # 指定cpu + --target-os=TARGET_OS # 指定操作系统 + -T BUILD_TARGET, --build-target=BUILD_TARGET # 指定编译目标,可以指定多个 + --gn-args=GN_ARGS # GN参数,支持指定多个 + --ninja-args=NINJA_ARGS # Ninja参数,支持指定多个 + -v, --verbose # 生成时显示所有命令行 + --keep-ninja-going # 让Ninja持续到1000000个工作失败 + --jobs=JOBS + --export-para=EXPORT_PARA + --build-only-gn # 只做GN解析,不运行Ninja + --ccache # 可选 如果使用ccache,需要本地安装ccache + --fast-rebuild # 快速重建,默认值为False + --log-level=LOG_LEVEL # 指定编译期间的日志级别','三个级别可选:debug, info and error,default='info' + --device-type=DEVICE_TYPE # 指定设备类型,默认值为'default' + --build-variant=BUILD_VARIANT # 指定设备操作模式,默认值为'user' + ``` + +2.hb方式 + +hb是OpenHarmony的命令行工具,用来执行编译命令。以下对hb的常用命令进行说明。 + +**hb set** + +设置要编译的产品 + +```shell +hb set -h +usage: hb set [-h] [-root [ROOT_PATH]] [-p] + +optional arguments: + -h, --help show this help message and exit + -root [ROOT_PATH], --root_path [ROOT_PATH] + Set OHOS root path + -p, --product Set OHOS board and kernel +``` + +- hb set 后无参数,进入默认设置流程 + +- hb set -root dir可直接设置代码根目录 + +- hb set -p设置要编译的产品 + +**hb env** + +查看当前设置信息 + +```shell +hb env +[OHOS INFO] root path: xxx +[OHOS INFO] board: hispark_taurus +[OHOS INFO] kernel: liteos +[OHOS INFO] product: ipcamera +[OHOS INFO] product path: xxx/vendor/hisilicon/ipcamera +[OHOS INFO] device path: xxx/device/hisilicon/hispark_taurus/sdk_linux_4.19 +``` + +**hb build** + +编译产品、部件、模块或芯片解决方案。 + +```shell +hb build -h +usage: hb build [-h] [-b BUILD_TYPE] [-c COMPILER] [-t [TEST [TEST ...]]] [-cpu TARGET_CPU] [--dmverity] [--tee] + [-p PRODUCT] [-f] [-n] [-T [TARGET [TARGET ...]]] [-v] [-shs] [--patch] [--compact-mode] + [--gn-args GN_ARGS] [--keep-ninja-going] [--build-only-gn] [--log-level LOG_LEVEL] [--fast-rebuild] + [--device-type DEVICE_TYPE] [--build-variant BUILD_VARIANT] + [component [component ...]] + +positional arguments: + component name of the component, mini/small only + +optional arguments: + -h, --help show this help message and exit + -b BUILD_TYPE, --build_type BUILD_TYPE + release or debug version, mini/small only + -c COMPILER, --compiler COMPILER + specify compiler, mini/small only + -t [TEST [TEST ...]], --test [TEST [TEST ...]] + compile test suit + -cpu TARGET_CPU, --target-cpu TARGET_CPU + select cpu + --dmverity enable dmverity + --tee Enable tee + -p PRODUCT, --product PRODUCT + build a specified product with {product_name}@{company} + -f, --full full code compilation + -n, --ndk compile ndk + -T [TARGET [TARGET ...]], --target [TARGET [TARGET ...]] + compile single target + -v, --verbose show all command lines while building + -shs, --sign_haps_by_server + sign haps by server + --patch apply product patch before compiling + --compact-mode compatible with standard build system set to false if we use build.sh as build entrance + --gn-args GN_ARGS specifies gn build arguments, eg: --gn-args="foo="bar" enable=true blah=7" + --keep-ninja-going keeps ninja going until 1000000 jobs fail + --build-only-gn only do gn parse, donot run ninja + --log-level LOG_LEVEL + specifies the log level during compilationyou can select three levels: debug, info and error + --fast-rebuild it will skip prepare, preloader, gn_gen steps so we can enable it only when there is no change + for gn related script + --device-type DEVICE_TYPE + specifies device type + --build-variant BUILD_VARIANT + specifies device operating mode +``` + +- hb build后无参数,会按照设置好的代码路径、产品进行编译,编译选项使用与之前保持一致。-f 选项将删除当前产品所有编译产品,等同于hb clean + hb build. + +- hb build {component_name}:基于设置好的产品对应的单板、内核,单独编译部件(e.g.:hb build kv_store)。 + +- hb build -p ipcamera@hisilicon:免set编译产品,该命令可以跳过set步骤,直接编译产品。 + +- 在device/board/device_company下单独执行hb build会进入内核选择界面,选择完成后会根据当前路径的单板、选择的内核编译出仅包含内核、驱动的镜像。 + +**hb clean** + +清除out目录对应产品的编译产物,仅保留args.gn、build.log。清除指定路径可输入路径参数:hb clean out/board/product,默认将清除当前hb set的产品对应out路径。 + +```shell +hb clean +usage: hb clean [-h] [out_path] + +positional arguments: + out_path clean a specified path. + +optional arguments: + -h, --help show this help message and exit +``` + +### 新增并编译不同配置 + +根据上一节的配置规则新增相应配置并进行编译,主要包含产品、部件、芯片解决方案和模块四个粒度。具体如下: + +- [新增并编译产品](subsys-build-product.md#新增并编译产品) +- [新增并编译部件](subsys-build-component.md#新增并编译部件) +- [新增并编译模块](subsys-build-module.md#新增并编译模块) +- [新增并编译芯片解决方案](subsys-build-chip_solution.md#新增并编译芯片解决方案) + +## 常见问题 + +- [常见编译问题和解决方法](subsys-build-FAQ.md#常见编译问题和解决方法) + +## 参考信息 + +- [关于deps、external_deps的使用](subsys-build-reference.md#关于deps、external_deps的使用) +- [开源软件Notice收集策略说明](subsys-build-reference.md#开源软件notice收集策略说明) +- [加快本地编译的一些参数](subsys-build-reference.md#加快本地编译的一些参数) +- [查看NinjaTrace](subsys-build-reference.md#查看ninjatrace) + diff --git a/zh-cn/device-dev/subsystems/subsys-build-chip_solution.md b/zh-cn/device-dev/subsystems/subsys-build-chip_solution.md new file mode 100644 index 0000000000..23ec6c6007 --- /dev/null +++ b/zh-cn/device-dev/subsystems/subsys-build-chip_solution.md @@ -0,0 +1,95 @@ +# 芯片解决方案 +### 芯片解决方案配置规则 + +- 芯片解决方案是指基于某款开发板的完整解决方案,包含驱动、设备侧接口适配、开发板sdk等。 +- 芯片解决方案是一个特殊的部件,源码路径规则为:**device/{开发板}/{芯片解决方案厂商}**。 +- 芯片解决方案部件会随产品选择的开发板默认编译。 +- 芯片解决方案目录树规则如下: + +```shell + device + └── board + └── company # 芯片解决方案厂商 + └── hispark_aries # 开发板名称 + ├── BUILD.gn # 编译脚本 + ├── hals # OS南向接口适配 + ├── linux # 可选,linux内核版本 + │ └── config.gni # linux版本编译配置 + └── liteos_a # 可选,liteos内核版本 + └── config.gni # liteos_a版本编译配置 +``` + +![icon-note.gif](public_sys-resources/icon-note.gif)**注意**:config.gni为开发板编译相关的配置,编译时会采用该配置文件中的参数编译所有OS部件,编译阶段系统全局可见。 + +- config.gni的关键字段介绍如下: + +```shell + kernel_type: 开发板使用的内核类型,例如:“liteos_a”, “liteos_m”, “linux”。 + kernel_version: 开发使用的内核版本,例如:“4.19”。 + board_cpu: 开发板CPU类型,例如:“cortex-a7”, “riscv32”。 + board_arch: 开发芯片arch, 例如: “armv7-a”, “rv32imac”。 + board_toolchain: 开发板自定义的编译工具链名称,例如:“gcc-arm-none-eabi”。若为空,则使用默认为ohos-clang。 + board_toolchain_prefix:编译工具链前缀,例如:“gcc-arm-none-eabi”。 + board_toolchain_type: 编译工具链类型,目前支持gcc和clang。例如:“gcc” ,“clang”。 + board_cflags: 开发板配置的c文件编译选项。 + board_cxx_flags: 开发板配置的cpp文件编译选项。 + board_ld_flags: 开发板配置的链接选项。 +``` + +### 新增并编译芯片解决方案 + +编译构建支持添加新的芯片解决方案厂商,具体步骤如下: + +1. 创建芯片解决方案目录。 按照芯片解决方案配置规则创建目录,以芯片厂商realtek的“rtl8720“开发板为例, 在代码根目录执行: + + ```shell + mkdir -p device/board/realtek/rtl8720 + ``` + +2. 创建内核适配目录,并编写开发板编译配置config.gni文件。 以realtek的“rtl8720“开发板的liteos_a适配为例,device/board/realtek/rtl8720/liteo_a/config.gni的内容如下: + + ```shell + # Kernel type, e.g. "linux", "liteos_a", "liteos_m". + kernel_type = "liteos_a" + + # Kernel version. + kernel_version = "3.0.0" + + # Board CPU type, e.g. "cortex-a7", "riscv32". + board_cpu = "real-m300" + + # Board arch, e.g. "armv7-a", "rv32imac". + board_arch = "" + + # Toolchain name used for system compiling. + # E.g. gcc-arm-none-eabi, arm-linux-harmonyeabi-gcc, ohos-clang, riscv32-unknown-elf. + # Note: The default toolchain is "ohos-clang". It's not mandatory if you use the default toochain. + board_toolchain = "gcc-arm-none-eabi" + + # The toolchain path instatlled, it's not mandatory if you have added toolchian path to your ~/.bashrc. + board_toolchain_path = + rebase_path("//prebuilts/gcc/linux-x86/arm/gcc-arm-none-eabi/bin", + root_build_dir) + + # Compiler prefix. + board_toolchain_prefix = "gcc-arm-none-eabi-" + + # Compiler type, "gcc" or "clang". + board_toolchain_type = "gcc" + + # Board related common compile flags. + board_cflags = [] + board_cxx_flags = [] + board_ld_flags = [] + ``` + +3. 编写编译脚本。 在开发板目录下创建BUILD.gn,target名称应与开发板名称一致。以realtek的rtl8720开发板为例,device/board/realtek/rtl8720/BUILD.gn内容可以是: + + ```shell + group("rtl8720") { # target类型也可以shared_library, static_library, executable + # 具体内容 + ...... + } + ``` + +4. 编译芯片解决方案。 在开发板目录下执行hb build,即可启动芯片解决方案的编译。 diff --git a/zh-cn/device-dev/subsystems/subsys-build-component.md b/zh-cn/device-dev/subsystems/subsys-build-component.md new file mode 100644 index 0000000000..f4d1e42770 --- /dev/null +++ b/zh-cn/device-dev/subsystems/subsys-build-component.md @@ -0,0 +1,160 @@ +# 部件 +### 部件配置规则 + +部件的bundle.json放在部件源码的根目录下。以泛sensor子系统的sensor服务部件为例,部件属性定义描述文件字段说明如下: + +```shell +{ + "name": "@ohos/sensor_lite", # HPM部件英文名称,格式"@组织/部件名称" + "description": "Sensor services", # 部件功能一句话描述 + "version": "3.1", # 版本号,版本号与OpenHarmony版本号一致 + "license": "MIT", # 部件License + "publishAs": "code-segment", # HPM包的发布方式,当前默认都为code-segment + "segment": { + "destPath": "" + }, # 发布类型为code-segment时为必填项,定义发布类型code-segment的代码还原路径(源码路径) + "dirs": {"base/sensors/sensor_lite"}, # HPM包的目录结构,字段必填内容可以留空 + "scripts": {}, # HPM包定义需要执行的脚本,字段必填,值非必填 + "licensePath": "COPYING", + "readmePath": { + "en": "README.rst" + }, + "component": { # 部件属性 + "name": "sensor_lite", # 部件名称 + "subsystem": "", # 部件所属子系统 + "syscap": [], # 部件为应用提供的系统能力 + "features": [], # 部件对外的可配置特性列表,一般与build中的sub_component对应,可供产品配置 + "adapted_system_type": [], # 轻量(mini)小型(small)和标准(standard),可以是多个 + "rom": "92KB", # 部件ROM值 + "ram": "~200KB", # 部件RAM估值 + "deps": { + "components": [ # 部件依赖的其他部件 + "samgr_lite", + "ipc_lite" + ], + "third_party": [ # 部件依赖的三方开源软件 + "bounds_checking_function" + ] + } + "build": { # 编译相关配置 + "sub_component": [ + ""//base/sensors/sensor_lite/services:sensor_service"", # 部件编译入口 + ], # 部件编译入口,模块在此处配置 + "inner_kits": [], # 部件间接口 + "test": [] # 部件测试用例编译入口 + } + } + } +``` + +> ![icon-note.gif](public_sys-resources/icon-note.gif)**注意**:lite上旧的部件在build/lite/components目录下对应子系统的json文件中,路径规则为:**{领域}/{子系统}/{部件}**,部件目录树规则如下: + +```shell +component +├── interfaces +│ ├── innerkits # 系统内接口,部件间使用 +│ └── kits # 应用接口,应用开发者使用 +├── frameworks # framework实现 +├── services # service实现 +└── BUILD.gn # 部件编译脚本 +``` + +部件配置中需要配置部件的名称、源码路径、功能简介、是否必选、编译目标、RAM、ROM、编译输出、已适配的内核、可配置的特性和依赖等属性定义。 + +新增部件时需要在对应子系统json文件中添加相应的部件定义。产品所配置的部件必须在某个子系统中被定义过,否则会校验失败。 + +### 新增并编译部件 + +1. 添加部件。 本节以添加一个自定义的部件为例,描述如何编译部件,编译库、编译可执行文件等。 + + 示例部件partA由feature1、feature2和feature3组成,feature1的编译目标为一个动态库,feature2的目标为一个可执行程序,feature3的目标为一个etc配置文件。 + + 示例部件partA的配置需要添加到一个子系统中,本次示例将添加到subsystem_examples子系统中(subsystem_examples子系统定义在test/examples/目录)。 + + 示例部件partA的完整目录结构如下: + + ```shell + test/examples/partA + ├── feature1 + │ ├── BUILD.gn + │ ├── include + │ │ └── helloworld1.h + │ └── src + │ └── helloworld1.cpp + ├── feature2 + │ ├── BUILD.gn + │ ├── include + │ │ └── helloworld2.h + │ └── src + │ └── helloworld2.cpp + └── feature3 + ├── BUILD.gn + └── src + └── config.conf + ``` + + 示例1:编写动态库gn脚本test/examples/partA/feature1/BUILD.gn,示例如下: + + ```shell + config("helloworld_lib_config") { + include_dirs = [ "include" ] + } + + ohos_shared_library("helloworld_lib") { + sources = [ + "include/helloworld1.h", + "src/helloworld1.cpp", + ] + public_configs = [ ":helloworld_lib_config" ] + part_name = "partA" + } + ``` + + 示例2:编写可执行文件gn脚本test/examples/partA/feature2/BUILD.gn,示例如下: + + ```shell + ohos_executable("helloworld_bin") { + sources = [ + "src/helloworld2.cpp" + ] + include_dirs = [ "include" ] + deps = [ # 依赖部件内模块 + "../feature1:helloworld_lib" + ] + external_deps = [ "partB:module1" ] # (可选)如果有跨部件的依赖,格式为“部件名:模块名” + install_enable = true # 可执行程序缺省不安装,需要安装时需要指定 + part_name = "partA" + } + ``` + + 示例3:编写etc模块gn脚本test/examples/partA/feature3/BUILD.gn,示例如下: + + ```shell + ohos_prebuilt_etc("feature3_etc") { + source = "src/config.conf" + relative_install_dir = "init" #可选,模块安装相对路径,相对于默认安装路径;默认在/system/etc目录 + part_name = "partA" + } + ``` + + 示例4:在部件的bundle.json中添加模块配置:test/examples/bundle.json。每个部件都有一个bundle.json配置文件,在部件的根目录下。示例见:[部件的bundle.json](subsys-build-component.md#部件配置规则) + +2. 将部件添加到产品配置中。 在产品的配置中添加部件,产品对应的配置文件://vendor/{product_company}/{product-name}/config.json。 + + 在产品配置文件中添加 "subsystem_examples:partA",表示该产品中会编译并打包partA到版本中。 + +3. 编译。 主要有两种编译方式,[命令行方式和hb方式](subsys-build-all.md#编译命令),下面以命令行方式为例: + + 部件可以使用"--build-target 部件名"进行单独编译,以编译产品hispark_taurus_standard的musl部件为例,编译命令如下: + + ``` + ./build.sh --product-name hispark_taurus_standard --build-target musl --ccache + ``` + + 也可以编译相应产品,以编译hispark_taurus_standard为例,编译命令如下: + + ```shell + ./build.sh --product-name hispark_taurus_standard --ccache + ``` + +4. 编译输出。 编译所生成的文件都归档在out/hispark_taurus/目录下,结果镜像输出在 out/hispark_taurus/packages/phone/images/ 目录下。 \ No newline at end of file diff --git a/zh-cn/device-dev/subsystems/subsys-build-feature.md b/zh-cn/device-dev/subsystems/subsys-build-feature.md new file mode 100644 index 0000000000..51794dd344 --- /dev/null +++ b/zh-cn/device-dev/subsystems/subsys-build-feature.md @@ -0,0 +1,70 @@ +# 特性 +### 特性配置规则 + +下面介绍feature的声明、定义以及使用方法。 + +- feature的声明 + + 在部件的bundle.json文件中通过feature_list来声明部件的feature列表,每个feature都必须以"**{部件名}**"开头。示例如下: + + ``` + { + "name": "@ohos/xxx", + "component": { + "name": "partName", + "subsystem": "subsystemName", + "features": [ + "{partName}_feature_A" + ] + } + } + ``` + + features中可以为部件声明多个feature。 + +- feature的定义 + + 在部件内可通过以下方式定义feature的默认值: + + ``` + declare_args() { + {partName}_feature_A = true + } + ``` + + 该值是此部件的默认值,产品可以在部件列表中重载该feature的值。 + + feature需给部件内多个模块使用时,建议把feature定义在部件的全局gni文件中,各个模块的BUILD.gn中import该gni文件。 + +- feature的使用 + + BUILD.gn文件中可通过以下方式进行根据feature决定部分代码或模块参与编译: + + ``` + if ({partName}_feature_A) { + sources += [ "xxx.c" ] + } + + # 某个特性引入的依赖,需要通过该feature进行隔离 + if ({partName}_feature_A) { + deps += [ "xxx" ] + external_deps += [ "xxx" ] + } + + # bundle.json中不支持if判断,如果bundle.json中包含的sub_component需要被裁减,可以定义group进行裁减判断 + group("testGroup") { + deps = [] + if ({partName}_feature_A) { + deps += [ "xxx" ] + } + } + ``` + + 也可以通过以下方式为模块定义代码宏进行代码级差异化配置: + + ``` + if ({partName}_feature_A) { + defines += ["FEATUREA_DEFINE"] + } + ``` + diff --git a/zh-cn/device-dev/subsystems/subsys-build-gn-coding-style-and-best-practice.md b/zh-cn/device-dev/subsystems/subsys-build-gn-coding-style-and-best-practice.md index d93ffb34a8..06637998b5 100644 --- a/zh-cn/device-dev/subsystems/subsys-build-gn-coding-style-and-best-practice.md +++ b/zh-cn/device-dev/subsystems/subsys-build-gn-coding-style-and-best-practice.md @@ -1,513 +1,513 @@ -# 构建系统编码规范与最佳实践 - -## 概述 - -gn是generate ninja的缩写,它是一个元编译系统(meta-build system),是ninja的前端,gn和ninja结合起来,完成OpenHarmony操作系统的编译任务。 - -### gn简介 - -- 目前采用gn的大型软件系统有:Chromium,Fuchsia和OpenHarmony。 -- gn语法自设计之初就自带局限性,比如不能求list的长度,不支持通配符等。这些局限性源于其 **有所为有所不为** 的设计哲学,见https://gn.googlesource.com/gn/+/main/docs/language.md#Design-philosophy。 所以在使用gn的过程中,如果发现某件事情用gn实现起来很复杂,请先停下来思考这件事情是否真的需要做。 -- 关于gn的更多详情见gn官方文档,见https://gn.googlesource.com/gn/+/main/docs/。 - -### 本文的目标读者和覆盖范围 - -目标读者为OpenHarmony的开发者。本文主要讨论gn的编码风格和使用gn过程中容易出现的问题,不讨论gn的语法,如需了解gn基础知识,见gn reference文档,见https://gn.googlesource.com/gn/+/main/docs/reference.md。 - -### 总体原则 - -在保证功能可用的前提下,脚本需要满足易于阅读,便于维护,良好的扩展性和性能等要求。 - -## 代码风格 - -### 命名 - -总体上遵循Linux kernel的命名风格,即**小写字母+下划线**的命名风格。 - -#### 局部变量 - -我们这里对局部变量的定义为:在某作用域内,且不向下传递的变量。 - -为了更好的区别于全局变量,局部变量统一采用**下划线开头**。 - -``` -# 例1 -action("some_action") { - ... - # _output是个局部变量,所以使用下划线开头 - _output = "${target_out_dir}/${target_name}.out" - outputs = [ _output ] - args = [ - ... - "--output", - rebase_path(_output, root_build_dir), - ... - ] - ... -} -``` - -#### 全局变量 - -全局变量使用**小写字母**开头。 - -如果变量值可以被gn args修改,则需要使用declare_args来声明,否则不要使用declare_args。 - -``` -# 例2 -declare_args() { - # 可以通过gn args来修改some_feature的值 - some_feature = false -} -``` - -#### 目标命名 - -目标命名采用**小写字母+下划线**的命名方式。 - -模板中的**子目标**命名方式采用"${target_name}+双下划线+后缀"的命名方式。这样做有两点好处: - -- 加入"${target_name}"可以防止子目标重名。 - -- 加入双下划线可以很方便地区分出子目标属于哪一个模块,方便在出现问题时快速定位。 - - ``` - # 例3 - template("ohos_shared_library") { - # "{target_name}"(主目标名)+"__"(双下划线)+"notice"(后缀) - _notice_target = "${target_name}__notice" - collect_notice(_notice_target) { - ... - } - shared_library(target_name) { - ... - } - } - ``` - -#### 自定义模板的命名 - -推荐采用**动宾短语**的形式来命名。 - -``` -# 例4 -# Good -template("compile_resources") { - ... -} -``` - -### 格式化 - -gn脚本在提交之前需要执行格式化。格式化可以保证代码对齐,换行等风格的统一。使用gn自带的format工具即可。命令如下: - -```shell -$ gn format path-to-BUILD.gn -``` - -gn format会按照字母序对import文件做排序,如果想保证import的顺序,可以添加空注释行。 - -假设原来的import顺序为: - -``` -# 例5 -import("//b.gni") -import("//a.gni") -``` - -经过format之后变为: - -``` -import("//a.gni") -import("//b.gni") -``` - -如果想保证原有的import顺序,可以添加空注释行。 - -``` -import("//b.gni") -# Comment to keep import order -import("//a.gni") -``` - -## 编码实践 - -### 实践原则 - -编译脚本实质上完成了两件工作: - -1. **描述模块之间依赖关系(deps)** - - 实践过程中,最常出现的问题是**依赖关系缺失**。 - -2. **描述模块编译的规则(rule)** - - 实践过程中,容易出现的问题是**输入和输出不明确**。 - -依赖缺失会导致两个问题: - -- **概率性编译错误** - - ``` - # 例6 - # 依赖关系缺失,导致概率性编译出错 - shared_library("a") { - ... - } - shared_library("b") { - ... - ldflags = [ "-la" ] - deps = [] - ... - } - group("images") { - deps = [ ":b" ] - } - ``` - - 上面的例子中,libb.so在链接的时候会链接liba.so,实质上构成b依赖a,但是b的依赖列表(deps)却没有声明对a的依赖。由于编译是并发执行的,如果libb.so在链接的时候liba.so还没有编译出来,就会出现编译错误。 - - 由于liba.so也有可能在libb.so之前编译出来,所以依赖缺失导致的编译错误是概率性的。 - -- **依赖关系缺失导致模块没有参与编译** - - 还是上面的例子,如果我们指定ninja编译目标为images,由于images仅仅依赖b,所以a不会参与编译。由于b实质上依赖a, 这时b在链接时会出现必现错误。 - -有一种不太常见的问题是**过多的依赖**。**过多的依赖会降低并发,导致编译变慢**。见下面的例子: - -_compile_js_target不需要依赖 _compile_resource_target,增加这层依赖,会导致 _compile_js_target在 _compile_resource_target编译完成之后才能开始编译。 - -``` -# 例7 -# 过多的依赖导致编译变慢 -template("too_much_deps") { - ... - _gen_resource_target = "${target_name}__res" - action(_gen_resource_target) { - ... - } - - _compile_resource_target = "${target_name}__compile_res" - action(_compile_resource_target) { - deps = [":$_gen_resource_target"] - ... - } - - _compile_js_target = "${target_name}__js" - action(_compile_js_target) { - # 这个deps不需要 - deps = [":$_compile_resource_target"] - } -} -``` - -输入不明确会导致: - -- **代码修改了,但增量编译时却没有参与编译。** -- **当使用缓存时,代码发生变化,但是缓存仍然命中。** - -下面的例子中,foo.py引用了bar.py中的函数。bar.py实质上是foo.py的输入,需要将bar.py添加到implict_input_action的input或者depfile中去。否则,修改bar.py,模块implict_input_action将不会重新编译。 - -``` -# 例8 -action("implict_input_action") { - script = "//path-to-foo.py" - ... -} -``` - -``` -#!/usr/bin/env -# Contents of foo.py -import bar -... -bar.some_function() -... -``` - -输出不明确会导致: - -- **隐式的输出** -- **当使用缓存时,隐式输出无法从缓存中获得** - -下面的例子中,foo.py会生成两个文件,a.out和b.out,但是implict_output_action的输出只声明了a.out。这种情况下,b.out实质上就是一个隐式输出。缓存中只会存储a.out,不会存储b.out,当缓存命中时,b.out就编译不出来了。 - -``` -# 例9 -action("implict_output_action") { - outputs = ["${target_out_dir}/a.out"] - script = "//path-to-foo.py" - ... -} -``` - -``` -#!/usr/bin/env -# Contents of foo.py -... -write_file("b.out") -write_file("a.out") -... -``` - -### 模板 - -**不要使用gn的原生模板,使用编译系统提供的模板** - -所谓gn原生模板,是指source_set,shared_library, static_library, action, executable,group这六个模板。 - -不推荐使用原生模板的原因有二: - -- **原生模板是最小功能模板**,无法提供external_deps的解析,notice收集,安装信息生成等的额外功能,这些额外功能最好是随着模块编译时同时生成,所以必须对原生模板做额外的扩展才能满足实际的需求。 - -- 当输入文件依赖的文件发生变化时,gn原生的action模板不能自动感知不到这种编译,无法重新编译。见例8 - - 原生模板和编译系统提供的模板之间的对应关系: - -| 编译系统提供的模板 | 原生模板 | -|:------------------- | -------------- | -| ohos_shared_library | shared_library | -| ohos_source_set | source_set | -| ohos_executable | executable | -| ohos_static_library | static_library | -| action_with_pydeps | action | -| ohos_group | group | - -### 使用python脚本 - -action中的script推荐使用python脚本,不推荐使用shell脚本。相比于shell脚本,python脚本: - -- python语法友好,不会因为少写一个空格就导致奇怪的错误。 -- python脚本有很强的可读性。 -- 可维护性强,可调试。 -- OpenHarmony对python任务做了缓存,可以加快编译速度。 - -### rebase_path - -- 仅在向action的参数列表中(args)调用rebase_path。 - - ``` - # 例10 - template("foo") { - action(target_name) { - ... - args = [ - # 仅在args中调用rebase_path - "--bar=" + rebase_path(invoker.bar, root_build_dir), - ... - ] - ... - } - } - - foo("good") { - bar = something - ... - } - ``` - -- 同一变量做两次rebase_path会出现意想不到的结果。 - - ``` - # 例11 - template("foo") { - action(target_name) { - ... - args = [ - # bar被执行了两次rebase_path, 传递的bar的值已经不对了 - "--bar=" + rebase_path(invoker.bar, root_build_dir), - ... - ] - ... - } - } - - foo("bad") { - # 不要在这里调用rebase_path - bar = rebase_path(some_value,root_build_dir) - ... - } - ``` - -### 模块间数据分享 - -模块间数据分享是很常见的事情,比如A模块想要知道B模块的输出和deps。 - -- 同一BUILD.gn之间数据分享 - - 同一BUILD.gn之间数据可以通过定义全局变量的方式来共享。 - - 下面的例子中,模块a的输出是模块b的输入,可以通过定义全局变量的方式来共享给b - - ``` - # 例12 - _output_a = get_label_info(":a", "out_dir") + "/a.out" - action("a") { - outputs = _output_a - ... - } - action("b") { - inputs = [_output_a] - ... - } - ``` - -- 不同BUILD.gn之间数据分享 - - 不同BUILD.gn之间传递数据,最好的办法是将需要共享的数据保存成文件,然后不同模块之间通过文件来传递和共享数据。这种场景比较复杂,读者可以参照OpenHarmony的hap编译过程的write_meta_data。 - -### forward_variable_from - -- 自定义模板需要首先将testonly传递(forward)进来。因为该模板的target有可能被testonly的目标依赖。 - - ``` - # 例13 - # 自定义模板首先要传递testonly - template("foo") { - forward_variable_from(invoker, ["testonly"]) - ... - } - ``` - -- 不推荐使用*来forward变量,需要的变量应该**显式地,一个一个地**被forward进来。 - - ``` - # 例14 - # Bad,使用*forward变量 - template("foo") { - forward_variable_from(invoker, "*") - ... - } - - # Good, 显式地,一个一个地forward变量 - template("bar") { - # - forward_variable_from(invoker, [ - "testonly", - "deps", - ... - ]) - ... - } - ``` - -### target_name - -target_name会随着作用域变化而变化,使用时需要注意。 - -``` -# 例15 -# target_name会随着作用域变化而变化 -template("foo") { - # 此时打印出来的target_name为"${target_name}" - print(target_name) - _code_gen_target = "${target_name}__gen" - code_gen(_code_gen_target) { - # 此时打印出来的target_name为"${target_name}__gen" - print(target_name) - ... - } - _compile_gen_target = "${target_name}__compile" - compile(_compile_gen_target) { - # 此时打印出来的target_name为"${target_name}__compile" - print(target_name) - ... - } - ... -} -``` - -### public_configs - -如果模块需要向外export头文件,请使用public_configs。 - -``` -# 例16 -# b依赖a,会同时继承a的headers -config("headers") { - include_dirs = ["//path-to-headers"] - ... -} -shared_library("a") { - public_configs = [":headers"] - ... -} -executable("b") { - deps = [":a"] - ... -} -``` - -### template - -自定义模板中必须有一个子目标的名字是target_name。该子目标会作为template的主目标。其他子目标都应该被主目标依赖,否则子目标不会被编译。 - -``` -# 例17 -# 自定义模板中必须有一个子目标的名字是target_name -template("foo") { - _code_gen_target = "${target_name}__gen" - code_gen(_code_gen_target) { - ... - } - _compile_gen_target = "${target_name}__compile" - compile(_compile_gen_target) { - # 此时打印出来的target_name为"${target_name}__compile" - print(target_name) - ... - } - ... - group(target_name) { - deps = [ - # 由于_compile_gen_target依赖了_code_gen_target,所以主目标只需要依赖_compile_gen_target即可。 - ":$_compile_gen_target" - ] - } -} -``` - -### set_source_assignment_filter - -set_source_assignment_filter除了可以过滤sources,还可以用来过滤其他变量。过滤完成后记得将过滤器和sources置空。 - -``` -# 例18 -# 使用set_source_assignment_filter过滤依赖, 挑选label符合*:*_res的添加到依赖列表中 -_deps = [] -foreach(_possible_dep, invoker.deps) { - set_source_assignment_filter(["*:*_res"]) - _label = get_label_info(_possible_dep, "label_no_toolchain") - sources = [] - sources = [ _label ] - if (sources = []) { - _deps += _sources - } -} -sources = [] -set_source_assignment_filter([]) -``` - -最新版本上set_source_assignment_filter被filter_include和filter_exclude取代。 - -### 部件内依赖采用deps,跨部件依赖采用external_deps - -- 部件在OpenHarmony上指能提供某个能力的一组模块。 - -- 在模块定义的时候可以声明part_name,用来表明当前模块属于哪个部件。 - -- 每个部件会声明其inner-kit,供其他部件调用。部件innerkit的声明见源码中的bundle.json。 - -- 部件间依赖只能依赖innerkit,不能依赖非innerkit的模块。 - -- 如果a模块和b模块的part_name相同,那么a、b模块属于同一个部件,a,b模块之间的依赖关系可以用deps来声明。 - -- 如果a、b模块的part_name不同,那么a、b模块不属于同一个部件,a、b模块之间的依赖关系需要通过external_deps来声明,依赖方式为"部件名:模块名"的方式。见例19。 - - ``` - # 例19 - shared_library("a") { - ... - external_deps = ["part_name_of_b:b"] - ... - } - ``` +# 构建系统编码规范与最佳实践 + +## 概述 + +gn是generate ninja的缩写,它是一个元编译系统(meta-build system),是ninja的前端,gn和ninja结合起来,完成OpenHarmony操作系统的编译任务。 + +### gn简介 + +- 目前采用gn的大型软件系统有:Chromium,Fuchsia和OpenHarmony。 +- gn语法自设计之初就自带局限性,比如不能求list的长度,不支持通配符等。这些局限性源于其 **有所为有所不为** 的[设计哲学](https://gn.googlesource.com/gn/+/main/docs/language.md#Design-philosophy)。 所以在使用gn的过程中,如果发现某件事情用gn实现起来很复杂,请先停下来思考这件事情是否真的需要做。 +- 关于gn的更多详情见[gn官方文档](https://gn.googlesource.com/gn/+/main/docs/)。 + +### 本文的目标读者和覆盖范围 + +目标读者为OpenHarmony的开发者。本文主要讨论gn的编码风格和使用gn过程中容易出现的问题,不讨论gn的语法,如需了解gn基础知识,见[gn reference文档](https://gn.googlesource.com/gn/+/main/docs/reference.md)。 + +### 总体原则 + +在保证功能可用的前提下,脚本需要满足易于阅读,便于维护,良好的扩展性和性能等要求。 + +## 代码风格 + +### 命名 + +总体上遵循Linux kernel的命名风格,即**小写字母+下划线**的命名风格。 + +#### 局部变量 + +我们这里对局部变量的定义为:在某作用域内,且不向下传递的变量。 + +为了更好的区别于全局变量,局部变量统一采用**下划线开头**。 + +```shell +# 例1 +action("some_action") { + ... + # _output是个局部变量,所以使用下划线开头 + _output = "${target_out_dir}/${target_name}.out" + outputs = [ _output ] + args = [ + ... + "--output", + rebase_path(_output, root_build_dir), + ... + ] + ... +} +``` + +#### 全局变量 + +全局变量使用**小写字母**开头。 + +如果变量值可以被gn args修改,则需要使用declare_args来声明,否则不要使用declare_args。 + +```shell +# 例2 +declare_args() { + # 可以通过gn args来修改some_feature的值 + some_feature = false +} +``` + +#### 目标命名 + +目标命名采用**小写字母+下划线**的命名方式。 + +模板中的**子目标**命名方式采用"${target_name}+双下划线+后缀"的命名方式。这样做有两点好处: + +- 加入"${target_name}"可以防止子目标重名。 + +- 加入双下划线可以很方便地区分出子目标属于哪一个模块,方便在出现问题时快速定位。 + + ```shell + # 例3 + template("ohos_shared_library") { + # "{target_name}"(主目标名)+"__"(双下划线)+"notice"(后缀) + _notice_target = "${target_name}__notice" + collect_notice(_notice_target) { + ... + } + shared_library(target_name) { + ... + } + } + ``` + +#### 自定义模板的命名 + +推荐采用**动宾短语**的形式来命名。 + +```shell +# 例4 +# Good +template("compile_resources") { + ... +} +``` + +### 格式化 + +gn脚本在提交之前需要执行格式化。格式化可以保证代码对齐,换行等风格的统一。使用gn自带的format工具即可。命令如下: + +```shell +$ gn format path-to-BUILD.gn +``` + +gn format会按照字母序对import文件做排序,如果想保证import的顺序,可以添加空注释行。 + +假设原来的import顺序为: + +```shell +# 例5 +import("//b.gni") +import("//a.gni") +``` + +经过format之后变为: + +```shell +import("//a.gni") +import("//b.gni") +``` + +如果想保证原有的import顺序,可以添加空注释行。 + +```shell +import("//b.gni") +# Comment to keep import order +import("//a.gni") +``` + +## 编码实践 + +### 实践原则 + +编译脚本实质上完成了两件工作: + +1. **描述模块之间依赖关系(deps)** + + 实践过程中,最常出现的问题是**依赖关系缺失**。 + +2. **描述模块编译的规则(rule)** + + 实践过程中,容易出现的问题是**输入和输出不明确**。 + +依赖缺失会导致两个问题: + +- **概率性编译错误** + + ```shell + # 例6 + # 依赖关系缺失,导致概率性编译出错 + shared_library("a") { + ... + } + shared_library("b") { + ... + ldflags = [ "-la" ] + deps = [] + ... + } + group("images") { + deps = [ ":b" ] + } + ``` + + 上面的例子中,libb.so在链接的时候会链接liba.so,实质上构成b依赖a,但是b的依赖列表(deps)却没有声明对a的依赖。由于编译是并发执行的,如果libb.so在链接的时候liba.so还没有编译出来,就会出现编译错误。 + + 由于liba.so也有可能在libb.so之前编译出来,所以依赖缺失导致的编译错误是概率性的。 + +- **依赖关系缺失导致模块没有参与编译** + + 还是上面的例子,如果我们指定ninja编译目标为images,由于images仅仅依赖b,所以a不会参与编译。由于b实质上依赖a, 这时b在链接时会出现必现错误。 + +有一种不太常见的问题是**过多的依赖**。**过多的依赖会降低并发,导致编译变慢**。见下面的例子: + +_compile_js_target不需要依赖 _compile_resource_target,增加这层依赖,会导致 _compile_js_target在 _compile_resource_target编译完成之后才能开始编译。 + +```shell +# 例7 +# 过多的依赖导致编译变慢 +template("too_much_deps") { + ... + _gen_resource_target = "${target_name}__res" + action(_gen_resource_target) { + ... + } + + _compile_resource_target = "${target_name}__compile_res" + action(_compile_resource_target) { + deps = [":$_gen_resource_target"] + ... + } + + _compile_js_target = "${target_name}__js" + action(_compile_js_target) { + # 这个deps不需要 + deps = [":$_compile_resource_target"] + } +} +``` + +输入不明确会导致: + +- **代码修改了,但增量编译时却没有参与编译。** +- **当使用缓存时,代码发生变化,但是缓存仍然命中。** + +下面的例子中,foo.py引用了bar.py中的函数。bar.py实质上是foo.py的输入,需要将bar.py添加到implict_input_action的input或者depfile中去。否则,修改bar.py,模块implict_input_action将不会重新编译。 + +```shell +# 例8 +action("implict_input_action") { + script = "//path-to-foo.py" + ... +} +``` + +```shell +#!/usr/bin/env +# Contents of foo.py +import bar +... +bar.some_function() +... +``` + +输出不明确会导致: + +- **隐式的输出** +- **当使用缓存时,隐式输出无法从缓存中获得** + +下面的例子中,foo.py会生成两个文件,a.out和b.out,但是implict_output_action的输出只声明了a.out。这种情况下,b.out实质上就是一个隐式输出。缓存中只会存储a.out,不会存储b.out,当缓存命中时,b.out就编译不出来了。 + +```shell +# 例9 +action("implict_output_action") { + outputs = ["${target_out_dir}/a.out"] + script = "//path-to-foo.py" + ... +} +``` + +```shell +#!/usr/bin/env +# Contents of foo.py +... +write_file("b.out") +write_file("a.out") +... +``` + +### 模板 + +**不要使用gn的原生模板,使用编译子系统提供的模板** + +所谓gn原生模板,是指source_set,shared_library, static_library, action, executable,group这六个模板。 + +不推荐使用原生模板的原因有二: + +- **原生模板是最小功能模板**,无法提供external_deps的解析,notice收集,安装信息生成等的额外功能,这些额外功能最好是随着模块编译时同时生成,所以必须对原生模板做额外的扩展才能满足实际的需求。 + +- 当输入文件依赖的文件发生变化时,gn原生的action模板不能自动感知不到这种编译,无法重新编译。见例8 + + 原生模板和编译子系统提供的模板之间的对应关系: + +| 编译子系统提供的模板 | 原生模板 | +| :------------------ | -------------- | +| ohos_shared_library | shared_library | +| ohos_source_set | source_set | +| ohos_executable | executable | +| ohos_static_library | static_library | +| action_with_pydeps | action | +| ohos_group | group | + +### 使用python脚本 + +action中的script推荐使用python脚本,不推荐使用shell脚本。相比于shell脚本,python脚本: + +- python语法友好,不会因为少写一个空格就导致奇怪的错误。 +- python脚本有很强的可读性。 +- 可维护性强,可调试。 +- OpenHarmony对python任务做了缓存,可以加快编译速度。 + +### rebase_path + +- 仅在向action的参数列表中(args)调用rebase_path。 + + ```shell + # 例10 + template("foo") { + action(target_name) { + ... + args = [ + # 仅在args中调用rebase_path + "--bar=" + rebase_path(invoker.bar, root_build_dir), + ... + ] + ... + } + } + + foo("good") { + bar = something + ... + } + ``` + +- 同一变量做两次rebase_path会出现意想不到的结果。 + + ```shell + # 例11 + template("foo") { + action(target_name) { + ... + args = [ + # bar被执行了两次rebase_path, 传递的bar的值已经不对了 + "--bar=" + rebase_path(invoker.bar, root_build_dir), + ... + ] + ... + } + } + + foo("bad") { + # 不要在这里调用rebase_path + bar = rebase_path(some_value,root_build_dir) + ... + } + ``` + +### 模块间数据分享 + +模块间数据分享是很常见的事情,比如A模块想要知道B模块的输出和deps。 + +- 同一BUILD.gn之间数据分享 + + 同一BUILD.gn之间数据可以通过定义全局变量的方式来共享。 + + 下面的例子中,模块a的输出是模块b的输入,可以通过定义全局变量的方式来共享给b + + ```shell + # 例12 + _output_a = get_label_info(":a", "out_dir") + "/a.out" + action("a") { + outputs = _output_a + ... + } + action("b") { + inputs = [_output_a] + ... + } + ``` + +- 不同BUILD.gn之间数据分享 + + 不同BUILD.gn之间传递数据,最好的办法是将需要共享的数据保存成文件,然后不同模块之间通过文件来传递和共享数据。这种场景比较复杂,读者可以参照OpenHarmony的hap编译过程的write_meta_data。 + +### forward_variable_from + +- 自定义模板需要首先将testonly传递(forward)进来。因为该模板的target有可能被testonly的目标依赖。 + + ```shell + # 例13 + # 自定义模板首先要传递testonly + template("foo") { + forward_variable_from(invoker, ["testonly"]) + ... + } + ``` + +- 不推荐使用*来forward变量,需要的变量应该**显式地,一个一个地**被forward进来。 + + ```shell + # 例14 + # Bad,使用*forward变量 + template("foo") { + forward_variable_from(invoker, "*") + ... + } + + # Good, 显式地,一个一个地forward变量 + template("bar") { + # + forward_variable_from(invoker, [ + "testonly", + "deps", + ... + ]) + ... + } + ``` + +### target_name + +target_name会随着作用域变化而变化,使用时需要注意。 + +```shell +# 例15 +# target_name会随着作用域变化而变化 +template("foo") { + # 此时打印出来的target_name为"${target_name}" + print(target_name) + _code_gen_target = "${target_name}__gen" + code_gen(_code_gen_target) { + # 此时打印出来的target_name为"${target_name}__gen" + print(target_name) + ... + } + _compile_gen_target = "${target_name}__compile" + compile(_compile_gen_target) { + # 此时打印出来的target_name为"${target_name}__compile" + print(target_name) + ... + } + ... +} +``` + +### public_configs + +如果模块需要向外export头文件,请使用public_configs。 + +```shell +# 例16 +# b依赖a,会同时继承a的headers +config("headers") { + include_dirs = ["//path-to-headers"] + ... +} +shared_library("a") { + public_configs = [":headers"] + ... +} +executable("b") { + deps = [":a"] + ... +} +``` + +### template + +自定义模板中必须有一个子目标的名字是target_name。该子目标会作为template的主目标。其他子目标都应该被主目标依赖,否则子目标不会被编译。 + +```shell +# 例17 +# 自定义模板中必须有一个子目标的名字是target_name +template("foo") { + _code_gen_target = "${target_name}__gen" + code_gen(_code_gen_target) { + ... + } + _compile_gen_target = "${target_name}__compile" + compile(_compile_gen_target) { + # 此时打印出来的target_name为"${target_name}__compile" + print(target_name) + ... + } + ... + group(target_name) { + deps = [ + # 由于_compile_gen_target依赖了_code_gen_target,所以主目标只需要依赖_compile_gen_target即可。 + ":$_compile_gen_target" + ] + } +} +``` + +### set_source_assignment_filter + +set_source_assignment_filter除了可以过滤sources,还可以用来过滤其他变量。过滤完成后记得将过滤器和sources置空。 + +```shell +# 例18 +# 使用set_source_assignment_filter过滤依赖, 挑选label符合*:*_res的添加到依赖列表中 +_deps = [] +foreach(_possible_dep, invoker.deps) { + set_source_assignment_filter(["*:*_res"]) + _label = get_label_info(_possible_dep, "label_no_toolchain") + sources = [] + sources = [ _label ] + if (sources = []) { + _deps += _sources + } +} +sources = [] +set_source_assignment_filter([]) +``` + +最新版本上set_source_assignment_filter被filter_include和filter_exclude取代。 + +### 部件内依赖采用deps,跨部件依赖采用external_deps + +- 部件在OpenHarmony上指能提供某个能力的一组模块。 + +- 在模块定义的时候可以声明part_name,用来表明当前模块属于哪个部件。 + +- 每个部件会声明其inner_kits,供其他部件调用。部件inner_kits的声明见源码中的bundle.json。 + +- 部件间依赖只能依赖inner_kits,不能依赖非inner_kits的模块。 + +- 如果a模块和b模块的part_name相同,那么a、b模块属于同一个部件,a,b模块之间的依赖关系可以用deps来声明。 + +- 如果a、b模块的part_name不同,那么a、b模块不属于同一个部件,a、b模块之间的依赖关系需要通过external_deps来声明,依赖方式为"部件名:模块名"的方式。见例19。 + + ```shell + # 例19 + shared_library("a") { + ... + external_deps = ["part_name_of_b:b"] + ... + } + ``` \ No newline at end of file diff --git a/zh-cn/device-dev/subsystems/subsys-build-gn-hap-compilation-guide.md b/zh-cn/device-dev/subsystems/subsys-build-gn-hap-compilation-guide.md index 5a01b95c68..dd3fcbf4a7 100644 --- a/zh-cn/device-dev/subsystems/subsys-build-gn-hap-compilation-guide.md +++ b/zh-cn/device-dev/subsystems/subsys-build-gn-hap-compilation-guide.md @@ -17,7 +17,7 @@ ## 开发指导 -### 编译系统提供的模板 +### 编译子系统提供的模板 #### ohos_hap 声明一个HAP目标,该目标会生成一个HAP,最终将会打包到system镜像中。 diff --git a/zh-cn/device-dev/subsystems/subsys-build-mini-lite.md b/zh-cn/device-dev/subsystems/subsys-build-mini-lite.md deleted file mode 100644 index a8cda2618b..0000000000 --- a/zh-cn/device-dev/subsystems/subsys-build-mini-lite.md +++ /dev/null @@ -1,949 +0,0 @@ -# 轻量和小型系统编译构建指导 - -## 概述 - - 一个基于gn和ninja的构建系统,以支持OpenHarmony部件化开发为目标,提供以下基本功能: - -- 支持按部件拼装产品并编译。 - -- 独立构建芯片解决方案厂商源码。 - -- 独立构建单个部件。 - -### 基本概念 - -在使用编译构建子系统前,应了解如下基本概念: - -- 子系统 - 子系统是一个逻辑概念,它由一个或多个具体的部件组成。OpenHarmony整体遵从分层设计,从下向上依次为:内核层、系统服务层、框架层和应用层。系统功能按照“系统 > 子系统 > 部件”逐级展开,在多设备部署场景下,支持根据实际需求裁剪某些非必要的子系统或部件。 - -- 部件 - 系统最小的可复用、可配置、可裁剪的功能单元。部件具备目录独立可并行开发、可独立编译、可独立测试的特征。 - -- gn - Generate ninja的缩写,用于产生ninja文件。 - -- ninja - ninja是一个专注于速度的小型构建系统。 - -- hb - OpenHarmony的命令行工具,用来执行编译命令。 - -### 目录结构 - -``` -build/lite -├── components # 部件描述文件 -├── figures # readme中的图片 -├── hb # hb pip安装包源码 -├── make_rootfs # 文件系统镜像制作脚本 -├── config # 编译配置项 -│ ├── component # 部件相关的模板定义 -│ ├── kernel # 内核相关的编译配置 -│ └── subsystem # 子系统编译配置 -├── platform # ld脚本 -├── testfwk # 测试编译框架 -└── toolchain # 编译工具链配置,包括:编译器路径、编译选项、链接选项等 -``` - -### 构建流程 - -编译构建流程如下图所示,主要分设置和编译两步: - - **图1** 编译构建流程 - - ![zh-cn_image_0000001171796557](figures/zh-cn_image_0000001171796557.jpg) - -1. hb set: 设置OpenHarmony源码目录和要编译的产品。 - -2. hb build: 编译产品、开发板或者部件。编译主要过程如下: - - 1. 读取编译配置:根据产品选择的开发板,读取开发板config.gni文件内容,主要包括编译工具链、编译链接命令和选项等。 - 2. 调用gn:调用gn gen命令,读取产品配置生成产品解决方案out目录和ninja文件。 - 3. 调用ninja:调用ninja -C out/board/product启动编译。 - 4. 系统镜像打包:将部件编译产物打包,设置文件属性和权限,制作文件系统镜像。 - -## 配置规则 - -为了实现芯片解决方案、产品解决方案与OpenHarmony是解耦的、可插拔的,部件、芯片解决方案和产品解决方案的路径、目录树和配置需遵循一定的规则,具体如下: - -### 部件 - - 部件源码路径命名规则为:**{领域}/{子系统}/{部件}**,部件目录树规则如下: - -> ![icon-caution.gif](public_sys-resources/icon-caution.gif) **注意:** -> 部件的名称、源码路径、功能简介、是否必选、编译目标、RAM、ROM、编译输出、已适配的内核、可配置的特性和依赖等属性定义在build/lite/components目录下对应子系统的json文件中,新增部件时需要在对应子系统json文件中添加相应的部件定义。产品所配置的部件必须在某个子系统中被定义过,否则会校验失败。 - -``` -component -├── interfaces -│ ├── innerkits # 系统内接口,部件间使用 -│ └── kits # 应用接口,应用开发者使用 -├── frameworks # framework实现 -├── services # service实现 -└── BUILD.gn # 部件编译脚本 -``` - - 以泛sensor子系统的sensor服务部件为例,部件属性定义描述文件字段说明如下: - - ``` - { - "name": "@ohos/sensor_lite", # HPM部件英文名称,格式"@组织/部件名称" - "description": "Sensor services", # 部件功能一句话描述 - "version": "3.1", # 版本号,版本号与OpenHarmony版本号一致 - "license": "MIT", # 部件License - "publishAs": "code-segment", # HPM包的发布方式,当前默认都为code_segment - "segment": { - "destPath": "" - }, # 发布类型为code_segment时为必填项,定义发布类型code_segment的代码还原路径(源码路径) - "dirs": {"base/sensors/sensor_lite"}, # HPM包的目录结构,字段必填内容可以留空 - "scripts": {}, # HPM包定义需要执行的脚本,字段必填,值非必填 - "licensePath": "COPYING", - "readmePath": { - "en": "README.rst" - }, - "component": { # 部件属性 - "name": "sensor_lite", # 部件名称 - "subsystem": "", # 部件所属子系统 - "syscap": [], # 部件为应用提供的系统能力 - "features": [], # 部件对外的可配置特性列表,一般与build中的sub_component对应,可供产品配置 - "adapted_system_type": [], # 轻量(mini)小型(small)和标准(standard),可以是多个 - "rom": "92KB", # 部件ROM值 - "ram": "~200KB", # 部件RAM估值 - "deps": { - "components": [ # 部件依赖的其他部件 - "samgr_lite" - ], - "third_party": [ # 部件依赖的三方开源软件 - "bounds_checking_function" - ] - } - "build": { # 编译相关配置 - "sub_component": [ - ""//base/sensors/sensor_lite/services:sensor_service"", # 部件编译入口 - ], # 部件编译入口,模块在此处配置 - "inner_kits": [], # 部件间接口 - "test": [] # 部件测试用例编译入口 - } - } - } - ``` - - 部件BUILD.gn的编写建议如下: - -- 编译目标名称与部件一致。 - -- 部件对外可配置的特性变量需声明在该部件BUILD.gn中,特性变量命名规则:ohos_{subsystem}_{component}_{feature}。特性在部件描述中也需要同步定义,在产品配置文件config.json中按需配置。 - -- 宏定义规则:OHOS_{SUBSYSTEM}_{COMPONENT}_{FEATURE} - - > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** - > 部件的编译脚本语言为gn,gn的基本用法请见[gn快速入门](https://gn.googlesource.com/gn/+/master/docs/quick_start.md)。部件即为gn定义的编译目标,可以为静态库、动态库、可执行文件或group。 - - 以图形的UI部件为例,foundation/graphic/ui/BUILD.gn文件如下: - - ``` - # 声明部件可配置的特性 - declare_args() { - enable_ohos_graphic_ui_animator = false # 动效特性开关 - ohos_ohos_graphic_ui_font = "vector" # 可配置的字体类型,vector或者bitmap - } - - # 部件基础功能 - shared_library("base") { - sources = [ - ...... - ] - include_dirs = [ - ...... - ] - } - - # 仅在animator开启时编译 - if(enable_ohos_graphic_ui_animator ) { - shared_library("animator") { - sources = [ - ...... - ] - include_dirs = [ - ...... - ] - deps = [ :base ] - } - } - ...... - # target名称建议与部件名称一致, 部件target类型可以是executable(bin文件),shared_library(动态库.so),static_library(静态库.a),group等等 - executable("ui") { - deps = [ - ":base" - ] - - # animator特性由产品配置 - if(enable_ohos_graphic_ui_animator ) { - deps += [ - "animator" - ] - } - } - ``` - -### 芯片解决方案 - -- 芯片解决方案是指基于某款开发板的完整解决方案,包含驱动、设备侧接口适配、开发板sdk等。 - -- 芯片解决方案是一个特殊的部件,源码路径规则为:**device/{开发板}/{芯片解决方案厂商}**。 - -- 芯片解决方案部件会随产品选择的开发板默认编译。 - -- 芯片解决方案目录树规则如下: - - ``` - device - └── board # 芯片解决方案厂商 - └── company # 开发板名称 - ├── BUILD.gn # 编译脚本 - ├── hals # OS南向接口适配 - ├── linux # 可选,linux内核版本 - │ └── config.gni # linux版本编译配置 - └── liteos_a # 可选,liteos内核版本 - └── config.gni # liteos_a版本编译配置 - ``` - - > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** - > config.gni为开发板编译相关的配置,编译时会采用该配置文件中的参数编译所有OS部件,编译阶段系统全局可见。 - -- config.gni的关键字段介绍如下: - - ``` - kernel_type: 开发板使用的内核类型,例如:“liteos_a”, “liteos_m”, “linux”。 - kernel_version: 开发使用的内核版本,例如:“4.19”。 - board_cpu: 开发板CPU类型,例如:“cortex-a7”, “riscv32”。 - board_arch: 开发芯片arch, 例如: “armv7-a”, “rv32imac”。 - board_toolchain: 开发板自定义的编译工具链名称,例如:“gcc-arm-none-eabi”。若为空,则使用默认为ohos-clang。 - board_toolchain_prefix:编译工具链前缀,例如:“gcc-arm-none-eabi”。 - board_toolchain_type: 编译工具链类型,目前支持gcc和clang。例如:“gcc” ,“clang”。 - board_cflags: 开发板配置的c文件编译选项。 - board_cxx_flags: 开发板配置的cpp文件编译选项。 - board_ld_flags: 开发板配置的链接选项。 - ``` - -### 产品解决方案 - -产品解决方案为基于开发板的完整产品,主要包含产品对OS的适配、部件拼装配置、启动配置和文件系统配置等。产品解决方案的源码路径规则为:**vendor/{产品解决方案厂商}/{产品名称}**_。_产品解决方案也是一个特殊的部件。 - -产品解决方案的目录树规则如下: - -``` -vendor -└── company # 产品解决方案厂商 - ├── product # 产品名称 - │ ├── init_configs - │ │ ├── etc # init进程启动配置(可选,仅linux内核需要) - │ │ └── init.cfg # 系统服务启动配置 - │ ├── hals # 产品解决方案OS适配 - │ ├── BUILD.gn # 产品编译脚本 - │ └── config.json # 产品配置文件 - │ └── fs.yml # 文件系统打包配置 - └── ...... -``` - -> ![icon-caution.gif](public_sys-resources/icon-caution.gif) **注意:** -> **新增产品须按如上的规则创建目录和文件,编译构建系统将按该规则扫描已配置的产品。** - -关键的目录和文件详细介绍如下: - -1. **vendor/company/product/init_configs/etc** - 该文件夹中包含rcS脚本,Sxxx脚本和fstab脚本。init进程在启动系统服务之前执行这些脚本。执行的流程为“rcS->fstab->S00-xxx“。Sxxx脚本中的内容与开发板和产品需要有关,主要包括设备节点的创建、创建目录、扫描设备节点、修改文件权限等等。这些文件在产品编译的BUILD.gn中按需拷贝到产品out目录中,最终打包到rootfs镜像中。 - -2. **vendor/company/product/init_configs/init.cfg** - init进程启动服务的配置文件,当前支持解析的命令有: - - - start: 启动某个服务 - - - mkdir: 创建文件夹 - - - chmod: 修改指定路径/文件的权限 - - - chown: 修改指定路径/文件的属组 - - - mount: 挂载命令 - - 该文件中的各个字段的解释如下: - - ``` - { - "jobs" : [{ # job数组,一个job对应一个命令集合。job的执行顺序:pre-init -> init -> post-init。 - "name" : "pre-init", - "cmds" : [ - "mkdir /storage/data", # 创建目录 - "chmod 0755 /storage/data", # 修改权限,权限值的格式为0xxx, 如0755 - "mkdir /storage/data/log", - "chmod 0755 /storage/data/log", - "chown 4 4 /storage/data/log", # 修改属组,第一个数字为uid, 第二个数字为gid - ...... - "mount vfat /dev/mmcblock0 /sdcard rw,umask=000" # 挂载,格式为: mount [文件系统类型] [source] [target] [flags] [data] - # 其中flags仅支持:nodev、noexec、nosuid和rdonly - ] - }, { - "name" : "init", - "cmds" : [ # 按cmds数组顺序启动启动服务 - "start shell", # 注意:start与服务名称之间有且只有一个空格 - ...... - "start service1" - ] - }, { - "name" : "post-init", # 最后执行的job, init进程启动完成后的处理(如驱动初始化后再mount设备) - "cmds" : [] - } - ], - "services" : [{ # service数组,一个service对应一个进程 - "name" : "shell", # 服务名称 - "path" : ["/sbin/getty", "-n", "-l", "/bin/sh", "-L", "115200", "ttyS000", "vt100"], # 可执行文件全路径,path必须为第一个元素 - "uid" : 0, # 进程的uid,须与二进制文件的uid保持一致 - "gid" : 0, # 进程的gid,须与二进制文件的gid保持一致 - "once" : 0, # 是否为一次性进程,1:进程退出后,init不在重新拉起。0:常驻进程,进程若退出,init将重新拉起 - "importance" : 0, # 是否为关键进程,1:是关键进程,若进程退出,init将会重启单板。0:非关键进程,若进程退出,init不会重启单板 - "caps" : [4294967295] - }, - ...... - ] - } - ``` - -3. **vendor/company/product/init_configs/hals** - 解决方案厂商对OS的适配,需要实现的接口请见各个部件的readme说明文档。 - -4. **vendor/company/product/config.json** - config.json为编译构建的主入口,包含了开发板、OS部件和内核等配置信息。 - - 以基于hispark_taurus开发板的ipcamera产品为例,配置文件如下: - - ``` - { - "product_name": "ipcamera", # 产品名称 - "version": "3.0", # config.json的版本号, 固定"3.0" - "type": "small", # 系统类型, 可选[mini, small, standard] - "ohos_version": "OpenHarmony 1.0", # 选择的OS版本 - "device_company": "hisilicon", # 芯片厂商 - "board": "hispark_taurus", # 开发板名称 - "kernel_type": "liteos_a", # 选择的内核类型 - "kernel_version": "3.0.0", # 选择的内核版本 - "subsystems": [ - { - "subsystem": "aafwk", # 选择的子系统 - "components": [ - { "component": "ability", "features":[ "enable_ohos_appexecfwk_feature_ability = true" ] } # 选择的部件和部件特性配置 - ] - }, - { - ...... - } - ...... - 更多子系统和部件 - } - } - ``` - -5. **vendor/company/product/fs.yml** - 该文件用于配置文件系统镜像制作过程,将编译产物打包成文件系统镜像,比如用户态根文件系统rootfs.img和可读写的userfs.img。它由多个列表组成,每个列表对应一个文件系统。字段说明如下: - - ``` - fs_dir_name: 必填,声明文件系统文件名, 如rootfs、userfs - fs_dirs: 选填,配置out下文件目录与文件系统文件目录的映射关系,每个文件目录对应一个列表 - source_dir: 选填,out下目标文件目录,若缺失则将根据target_dir在文件系统下创建空目录 - target_dir: 必填,文件系统下对应文件目录 - ignore_files:选填,声明拷贝忽略文件 - dir_mode: 选填,文件目录权限,默认755 - file_mode: 选填,该文件目录下所有文件的权限,默认555 - fs_filemode: 选填,配置需要特殊声明权限的文件,每个文件对应一个列表 - file_dir: 必填,文件系统下具体文件路径 - file_mode: 必填,文件权限声明 - fs_symlink: 选填,配置文件系统软连接 - fs_make_cmd: 必填,配置需要制作文件系统脚本,OS提供的脚本在build/lite/make_rootfs下, 支持linux,liteos内核和ext4、jffs2、vfat格式。也支持芯片解决方案厂商自定义。 - fs_attr: 选填,根据配置项动态调整文件系统 - ``` - - 其中fs_symlink、fs_make_cmd字段支持以下变量: - - - ${root_path} - 代码根目录,对应gn的${ohos_root_path} - - - ${out_path} - 产品out目录,对应gn的${root_out_dir} - - - ${fs_dir} - 文件系统目录,由以下变量拼接而成 - - - ${root_path} - - ${fs_dir_name} - - > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** - > fs.yml是可选的,对于没有文件系统的设备可不配置。 -6. **vendor/company/product/BUILD.gn** - 产品编译的入口,主要用于编译解决方案厂商源码和拷贝启动配置文件。如果某个产品被选择为要编译的产品,那么对应产品目录下的BUILD.gn会默认编译。一个典型的产品编译BUILD.gn应该如下: - - ``` - group("product") { # target名称需与product名称即三级目录名称一致 - deps = [] - # 拷贝init配置 - deps += [ "init_configs" ] - # 其他 - ...... - } - ``` - -## 使用指导 - -### 前提条件 - -开发环境需安装gn、ninja构建工具、python 3.9.2及以上和hb。安装方法请见[搭建基础环境](../quick-start/quickstart-lite-env-setup.md)。 - -### hb工具使用说明 - -hb是OpenHarmony的命令行工具,用来执行编译命令。以下对hb的常用命令进行说明。 - - **hb set** - -``` -hb set -h -usage: hb set [-h] [-root [ROOT_PATH]] [-p] - -optional arguments: - -h, --help show this help message and exit - -root [ROOT_PATH], --root_path [ROOT_PATH] - Set OHOS root path - -p, --product Set OHOS board and kernel -``` - -- hb set 后无参数,进入默认设置流程 - -- hb set -root dir可直接设置代码根目录 - -- hb set -p设置要编译的产品 - -**hb env** - -查看当前设置信息 - -``` -hb env -[OHOS INFO] root path: xxx -[OHOS INFO] board: hispark_taurus -[OHOS INFO] kernel: liteos -[OHOS INFO] product: ipcamera -[OHOS INFO] product path: xxx/vendor/hisilicon/ipcamera -[OHOS INFO] device path: xxx/device/hisilicon/hispark_taurus/sdk_linux_4.19 -``` - - **hb build** - -``` -hb build -h -usage: hb build [-h] [-b BUILD_TYPE] [-c COMPILER] [-t [TEST [TEST ...]]] [-cpu TARGET_CPU] [--dmverity] [--tee] - [-p PRODUCT] [-f] [-n] [-T [TARGET [TARGET ...]]] [-v] [-shs] [--patch] [--compact-mode] - [--gn-args GN_ARGS] [--keep-ninja-going] [--build-only-gn] [--log-level LOG_LEVEL] [--fast-rebuild] - [--device-type DEVICE_TYPE] [--build-variant BUILD_VARIANT] - [component [component ...]] - -positional arguments: - component name of the component, mini/small only - -optional arguments: - -h, --help show this help message and exit - -b BUILD_TYPE, --build_type BUILD_TYPE - release or debug version, mini/small only - -c COMPILER, --compiler COMPILER - specify compiler, mini/small only - -t [TEST [TEST ...]], --test [TEST [TEST ...]] - compile test suit - -cpu TARGET_CPU, --target-cpu TARGET_CPU - select cpu - --dmverity enable dmverity - --tee Enable tee - -p PRODUCT, --product PRODUCT - build a specified product with {product_name}@{company} - -f, --full full code compilation - -n, --ndk compile ndk - -T [TARGET [TARGET ...]], --target [TARGET [TARGET ...]] - compile single target - -v, --verbose show all command lines while building - -shs, --sign_haps_by_server - sign haps by server - --patch apply product patch before compiling - --compact-mode compatible with standard build system set to false if we use build.sh as build entrance - --gn-args GN_ARGS specifies gn build arguments, eg: --gn-args="foo="bar" enable=true blah=7" - --keep-ninja-going keeps ninja going until 1000000 jobs fail - --build-only-gn only do gn parse, donot run ninja - --log-level LOG_LEVEL - specifies the log level during compilationyou can select three levels: debug, info and error - --fast-rebuild it will skip prepare, preloader, gn_gen steps so we can enable it only when there is no change - for gn related script - --device-type DEVICE_TYPE - specifies device type - --build-variant BUILD_VARIANT - specifies device operating mode -``` - -- hb build后无参数,会按照设置好的代码路径、产品进行编译,编译选项使用与之前保持一致。-f 选项将删除当前产品所有编译产品,等同于hb clean + hb build. - -- hb build {component_name}:基于设置好的产品对应的单板、内核,单独编译部件(e.g.:hb build kv_store)。 - -- hb build -p ipcamera\@hisilicon:免set编译产品,该命令可以跳过set步骤,直接编译产品。 - -- 在device/board/device_company下单独执行hb build会进入内核选择界面,选择完成后会根据当前路径的单板、选择的内核编译出仅包含内核、驱动的镜像。 - -**hb clean** - -清除out目录对应产品的编译产物,仅保留args.gn、build.log。清除指定路径可输入路径参数:hb clean out/board/product,默认将清除当前hb set的产品对应out路径。 - -``` -hb clean -usage: hb clean [-h] [out_path] - -positional arguments: - out_path clean a specified path. - -optional arguments: - -h, --help show this help message and exit -``` - -### 新增部件 - -本小节介绍如何新增一个部件,首先确定部件归属的子系统和部件名称,然后按如下步骤新增: - -1. 源码开发完成后,添加部件编译脚本。 - - 以编译部件hello_world可执行文件为例,applications/sample/hello_world/BUILD.gn可以写为: - - ``` - executable("hello_world") { - include_dirs = [ - "include", - ] - sources = [ - "src/hello_world.c" - ] - } - ``` - - 如上编译脚本,可编译出一个可在OpenHarmony上运行的名为hello_world的可执行文件。 - - 单独编译该部件,hb set任意选择一款产品,然后使用-T选项单独编译部件: - - ``` - hb build -f -T //applications/sample/hello_world - ``` - - 部件在开发板上功能验证完成后,可按步骤2-4将部件配置到产品中。 - -2. 添加部件描述。 - - 部件描述位于build/lite/components下,新增的部件需加入对应子系统的json文件中。一个部件描述必选的字段有: - - - component:部件名称。 - - description:部件的一句话功能描述。 - - optional:部件是否为系统可选。 - - dirs:部件源码路径。 - - targets:部件编译入口。 - - 以将hello_world部件加入应用子系统为例,在applications.json中添加hello_world对象: - - ``` - { - "components": [ - { - "component": "hello_world", - "description": "Hello world.", - "optional": "true", - "dirs": [ - "applications/sample/hello_world" - ], - "targets": [ - "//applications/sample/hello_world" - ] - }, - ... - ] - } - ``` - -3. 将部件配置到产品。 - - 产品的配置文件config.json位于vendor/company/product/下,产品配置文件需包含产品名称、OpenHarmony版本号、device厂商、开发板、内核类型、内核版本号,以及配置的子系统和部件。以将hello_world部件加入产品配置文件my_product.json中为例,加入hello_world对象: - - ``` - { - "product_name": "hello_world_test", - "ohos_version": "OpenHarmony 1.0", - "device_company": "hisilicon", - "board": "hispark_taurus", - "kernel_type": "liteos_a", - "kernel_version": "1.0.0", - "subsystems": [ - { - "subsystem": "applications", - "components": [ - { "component": "hello_world", "features":[] } - ] - }, - ... - ] - } - ``` - -4. 编译产品。 - - 1. 代码根目录输入hb set选择对应产品。 - - 2. 执行hb build。 - -### 新增芯片解决方案 - -编译构建支持添加新的芯片解决方案厂商,具体步骤如下: - -1. 创建芯片解决方案目录。 - 按照[芯片解决方案配置规则](#配置规则)创建目录,以芯片厂商realtek的“rtl8720“开发板为例, 在代码根目录执行: - - ``` - mkdir -p device/board/realtek/rtl8720 - ``` - -2. 创建内核适配目录,并编写开发板编译配置config.gni文件。 - 以realtek的“rtl8720“开发板的liteos_a适配为例,device/board/realtek/rtl8720/liteo_a/config.gni的内容如下: - - ``` - # Kernel type, e.g. "linux", "liteos_a", "liteos_m". - kernel_type = "liteos_a" - - # Kernel version. - kernel_version = "3.0.0" - - # Board CPU type, e.g. "cortex-a7", "riscv32". - board_cpu = "real-m300" - - # Board arch, e.g. "armv7-a", "rv32imac". - board_arch = "" - - # Toolchain name used for system compiling. - # E.g. gcc-arm-none-eabi, arm-linux-harmonyeabi-gcc, ohos-clang, riscv32-unknown-elf. - # Note: The default toolchain is "ohos-clang". It's not mandatory if you use the default toochain. - board_toolchain = "gcc-arm-none-eabi" - - # The toolchain path installed, it's not mandatory if you have added toolchain path to your ~/.bashrc. - board_toolchain_path = - rebase_path("//prebuilts/gcc/linux-x86/arm/gcc-arm-none-eabi/bin", - root_build_dir) - - # Compiler prefix. - board_toolchain_prefix = "gcc-arm-none-eabi-" - - # Compiler type, "gcc" or "clang". - board_toolchain_type = "gcc" - - # Board related common compile flags. - board_cflags = [] - board_cxx_flags = [] - board_ld_flags = [] - ``` - -3. 编写编译脚本。 - 在开发板目录下创建BUILD.gn,target名称应与开发板名称一致。以realtek的rtl8720开发板为例,device/board/realtek/rtl8720/BUILD.gn内容可以是: - - ``` - group("rtl8720") { # target类型也可以shared_library, static_library, executable - # 具体内容 - ...... - } - ``` - -4. 编译芯片解决方案。 - 在开发板目录下执行hb build,即可启动芯片解决方案的编译。 - -### 新增产品解决方案 - -编译构建支持芯片解决方案和部件的灵活拼装,形成定制化的产品解决方案。具体步骤如下: - -1. 创建产品目录 - 按照[产品解决方案配置规则](#配置规则)创建产品目录,以基于“rtl8720“开发板的wifiiot模组为例,在代码根目录执行: - - ``` - mkdir -p vendor/my_company/wifiiot - ``` - -2. 拼装产品 - 在新建的产品目录下新建config.json文件,以步骤1中的wifiiot为例,vendor/my_company/wifiiot/config.json可以是: - - ``` - { - "product_name": "wifiiot", # 产品名称 - "version": "3.0", # config.json的版本号, 固定"3.0" - "type": "small", # 系统类型, 可选[mini, small, standard] - "ohos_version": "OpenHarmony 1.0", # 使用的OS版本 - "device_company": "realtek", # 芯片解决方案厂商名称 - "board": "rtl8720", # 开发板名称 - "kernel_type": "liteos_m", # 选择的内核类型 - "kernel_version": "3.0.0", # 选择的内核版本 - "subsystems": [ - { - "subsystem": "kernel", # 选择的子系统 - "components": [ - { "component": "liteos_m", "features":[] } # 选择的部件和部件特性 - ] - }, - ... - { - 更多子系统和部件 - } - ] - } - ``` - - 注意:编译构建系统编译前会对device_company,board,kernel_type,kernel_version、subsystem、component字段进行有效性检查,其中device_company,board,kernel_type,kernel_version应与已知的芯片解决方案匹配,subsystem、component应与build/lite/components下的部件描述匹配。 - -3. 适配OS接口 - 在产品目录下创建hals目录,并将产品解决方案对OS适配的源码和编译脚本放入该目录下。 - -4. 配置系统服务 - 在产品目录下创建init_configs目录,并在init_configs目录下创建init.cfg文件,按需配置要启动的系统服务。 - -5. 配置init进程(仅linux内核需要) - 在init_configs目录下创建etc目录,然后在etc下创建init.d文件夹和fstab文件。最后按产品需求在init.d文件下创建并编辑rcS文件和Sxxx文件。 - -6. 配置文件系统镜像(可选,仅支持文件系统的开发板需要) - 在产品目录下创建fs.yml文件。fs.yml需按产品实际情况配置,一个典型的fs.yml文件如下: - - ``` - - - fs_dir_name: rootfs # 镜像的名称 - fs_dirs: - - - # 将编译生成的out/my_board/my_product/bin目录下的文件拷贝到rootfs/bin中,并忽略测试bin - source_dir: bin - target_dir: bin - ignore_files: - - Test.bin - - TestSuite.bin - - - # 将编译生成的out/my_board/my_product/libs目录下的文件拷贝到rootfs/lib中,忽略所有.a文件,并设置文件和文件夹的权限为644和755 - source_dir: libs - target_dir: lib - ignore_files: - - .a - dir_mode: 755 - file_mode: 644 - - - source_dir: usr/lib - target_dir: usr/lib - ignore_files: - - .a - dir_mode: 755 - file_mode: 644 - - - source_dir: config - target_dir: etc - - - source_dir: system - target_dir: system - - - source_dir: sbin - target_dir: sbin - - - source_dir: usr/bin - target_dir: usr/bin - - - source_dir: usr/sbin - target_dir: usr/sbin - - - # 创建一个proc空目录 - target_dir: proc - - - target_dir: mnt - - - target_dir: opt - - - target_dir: tmp - - - target_dir: var - - - target_dir: sys - - - source_dir: etc - target_dir: etc - - - source_dir: vendor - target_dir: vendor - - - target_dir: storage - - fs_filemode: - - - file_dir: lib/ld-uClibc-0.9.33.2.so - file_mode: 555 - - - file_dir: lib/ld-2.24.so - file_mode: 555 - - - file_dir: etc/init.cfg - file_mode: 400 - fs_symlink: - - - # 在rootfs/lib下创建软连接ld-musl-arm.so.1 -> libc.so - source: libc.so - link_name: ${fs_dir}/lib/ld-musl-arm.so.1 - - - source: mksh - link_name: ${fs_dir}/bin/sh - - - source: mksh - link_name: ${fs_dir}/bin/shell - fs_make_cmd: - # 使用脚本将rootfs制作为ext4格式的image - - ${root_path}/build/lite/make_rootfs/rootfsimg_linux.sh ${fs_dir} ext4 - - - fs_dir_name: userfs - fs_dirs: - - - source_dir: storage/etc - target_dir: etc - - - source_dir: data - target_dir: data - fs_make_cmd: - - ${root_path}/build/lite/make_rootfs/rootfsimg_linux.sh ${fs_dir} ext4 - - ``` - -7. 配置产品Patch(可选,视产品涉及部件是否需要打补丁而定) - 在产品目录下创建patch.yml文件。patch.yml需按产品实际情况配置,一个典型的patch.yml文件如下: - - ``` - # 需要打patch的路径 - foundation/communication/dsoftbus: - # 该路径下需要打的patch存放路径 - - foundation/communication/dsoftbus/1.patch - - foundation/communication/dsoftbus/2.patch - third_party/wpa_supplicant: - - third_party/wpa_supplicant/1.patch - - third_party/wpa_supplicant/2.patch - - third_party/wpa_supplicant/3.patch - ... - ``` - - 配置完成后,编译时增加--patch参数,即可在产品编译前将配置的Patch文件打到对应目录中,再进行编译: - - ``` - hb build -f --patch - ``` - -8. 编写编译脚本 - 在产品目录下创建BUILD.gn文件,按产品实际情况编写脚本。以步骤1中的wifiiot为例,BUILD.gn示例如下: - - ``` - group("wifiiot") { # target名称与产品名一致 - deps = [] - # 拷贝init配置 - deps += [ "init_configs" ] - # 将hals加入编译 - deps += [ "hals" ] - # 其他 - ...... - } - ``` - -9. 编译产品。 - 在代码根目录执行hb set按提示选择新增的产品,然后执行hb build即可启动编译。 - -## 常见问题 - -### 编译构建过程中,提示“usr/sbin/ninja: invalid option -- w” - -- **现象描述:** - 编译失败,提示“usr/sbin/ninja: invalid option -- w”。 - -- **可能原因:** - 编译环境中ninja版本太低,不支持--w选项。 - -- **解决办法:** - 卸载环境中ninja和gn,按照[获取工具](../get-code/gettools-ide.md)。 - -### 编译构建过程中,提示“/usr/bin/ld: cannot find -lncurses” - -- **现象描述:** - 编译失败,提示“/usr/bin/ld: cannot find -lncurses”。 - -- **可能原因:** - 编译环境ncurses库缺失。 - -- **解决办法:** - - ``` - sudo apt-get install lib32ncurses5-dev - ``` - -### 编译构建过程中,提示“line 77: mcopy: command not found” - -- **现象描述:** - ​编译失败,提示“line 77: mcopy: command not found”。 - -- **可能原因:** - 编译环境未安装mcopy。 - -- **解决办法:** - - ``` - ​sudo apt-get install dosfstools mtools - ``` - -### 编译构建过程中,提示“riscv32-unknown-elf-gcc: error trying to exec 'cc1': execvp: No such file or directory” - -- **现象描述:** - 编译失败,提示“riscv32-unknown-elf-gcc: error trying to exec 'cc1': execvp: No such file or directory”。 - -- ​**可能原因:** - 当前用户对riscv编译器路径下的文件访问权限不够。 - -- ​**解决办法:** - 查询gcc_riscv32所在目录。 - - ``` - which riscv32-unknown-elf-gcc - ``` - - 使用chmod命令修改目录权限为755。 - -### 编译构建过程中,提示“No module named 'Crypto'” - -- **现象描述:** - 编译失败,提示“No module named 'Crypto'”。 - -- **可能原因:** - python3未安装Crypto。 - -- **解决办法:** - - 1. 查询Python版本号。 - - ``` - python3 --version - ``` - - 2. 需使用python3.9.2以上版本,然后安装pycryptodome。 - - ``` - sudo pip3 install pycryptodome - ``` - -### 编译构建过程中,提示“xx.sh : xx unexpected operator” - -- **现象描述:** - 编译失败:“xx.sh [: xx unexpected operator”。 - -- **可能原因:** - 编译环境shell不是bash。 - -- **解决办法:** - - ``` - sudo rm -rf /bin/sh - sudo ln -s /bin/bash /bin/sh - ``` \ No newline at end of file diff --git a/zh-cn/device-dev/subsystems/subsys-build-module.md b/zh-cn/device-dev/subsystems/subsys-build-module.md new file mode 100644 index 0000000000..151a060f1f --- /dev/null +++ b/zh-cn/device-dev/subsystems/subsys-build-module.md @@ -0,0 +1,505 @@ +# 模块 +## 模块配置规则 + +编译子系统通过模块、部件和产品三层配置来实现编译和打包。模块就是编译子系统的一个目标,包括(动态库、静态库、配置文件、预编译模块等)。模块要定义属于哪个部件,一个模块只能归属于一个部件。Openharmony使用定制化的Gn模板来配置模块规则,Gn语法相关的基础知识请参考[官网手册](https://gn.googlesource.com/gn/+/main/docs/reference.md)。 + +以下是常用的模块配置规则: + +``` +# C/C++模板 +ohos_shared_library +ohos_static_library +ohos_executable +ohos_source_set + +# 预编译模板: +ohos_prebuilt_executable +ohos_prebuilt_shared_library +ohos_prebuilt_static_library + +#hap模板 +ohos_hap +ohos_app_scope +ohos_js_assets +ohos_resources + +#其他常用模板 +#配置文件 +ohos_prebuild_etc + +#sa配置 +ohos_sa_profile +``` + +ohos开头的模板与内建模板的差异主要在于:推荐使用ohos定制模板。 + +### C/C++模板示例 + +ohos开头的模板对应的.gni文件路径在:openharmony/build/templates/cxx/cxx.gni。 + +ohos_shared_library示例 + +```shell +import("//build/ohos.gni") +ohos_shared_library("helloworld") { + sources = ["file"] + include_dirs = [] # 如有重复头文件定义,优先使用前面路径头文件 + cflags = [] # 如重复冲突定义,后面的参数优先生效,也就是该配置项中优先生效 + cflags_c = [] + cflags_cc = [] + ldflags = [] # 如重复冲突定义,前面参数优先生效,也就是ohos_template中预制参数优先生效 + configs = [] + deps = [] # 部件内模块依赖 + + external_deps = [ # 跨部件模块依赖定义, + "part_name:module_name", # 定义格式为 "部件名:模块名称" + ] # 这里依赖的模块必须是依赖的部件声明在inner_kits中的模块 + + output_name = [string] # 模块输出名 + output_extension = [] # 模块名后缀 + module_install_dir = [] # 缺省在/system/lib64或/system/lib下, 模块安装路径,模块安装路径,从system/,vendor/后开始指定 + relative_install_dir = [] # 模块安装相对路径,相对于/system/lib64或/system/lib;如果有module_install_dir配置时,该配置不生效 + + part_name = [string] # 必选,所属部件名称 + output_dir + + # Sanitizer variables + cfi = [boolean] + scs = [boolean] + scudo = [] + ubsan = [] + boundary_sanitize = [] + integer_overflow_sanitize = [] + + testonly = [boolean] + license_as_sources = [] + license_file = [] # 后缀名是.txt的文件 + remove_configs = [] + no_default_deps = [] + install_images = [] + install_enable = [boolean] + symlink_target_name = [] + version_script = [] + use_exceptions = [] +} +``` + +ohos_static_library示例 + +```shell +import("//build/ohos.gni") +ohos_static_library("helloworld") { + sources = ["file"] # 后缀名是.c的相关文件 + include_dirs = ["dir"] # 包含目录 + configs = [] # 配置 + deps = [] # 部件内模块依赖 + part_name = [string] # 部件名称 + subsystem_name = [string] # 子系统名称 + cflags = [] + + external_deps = [ # 跨部件模块依赖定义, + "part_name:module_name", # 定义格式为 "部件名:模块名称" + ] # 这里依赖的模块必须是依赖的部件声明在inner_kits中的模块 + + lib_dirs = [] + public_configs = [] + + # Sanitizer variables + cfi = [boolean] + scs = [boolean] + scudo = [] + ubsan = [] + boundary_sanitize = [] + integer_overflow_sanitize = [] + + remove_configs = [] + no_default_deps = [] + license_file = [] # 后缀名是.txt的文件 + license_as_sources = [] + use_exceptions = [] +} +``` + +ohos_executable示例 + +```shell +import("//build/ohos.gni") +ohos_executable("helloworld") { + configs = [] # 配置 + part_name = [string] # 部件名称 + subsystem_name = [string] # 子系统名称 + deps = [] # 部件内模块依赖 + + external_deps = [ # 跨部件模块依赖定义, + "part_name:module_name", # 定义格式为 "部件名:模块名称" + ] # 这里依赖的模块必须是依赖的部件声明在inner_kits中的模块 + ohos_test = [] + test_output_dir = [] + + # Sanitizer variables + cfi = [boolean] + scs = [boolean] + scudo = [] + ubsan = [] + boundary_sanitize = [] + integer_overflow_sanitize = [] + + testonly = [boolean] + license_as_sources = [] + license_file = [] # 后缀名是.txt的文件 + remove_configs = [] + static_link = [] + install_images = [] + module_install_dir = [] # 模块安装路径,从system/,vendor/后开始指定 + relative_install_dir = [] + symlink_target_name = [] + output_dir = [directory] # 存放输出文件的目录 + install_enable = [boolean] + version_script = [] + use_exceptions = [] +} +``` + +ohos_source_set示例 + +```shell +import("//build/ohos.gni") +ohos_source_set("helloworld") { + sources = ["file"] # 后缀名是.c的相关文件 + include_dirs = [] # 包含目录 + configs = [] # 配置 + public = [] # .h类型头文件 + defines = [] + public_configs = [] + part_name = [string] # 部件名称 + subsystem_name = [string] # 子系统名称 + deps = [] # 部件内模块依赖 + + external_deps = [ # 跨部件模块依赖定义, + "part_name:module_name", # 定义格式为 "部件名:模块名称" + ] # 这里依赖的模块必须是依赖的部件声明在inner_kits中的模块 + + # Sanitizer variables + cfi = [boolean] + scs = [boolean] + scudo = [] + ubsan = [] + boundary_sanitize = [] + integer_overflow_sanitize = [] + + testonly = [boolean] + license_as_sources = [] + license_file = [] + remove_configs = [] + no_default_deps = [] + license_file = [] # 后缀名是.txt的文件 + license_as_sources = [] + use_exceptions = [] +} +``` + +![icon-note.gif](public_sys-resources/icon-note.gif)**注意**:只有sources和part_name是必选,其他都是可选的。 + +### 预编译模板示例 + +预编译模板的.gni相关文件路径在:openharmony/build/templates/cxx/prebuilt.gni。 + +ohos_prebuilt_executable示例 + +```shell +import("//build/ohos.gni") +ohos_prebuilt_executable("helloworld") { + sources = ["file"] # 源 + output = [] + install_enable = [boolean] + + deps = [] # 部件内模块依赖 + public_configs = [] + subsystem_name = [string] # 子系统名 + part_name = [string] # 部件名 + + testonly = [boolean] + visibility = [] + + install_images = [] + module_install_dir = [] # 模块安装路径,从system/,vendor/后开始指定 + relative_install_dir = [] # 模块安装相对路径,相对于system/etc;如果有module_install_dir配置时,该配置不生效 + symlink_target_name = [] + + + license_file = [] # 后缀名是.txt的文件 + license_as_sources = [] +} +``` + +ohos_prebuilt_shared_library示例 + +```shell +import("//build/ohos.gni") +ohos_prebuilt_shared_library("helloworld") { + sources = ["file"] # 一般是后缀为.so的文件 + output = [] + install_enable = [boolean] + + deps = [] # 部件内模块依赖 + public_configs = [] + subsystem_name = [string] # 子系统名 + part_name = [string] # 部件名 + + testonly = [boolean] + visibility = [] + + install_images = [] + module_install_dir = [] # 模块安装路径,从system/,vendor/后开始指定 + relative_install_dir = [] # 模块安装相对路径,相对于system/etc;如果有module_install_dir配置时,该配置不生效 + symlink_target_name = [string] + + + license_file = [string] # 后缀名是.txt的文件 + license_as_sources = [] +} +``` + +ohos_prebuilt_static_library示例 + +```shell +import("//build/ohos.gni") +ohos_prebuilt_static_library("helloworld") { + sources = ["file"] # 一般是后缀为.so的文件 + output = [] + + deps = [] # 部件内模块依赖 + public_configs = [] + subsystem_name = [string] # 子系统名 + part_name = [string] # 部件名 + + testonly = [boolean] + visibility = [] + + license_file = [string] # 后缀名是.txt的文件 + license_as_sources = [] +} +``` + +![icon-note.gif](public_sys-resources/icon-note.gif)**注意**:只有sources和part_name是必选,其他都是可选的。 + +### Hap模板 + +hap模板详见:[ HAP编译构建指导](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/subsystems/subsys-build-gn-hap-compilation-guide.md) + + + +### 其他常用模板 + +ohos_prebuilt_etc示例: + +```shell +import("//build/ohos.gni") +ohos_prebuilt_etc("helloworld") { + # ohos_prebuilt_etc模板最常用属性: + sources = ["file"] + module_install_dir = [] # 模块安装路径,从system/,vendor/后开始指定 + subsystem_name = [string] # 子系统名 + part_name = [string] # 必选,所属部件名称 + install_images = [] + relative_install_dir = [] # 模块安装相对路径,相对于system/etc;如果有module_install_dir配置时,该配置不生效 + + # ohos_prebuilt_etc模板不常用属性: + deps = [] # 部件内模块依赖 + testonly = [boolean] + visibility = [] + public_configs = [] + symlink_target_name = [string] + license_file = [string] + license_as_sources = [] +} +``` + +ohos_sa_profile示例: + +```shell +import("//build/ohos.gni") +ohos_sa_profile("helloworld") { + sources = [".xml"] # xml文件 + part_name = [string] # 部件名 + subsystem_name = [string] # 子系统名 +} +``` + +![icon-note.gif](public_sys-resources/icon-note.gif)**注意**:只有sources和part_name是必选,其他都是可选的。 + +## 新增并编译模块 + +新建模块可以分为以下三种情况。主要的添加逻辑如下面的流程图所示,若没有子系统则需新建子系统并在该子系统的部件下添加模块,若没有部件则需新建部件并在其中添加模块,否则直接在原有部件中添加模块即可,需要注意的是芯片解决方案作为特殊部件是没有对应子系统的。 + +- 在原有部件中添加一个模块 + +- 新建部件并在其中添加模块 + +- 新建子系统并在该子系统的部件下添加模块 + + ![模块添加流程](figures/module_addition_process.png) + +**在原有部件中添加一个模块** + +1. 在模块目录下配置BUILD.gn,根据模板类型选择对应的gn模板。 + +2. 修改bundle.json配置文件。 + + ```shell + { + "name": "@ohos/", # HPM部件英文名称,格式"@组织/部件名称" + "description": "xxxxxxxxxxxxxxxxxxx", # 部件功能一句话描述 + "version": "3.1", # 版本号,版本号与OpenHarmony版本号一致 + "license": "MIT", # 部件License + "publishAs": "code-segment", # HPM包的发布方式,当前默认都为code-segment + "segment": { + "destPath": "third_party/nghttp2" + }, # 发布类型为code-segment时为必填项,定义发布类型code-segment的代码还原路径(源码路径) + "dirs": {}, # HPM包的目录结构,字段必填内容可以留空 + "scripts": {}, # HPM包定义需要执行的脚本,字段必填,值非必填 + "licensePath": "COPYING", + "readmePath": { + "en": "README.rst" + }, + "component": { # 部件属性 + "name": "", # 部件名称 + "subsystem": , # 部件所属子系统 + "syscap": [], # 部件为应用提供的系统能力 + "features": [], # 部件对外的可配置特性列表,一般与build中的sub_component对应,可供产品配置 + "adapted_system_type": [], # 轻量(mini)小型(small)和标准(standard),可以是多个 + "rom": "xxxKB" # ROM基线,没有基线写当前值 + "ram": "xxxKB", # RAM基线,没有基线写当前值 + "deps": { + "components": [], # 部件依赖的其他部件 + "third_party": [] # 部件依赖的三方开源软件 + }, + + "build": { # 编译相关配置 + "sub_component": [ + "//foundation/arkui/napi:napi_packages", # 原有模块1 + "//foundation/arkui/napi:napi_packages_ndk" # 原有模块2 + "//foundation/arkui/napi:new" # 新增模块new + ], # 部件编译入口,模块在此处配置 + "inner_kits": [], # 部件间接口 + "test": [] # 部件测试用例编译入口 + } + } + } + ``` + + ![icon-note.gif](public_sys-resources/icon-note.gif)**注意**:无论哪种方式该bundle.json文件均在对应子系统所在文件夹下。 + +3. 成功添加验证:编译完成后打包到image中去,生成对应的so文件或者二进制文件。 + +**新建部件并在其中添加一个模块** + +1. 在模块目录下配置BUILD.gn,根据模板类型选择对应的gn模板。这一步与在原有部件中添加一个模块的方法基本一致,只需注意该模块对应BUILD.gn文件中的part_name为新建部件的名称即可。 + +2. 新建一个bundle.json文件,bundle.json文件均在对应子系统所在文件夹下。 + +3. 在vendor/{product_company}/{product-name}/config.json中添加对应的部件,直接添加到原有部件后即可。 + + ```shell + "subsystems": [ + { + "subsystem": "部件所属子系统名", + "components": [ + { "component": "部件名1", "features":[] }, # 子系统下的原有部件1 + { "component": "部件名2", "features":[] }, # 子系统下的原有部件2 + { "component": "部件名new", "features":[] } # 子系统下的新增部件new + ] + }, + . + ] + ``` + +4. 成功添加验证:编译完成后打包到image中去,生成对应的so文件或者二进制文件。 + + +**新建子系统并在该子系统的部件下添加模块** + +1. 在模块目录下配置BUILD.gn,根据模板类型选择对应的gn模板。这一步与新建部件并在其中添加模块中对应的步骤并无区别。 + +2. 在新建的子系统目录下每个部件对应的文件夹下创建bundle.json文件,定义部件信息。这一步与新建部件并在其中添加模块中对应的步骤并无区别。 + +3. 修改build目录下的subsystem_config.json文件。 + + ```shell + { + "子系统名1": { # 原有子系统1 + "path": "子系统目录1", + "name": "子系统名1" + }, + "子系统名2": { # 原有子系统2 + "path": "子系统目录2", + "name": "子系统名2" + }, + "子系统名new": { # 新增子系统new + "path": "子系统目录new", + "name": "子系统名new" + }, + + } + ``` + + 该文件定义了有哪些子系统以及这些子系统所在文件夹路径,添加子系统时需要说明子系统path与name,分别表示子系统路径和子系统名。 + +4. 在vendor/{product_company}/{product-name}目录下的产品配置如product-name是hispark_taurus_standard时,在config.json中添加对应的部件,直接添加到原有部件后即可。 + + ```shell + "subsystems": [ + { + "subsystem": "arkui", # 原有的子系统名 + "components": [ # 单个子系统下的所有部件集合 + { + "component": "ace_engine_standard", # 原有的部件名 + "features": [] + }, + { + "component": "napi", # 原有的部件名 + "features": [] + } + { + "component": "component_new1", # 原有子系统新增的的部件名component_new1 + "features": [] + } + ] + }, + { + "subsystem": "subsystem_new", # 新增的子系统名 + "components": [ + { + "component": "component_new2", # 新增子系统新增的的部件名component_new2 + "features": [] + } + ] + }, + + ] + ``` + +4. 成功添加验证:编译完成后打包到image中去,生成对应的so文件或者二进制文件。 + + +**编译模块** + +主要有两种编译方式,[命令行方式和hb方式](subsys-build-all.md#编译命令),这里以命令行方式为例。 + + 模块可以使用“--build-target 模块名"单独编译,编译命令如下: + + ```shell + ./build.sh --build-target 模块名 + ``` + + 也可以编译相应产品,以编译hispark_taurus_standard为例,编译命令如下: + + ```shell + ./build.sh --product-name hispark_taurus_standard --build-target 模块名 --ccache + ``` + + 还可以编译模块所在的部件: + + ```shell + ./build.sh --product-name hispark_taurus_standard --build-target musl --build-target 模块名 --ccache + ``` \ No newline at end of file diff --git a/zh-cn/device-dev/subsystems/subsys-build-product.md b/zh-cn/device-dev/subsystems/subsys-build-product.md new file mode 100644 index 0000000000..154cdfdc9e --- /dev/null +++ b/zh-cn/device-dev/subsystems/subsys-build-product.md @@ -0,0 +1,337 @@ +# 产品 +### 产品配置规则 + +产品解决方案为基于开发板的完整产品,主要包含产品对OS的适配、部件拼装配置、启动配置和文件系统配置等。产品解决方案的源码路径规则为:**vendor/{产品解决方案厂商}/{产品名称}**_。 + +产品解决方案的目录树规则如下: + +```shell +vendor +└── company # 产品解决方案厂商 + ├── product # 产品名称 + │ ├── init_configs + │ │ ├── etc # init进程启动配置(可选,仅linux内核需要) + │ │ └── init.cfg # 系统服务启动配置 + │ ├── hals # 产品解决方案OS适配 + │ ├── BUILD.gn # 产品编译脚本 + │ └── config.json # 产品配置文件 + │ └── fs.yml # 文件系统打包配置 + └── ...... +``` + +> ![icon-note.gif](public_sys-resources/icon-note.gif)**注意**:新增产品须按如上的规则创建目录和文件,编译构建系统将按该规则扫描已配置的产品。 + +关键的目录和文件详细介绍如下: + +1. **vendor/company/product/init_configs/etc** 该文件夹中包含rcS脚本,Sxxx脚本和fstab脚本。init进程在启动系统服务之前执行这些脚本。执行的流程为“rcS->fstab->S00-xxx“。Sxxx脚本中的内容与开发板和产品需要有关,主要包括设备节点的创建、创建目录、扫描设备节点、修改文件权限等等。这些文件在产品编译的BUILD.gn中按需拷贝到产品out目录中,最终打包到rootfs镜像中。 + +2. **vendor/company/product/init_configs/init.cfg** init进程启动服务的配置文件,当前支持解析的命令有: + + - start: 启动某个服务 + + - mkdir: 创建文件夹 + + - chmod: 修改指定路径/文件的权限 + + - chown: 修改指定路径/文件的属组 + + - mount: 挂载命令 + + 该文件中的各个字段的解释如下: + + ```shell + { + "jobs" : [{ # job数组,一个job对应一个命令集合。job的执行顺序:pre-init -> init -> post-init。 + "name" : "pre-init", + "cmds" : [ + "mkdir /storage/data", # 创建目录 + "chmod 0755 /storage/data", # 修改权限,权限值的格式为0xxx, 如0755 + "mkdir /storage/data/log", + "chmod 0755 /storage/data/log", + "chown 4 4 /storage/data/log", # 修改属组,第一个数字为uid, 第二个数字为gid + ...... + "mount vfat /dev/mmcblock0 /sdcard rw,umask=000" # 挂载,格式为: mount [文件系统类型] [source] [target] [flags] [data] + # 其中flags仅支持:nodev、noexec、nosuid和rdonly + ] + }, { + "name" : "init", + "cmds" : [ # 按cmds数组顺序启动启动服务 + "start shell", # 注意:start与服务名称之间有且只有一个空格 + ...... + "start service1" + ] + }, { + "name" : "post-init", # 最后执行的job, init进程启动完成后的处理(如驱动初始化后再mount设备) + "cmds" : [] + } + ], + "services" : [{ # service数组,一个service对应一个进程 + "name" : "shell", # 服务名称 + "path" : ["/sbin/getty", "-n", "-l", "/bin/sh", "-L", "115200", "ttyS000", "vt100"], # 可执行文件全路径,path必须为第一个元素 + "uid" : 0, # 进程的uid,须与二进制文件的uid保持一致 + "gid" : 0, # 进程的gid,须与二进制文件的gid保持一致 + "once" : 0, # 是否为一次性进程,1:进程退出后,init不在重新拉起。0:常驻进程,进程若退出,init将重新拉起 + "importance" : 0, # 是否为关键进程,1:是关键进程,若进程退出,init将会重启单板。0:非关键进程,若进程退出,init不会重启单板 + "caps" : [4294967295] + }, + ...... + ] + } + ``` + +3. **vendor/company/product/init_configs/hals** 解决方案厂商对OS的适配,需要实现的接口请见各个部件的readme说明文档。 + +4. **vendor/company/product/config.json** config.json为编译构建的主入口,包含了开发板、OS部件和内核等配置信息。 + + 以基于hispark_taurus开发板的ipcamera产品为例,配置文件如下: + + ```shell + { + "product_name": "ipcamera", # 产品名称 + "version": "3.0", # config.json的版本号, 固定"3.0" + "type": "small", # 系统类型, 可选[mini, small, standard] + "ohos_version": "OpenHarmony 1.0", # 选择的OS版本 + "device_company": "hisilicon", # 芯片厂商 + "board": "hispark_taurus", # 开发板名称 + "kernel_type": "liteos_a", # 选择的内核类型 + "kernel_version": "3.0.0", # 选择的内核版本 + "subsystems": [ + { + "subsystem": "aafwk", # 选择的子系统 + "components": [ + { "component": "ability", "features":[ "enable_ohos_appexecfwk_feature_ability = true" ] } # 选择的部件和部件特性配置 + ] + }, + { + ...... + } + ...... + 更多子系统和部件 + } + } + ``` + +5. **vendor/company/product/fs.yml** 该文件用于配置文件系统镜像制作过程,将编译产物打包成文件系统镜像,比如用户态根文件系统rootfs.img和可读写的userfs.img。它由多个列表组成,每个列表对应一个文件系统。字段说明如下: + + ```shell + fs_dir_name: 必填,声明文件系统文件名, 如rootfs、userfs + fs_dirs: 选填,配置out下文件目录与文件系统文件目录的映射关系,每个文件目录对应一个列表 + source_dir: 选填,out下目标文件目录,若缺失则将根据target_dir在文件系统下创建空目录 + target_dir: 必填,文件系统下对应文件目录 + ignore_files:选填,声明拷贝忽略文件 + dir_mode: 选填,文件目录权限,默认755 + file_mode: 选填,该文件目录下所有文件的权限,默认555 + fs_filemode: 选填,配置需要特殊声明权限的文件,每个文件对应一个列表 + file_dir: 必填,文件系统下具体文件路径 + file_mode: 必填,文件权限声明 + fs_symlink: 选填,配置文件系统软连接 + fs_make_cmd: 必填,配置需要制作文件系统脚本,OS提供的脚本在build/lite/make_rootfs下, 支持linux,liteos内核和ext4、jffs2、vfat格式。也支持芯片解决方案厂商自定义。 + fs_attr: 选填,根据配置项动态调整文件系统 + ``` + + 其中fs_symlink、fs_make_cmd字段支持以下变量: + + - rootpath代码根目录,对应gn的{ohos_root_path} + - outpath产品out目录,对应gn的{root_out_dir} + - ${fs_dir} 文件系统目录,由以下变量拼接而成 + - ${root_path} + - ${fs_dir_name} + +> ![icon-note.gif](public_sys-resources/icon-note.gif)**注意**:fs.yml是可选的,对于没有文件系统的设备可不配置。 + +6. **vendor/company/product/BUILD.gn** 产品编译的入口,主要用于编译解决方案厂商源码和拷贝启动配置文件。如果某个产品被选择为要编译的产品,那么对应产品目录下的BUILD.gn会默认编译。一个典型的产品编译BUILD.gn应该如下: + + ```shell + group("product") { # target名称需与product名称即三级目录名称一致 + deps = [] + deps += [ "init_configs" ] # 拷贝init配置 + ...... # 其他 + } + ``` + +### 新增并编译产品 + +编译构建支持芯片解决方案和部件的灵活拼装,形成定制化的产品解决方案。具体步骤如下: + +1. 创建产品目录 按照产品配置规则创建产品目录,以基于“rtl8720“开发板的wifiiot模组为例,在代码根目录执行: + + ```shell + mkdir -p vendor/my_company/wifiiot + ``` + +2. 拼装产品 在新建的产品目录下新建config.json文件,以步骤1中的wifiiot为例,vendor/my_company/wifiiot/config.json可以是: + + ```shell + { + "product_name": "wifiiot", # 产品名称 + "version": "3.0", # config.json的版本号, 固定"3.0" + "type": "small", # 系统类型, 可选[mini, small, standard] + "ohos_version": "OpenHarmony 1.0", # 使用的OS版本 + "device_company": "realtek", # 芯片解决方案厂商名称 + "board": "rtl8720", # 开发板名称 + "kernel_type": "liteos_m", # 选择的内核类型 + "kernel_version": "3.0.0", # 选择的内核版本 + "subsystems": [ + { + "subsystem": "kernel", # 选择的子系统 + "components": [ + { "component": "liteos_m", "features":[] } # 选择的部件和部件特性 + ] + }, + ... + { + 更多子系统和部件 + } + ] + } + ``` + + ![icon-note.gif](public_sys-resources/icon-note.gif)**注意**:编译构建系统编译前会对device_company,board,kernel_type,kernel_version、subsystem、component字段进行有效性检查,其中device_company,board,kernel_type,kernel_version应与已知的芯片解决方案匹配,subsystem、component应与build/lite/components下的部件描述匹配。 + +3. 适配OS接口 在产品目录下创建hals目录,并将产品解决方案对OS适配的源码和编译脚本放入该目录下。 + +4. 配置系统服务 在产品目录下创建init_configs目录,并在init_configs目录下创建init.cfg文件,按需配置要启动的系统服务。 + +5. 配置init进程(仅linux内核需要) 在init_configs目录下创建etc目录,然后在etc下创建init.d文件夹和fstab文件。最后按产品需求在init.d文件下创建并编辑rcS文件和Sxxx文件。 + +6. 配置文件系统镜像(可选,仅支持文件系统的开发板需要) 在产品目录下创建fs.yml文件。fs.yml需按产品实际情况配置,一个典型的fs.yml文件如下: + + ```shell + - + fs_dir_name: rootfs # 镜像的名称 + fs_dirs: + - + # 将编译生成的out/my_board/my_product/bin目录下的文件拷贝到rootfs/bin中,并忽略测试bin + source_dir: bin + target_dir: bin + ignore_files: + - Test.bin + - TestSuite.bin + - + # 将编译生成的out/my_board/my_product/libs目录下的文件拷贝到rootfs/lib中,忽略所有.a文件,并设置文件和文件夹的权限为644和755 + source_dir: libs + target_dir: lib + ignore_files: + - .a + dir_mode: 755 + file_mode: 644 + - + source_dir: usr/lib + target_dir: usr/lib + ignore_files: + - .a + dir_mode: 755 + file_mode: 644 + - + source_dir: config + target_dir: etc + - + source_dir: system + target_dir: system + - + source_dir: sbin + target_dir: sbin + - + source_dir: usr/bin + target_dir: usr/bin + - + source_dir: usr/sbin + target_dir: usr/sbin + - + # 创建一个proc空目录 + target_dir: proc + - + target_dir: mnt + - + target_dir: opt + - + target_dir: tmp + - + target_dir: var + - + target_dir: sys + - + source_dir: etc + target_dir: etc + - + source_dir: vendor + target_dir: vendor + - + target_dir: storage + + fs_filemode: + - + file_dir: lib/ld-uClibc-0.9.33.2.so + file_mode: 555 + - + file_dir: lib/ld-2.24.so + file_mode: 555 + - + file_dir: etc/init.cfg + file_mode: 400 + fs_symlink: + - + # 在rootfs/lib下创建软连接ld-musl-arm.so.1 -> libc.so + source: libc.so + link_name: ${fs_dir}/lib/ld-musl-arm.so.1 + - + source: mksh + link_name: ${fs_dir}/bin/sh + - + source: mksh + link_name: ${fs_dir}/bin/shell + fs_make_cmd: + # 使用脚本将rootfs制作为ext4格式的image + - ${root_path}/build/lite/make_rootfs/rootfsimg_linux.sh ${fs_dir} ext4 + - + fs_dir_name: userfs + fs_dirs: + - + source_dir: storage/etc + target_dir: etc + - + source_dir: data + target_dir: data + fs_make_cmd: + - ${root_path}/build/lite/make_rootfs/rootfsimg_linux.sh ${fs_dir} ext4 + ``` + +7. 配置产品Patch(可选,视产品涉及部件是否需要打补丁而定) 在产品目录下创建patch.yml文件。patch.yml需按产品实际情况配置,一个典型的patch.yml文件如下: + + ```shell + # 需要打patch的路径 + foundation/communication/dsoftbus: + # 该路径下需要打的patch存放路径 + - foundation/communication/dsoftbus/1.patch + - foundation/communication/dsoftbus/2.patch + third_party/wpa_supplicant: + - third_party/wpa_supplicant/1.patch + - third_party/wpa_supplicant/2.patch + - third_party/wpa_supplicant/3.patch + ... + ``` + + 配置完成后,编译时增加--patch参数,即可在产品编译前将配置的Patch文件打到对应目录中,再进行编译: + + ```shell + hb build -f --patch + ``` + +8. 编写编译脚本 在产品目录下创建BUILD.gn文件,按产品实际情况编写脚本。以步骤1中的wifiiot为例,BUILD.gn示例如下: + + ```shell + group("wifiiot") { # target名称与产品名一致 + deps = [] + deps += [ "init_configs" ] # 拷贝init配置 + deps += [ "hals" ] # 将hals加入编译 + ...... # 其他 + } + ``` + +9. 编译产品。 主要有两种编译方式,[命令行方式和hb方式](subsys-build-all.md#编译命令),这里以命令行方式为例,假设编译的产品名是hispark_taurus_standard,则编译命令是: + + ``` + ./build.sh --product-name hispark_taurus_standard --ccache + ``` + + diff --git a/zh-cn/device-dev/subsystems/subsys-build-reference.md b/zh-cn/device-dev/subsystems/subsys-build-reference.md new file mode 100644 index 0000000000..6133338c01 --- /dev/null +++ b/zh-cn/device-dev/subsystems/subsys-build-reference.md @@ -0,0 +1,143 @@ +# 参考信息 + +## 关于deps、external_deps的使用 + +在添加一个模块的时候,需要在BUILD.gn中声明它的依赖,为了便于后续处理部件间依赖关系,我们将依赖分为两种——部件内依赖deps和部件间依赖external_deps。 + +**依赖分类** + +![依赖关系分类](figures/dependency_classification.png) + +如上图所示,主要分为部件内依赖(图左)和部件间依赖(图右)。 + +- 部件内依赖: 现有模块module1属于部件part1,要添加一个属于部件part1的模块module2,module2依赖于module1,这种情况就属于部件内依赖。 + +- 部件间依赖: 现有模块module1属于部件part1,要添加一个模块module2,module2依赖于module1,module2属于部件part2。模块module2与模块module1分属于两个不同的部件,这种情况就属于部件间依赖。 + +- 部件内依赖示例: + + ```shell + import("//build/ohos.gni") + ohos_shared_library("module1") { + …… + part_name = "part1" # 必选,所属部件名称 + …… + } + ``` + + ```shell + import("//build/ohos.gni") + ohos_shared_library("module2") { + …… + deps = [ + "module1的gn target", + …… + ] # 部件内模块依赖 + part_name = "part1" # 必选,所属部件名称 + } + ``` + +- 部件间依赖示例: + + ```shell + import("//build/ohos.gni") + ohos_shared_library("module1") { + …… + part_name = "part1" # 必选,所属部件名称 + …… + } + ``` + + ```shell + import("//build/ohos.gni") + ohos_shared_library("module2") { + …… + external_deps = [ + "part1:module1", + …… + ] # 部件间模块依赖,这里依赖的模块必须是依赖的部件声明在inner_kits中的模块 + part_name = "part2" # 必选,所属部件名称 + } + ``` + + ![icon-note.gif](public_sys-resources/icon-note.gif)**注意**:部件间依赖要写在external_deps里面,格式为”部件名:模块名"的形式,并且依赖的模块必须是依赖的部件声明在inner_kits中的模块。 + +## 开源软件Notice收集策略说明 + +开源软件Notice是与项目开源相关的文件,收集这些文件的目的是为了符合开源的规范。 + +**收集目标** + +只收集打包到镜像里面的模块对应的License;不打包的都不收集,比如构建过程使用的工具(如clang、python、ninja等)都是不收集的。 + +静态库本身是不会被打包的,一般是作为动态库或者可执行程序的一部分被打包到系统中的,为了确保完备,静态库的都会收集。 + +最终合并的NOTICE.txt要体现出镜像中每个文件都是用了哪些License,模块和License要有对应关系。 + +最终合并的NOTICE.txt文件在/system/etc/ 目录下。 + +**收集规则** + +按照优先级收集License,以下由1到4,优先级依次降低。 + +1. 模块在BUILD.gn中直接声明自己使用的License文件,优先级最高。如下示例: + + ```shell + ohos_shared_library("example") { + ... + license_file = "path-to-license-file" + ... + } + ``` + +2. 如果模块没有显式声明,那么编译脚本会在BUILD.gn所在的当前目录中查找Readme.OpenSource文件,解析该文件,找出该文件中声明的license,将其作为模块的License。 如果Readme.OpenSource文件中配置的license文件不存在,直接报错。 + +3. 如果Readme.OpenSource文件不存在,编译脚本会从当前目录开始,向上层目录寻找(一直找到源码的根目录),默认查找License、Copyright、Notice三个文件,如果找到,则将其作为模块的License。 + +4. 如果上面三种方式都未找到license,则使用默认的license作为该模块的license;默认license是Apache2.0 License。 + +需要注意及检查的问题 + +- 三方的开源软件,比如openssl,icu等,这部分软件基本上在源码目录下都要求配置Readme.OpenSource,要检查Readme.OpenSource文件是否和BUILD.gn文件在同一个目录,以及Readme.OpenSource文件中配置的License文件是否存在以及真实有效。 +- 代码目录下,如果代码使用的不是Apache2.0 License,需要在目录下提供对应的License文件,或者直接在模块中指定license_file。 +- 如果BUILD.gn中添加的源码文件不是当前目录的,需要检查下源码文件所在仓下的license是否和BUILD.gn文件所在仓的一致。 + +## 加快本地编译的一些参数 + +编译时,适当选择添加以下的编译参数可以加快编译的过程。 + +- **添加--ccache参数**: + - 原理:ccache会缓存c/c++编译的编译输出,下一次在编译输入不变的情况下,直接复用缓存的产物。 + - 安装: + - 快速安装:执行sudo apt-get install ccache命令。 + - [官网下载](https://ccache.dev/download.html),下载二进制文件,把ccache所在路径配置到环境变量。 + - 使用:执行./build.sh --product-name 产品名 --ccache命令。 +- **添加--fast-rebuild参数** + - 原理:编译流程主要分为:preloader->loader->gn->ninja这四个过程,在本地没有修改gn和产品配置相关文件的前提下,添加--fast-rebuild会让你直接从ninja编译开始。 + - 使用:执行./build.sh --product-name 产品名 --fast-rebuild命令。 +- **添加enable_notice_collection=false参数** + - 原理:省略掉收集开源软件模块的license的过程。 + - 使用:执行./build.sh --product-name 产品名 --gn-args --enable_notice_collection=false --ccache命令。 +- **添加--build-target参数** + - 该参数用于指定编译模块,如何找模块的名字: + - 相关仓下BUILD.gn中关注group、ohos_shared_library、ohos_executable等关键字。 + - ./build.sh --product-name 产品名 --build-target 模块名 --build-only-gn生成build.ninja,然后去该文件中查找相关模块名。 + - 使用:执行./build.sh --product-name 产品名 --build-target ark_js_host_linux_tools_packages命令。 + +## 查看NinjaTrace + +out/rk3568/.ninja_log文件记录了每个模块编译的开始和结束时间(ms),结束时间和开始时间间隔越短表示模块的编译时间越短,编译性能越高。 + +从左到右分别表示:start time|end time|mtime|command hash。 + +![Ninja_Trace](figures/Ninja_Trace.png) + +图形化显示编译时间。 + +- 本地打开ninja trace: + 解压out/rk3568/build.trace.gz,将build.trace拖到chrome的trace链接chrome://tracing/打开即可。 +- 在CI网站ci.openharmony.cn/events上打开ninja trace: + CI上每个编译的输出里面有build.trace.html可直接打开,具体方法是: + 1. 点击静态检查下的“成功”; + + 2. 点击输出列的“输出”即可在左侧的build_trace列看到build.trace.html文件,单击该文件即可打开。 \ No newline at end of file diff --git a/zh-cn/device-dev/subsystems/subsys-build-standard-large.md b/zh-cn/device-dev/subsystems/subsys-build-standard-large.md deleted file mode 100644 index 8c124330eb..0000000000 --- a/zh-cn/device-dev/subsystems/subsys-build-standard-large.md +++ /dev/null @@ -1,807 +0,0 @@ -# 标准系统编译构建指导 - -## 概述 - -编译构建子系统提供了一个基于gn和ninja的编译构建框架。主要提供以下功能: - -- 构建不同芯片平台的产品。如:hispark_taurus_standard平台。 - -- 根据产品配置,按照部件组装并打包产品特性的能力。 - -### 基本概念 - -在了解编译构建子系统的能力前,应了解如下基本概念: -- 平台 - - 开发板和内核的组合,不同平台支持的子系统和部件不同。 - -- 子系统 - - OpenHarmony整体遵从分层设计,从下向上依次为:内核层、系统服务层、框架层和应用层。系统功能按照“系统 > 子系统 > 部件”逐级展开,在多设备部署场景下,支持根据实际需求裁剪某些非必要的子系统或部件。子系统是一个逻辑概念,它具体由对应的部件构成。 - -- 部件 - - 对子系统的进一步拆分,可复用的软件单元,它包含源码、配置文件、资源文件和编译脚本;能独立构建,以二进制方式集成,具备独立验证能力的二进制单元。 - -- gn - - Generate ninja的缩写,用于产生ninja文件。 - -- ninja - - ninja是一个专注于速度的小型构建系统。 - -### 运作机制 - -OpenHarmony侧的编译构建流程主要包括编译命令行解析,调用gn,执行ninja: - -- 命令行解析:解析待编译的产品名称,加载相关配置。 - -- 调用gn: 根据命令行解析的产品名称和编译类型,配置编译工具链和全局的编译选项。 - -- 执行ninja:启动编译并生成对应的产品版本。 - -### 约束与限制 - -- 需按照[源码获取](../get-code/sourcecode-acquire.md)指导下载全量源码(采用方式三获取)。 - -- 编译环境需要Ubuntu18.04及以上版本。 - -- 安装编译所需的程序包。 - 安装命令: - - ``` - # 推荐使用脚本,在家目录执行 - # ./build/build_scripts/env_setup.sh - # 不要用root执行,会将环境变量加到root。如果你的sheel不是bash或者zsh,执行完还需要你手动配置以下内容到你的环境变量中,cd ~到你用户家目录查看隐藏文件能显示你的用户环境变量文件。 - # export PATH=/home/tools/llvm/bin:$PATH - # export PATH=/home/tools/hc-gen:$PATH - # export PATH=/home/tools/gcc_riscv32/bin:$PATH - # export PATH=/home/tools/ninja:$PATH - # export PATH=/home/tools/node-v12.20.0-linux-x64/bin:$PATH - # export PATH=/home/tools/gn:$PATH - # export PATH=/root/.local/bin:$PATH - - # 如果不用脚本执行,则需要安装以下内容 - apt-get update -y - apt-get install -y apt-utils binutils bison flex bc build-essential make mtd-utils gcc-arm-linux-gnueabi u-boot-tools python3.9.2 python3-pip git zip unzip curl wget gcc g++ ruby dosfstools mtools default-jre default-jdk scons python3-distutils perl openssl libssl-dev cpio git-lfs m4 ccache zlib1g-dev tar rsync liblz4-tool genext2fs binutils-dev device-tree-compiler e2fsprogs git-core gnupg gnutls-bin gperf lib32ncurses5-dev libffi-dev zlib* libelf-dev libx11-dev libgl1-mesa-dev lib32z1-dev xsltproc x11proto-core-dev libc6-dev-i386 libxml2-dev lib32z-dev libdwarf-dev - apt-get install -y grsync xxd libglib2.0-dev libpixman-1-dev kmod jfsutils reiserfsprogs xfsprogs squashfs-tools pcmciautils quota ppp libtinfo-dev libtinfo5 libncurses5 libncurses5-dev libncursesw5 libstdc++6 python2.7 gcc-arm-none-eabi vim ssh locales doxygen - # python需要安装以下模块 - chmod +x /usr/bin/repo - pip3 install --trusted-host https://repo.huaweicloud.com -i https://repo.huaweicloud.com/repository/pypi/simple requests setuptools pymongo kconfiglib pycryptodome ecdsa ohos-build pyyaml prompt_toolkit==1.0.14 redis json2html yagmail python-jenkins - pip3 install esdk-obs-python --trusted-host pypi.org - pip3 install six --upgrade --ignore-installed six - #还需要安装llvm,hc-gen,gcc_riscv32,ninja,node-v14.15.4-linux-x64,gn并将上述shell环境非bash或者zsh的配置内容导入到你用户的环境变量中 - ``` - - - -## 编译构建使用指导 - -### 目录结构 - -``` - -/build # 编译构建主目录 - -├── __pycache__ -├── build_scripts/ # 编译相关的python脚本 -├── common/ -├── config/ # 编译相关的配置项 -├── core -│ ├── gn/ # 编译入口BUILD.gn配置 - └── build_scripts/ -├── docs -gn_helpers.py* -lite/ # hb和preloader入口 -misc/ -├── ohos # OpenHarmony编译打包流程配置 -│ ├── kits # kits编译打包模板和处理流程 -│ ├── ndk # ndk模板和处理流程 -│ ├── notice # notice模板和处理流程 -│ ├── packages # 版本打包模板和处理流程 -│ ├── sa_profile # sa模板和处理流程 -│ ├── sdk # sdk模板和处理流程,包括sdk中包含的模块配置 -│ └── testfwk # 测试相关的处理 -├── ohos.gni* # 汇总了常用的gni文件,方便各个模块一次性import -├── ohos_system.prop -├── ohos_var.gni* -├── prebuilts_download.sh* -├── print_python_deps.py* -├── scripts/ -├── subsystem_config.json -├── subsystem_config_example.json -├── templates/ # c/c++编译模板定义 -├── test.gni* -├── toolchain # 编译工具链配置 -├── tools # 常用工具 -├── version.gni -├── zip.py* - - -``` - -### 编译命令 - -- 代码根目录下执行全量版本的编译命令: - - ``` - - ./build.sh --product-name {product_name} - - ``` - - {product_name}为当前版本支持的平台。比如:hispark_taurus_standard等。 - - 编译完成后,结果镜像保存在 out/{device_name}/packages/phone/images/ 目录下。 - -- 编译命令支持选项:./build.sh -h - - ``` - -h, --help # 显示帮助信息并退出 - --source-root-dir=SOURCE_ROOT_DIR # 指定路径 - --product-name=PRODUCT_NAME # 指定产品名 - --device-name=DEVICE_NAME # 指定装置名称 - --target-cpu=TARGET_CPU # 指定cpu - --target-os=TARGET_OS # 指定操作系统 - -T BUILD_TARGET, --build-target=BUILD_TARGET # 指定编译目标,可以指定多个 - --gn-args=GN_ARGS # gn参数,支持指定多个 - --ninja-args=NINJA_ARGS # ninja参数,支持指定多个 - -v, --verbose # 生成时显示所有命令行 - --keep-ninja-going # 让ninja持续到1000000个工作失败 - --sparse-image - --jobs=JOBS - --export-para=EXPORT_PARA - --build-only-gn # 只做gn解析,不运行ninja - --ccache # 可选 编译使用ccache,需要本地安装ccache - --fast-rebuild # 快速重建,default=False - --log-level=LOG_LEVEL # 指定编译期间的日志级别','三个级别可选:debug, info and error,default='info' - --device-type=DEVICE_TYPE # 指定设备类型,default='default' - --build-variant=BUILD_VARIANT # 指定设备操作模式,default='user' - - ``` - -### 开发步骤 - -1. 添加部件。 - 本节以添加一个自定义的部件为例,描述如何编译部件,编译库、编译可执行文件等。 - - 示例部件partA由feature1、feature2和feature3组成,feature1的编译目标为一个动态库,feature2的目标为一个可执行程序,feature3的目标为一个etc配置文件。 - - 示例部件partA的配置需要添加到一个子系统中,本次示例将添加到subsystem_examples子系统中(subsystem_examples子系统定义在test/examples/目录)。 - - 示例部件partA的完整目录结构如下: - - ``` - - test/examples/partA - ├── feature1 - │ ├── BUILD.gn - │ ├── include - │ │ └── helloworld1.h - │ └── src - │ └── helloworld1.cpp - ├── feature2 - │ ├── BUILD.gn - │ ├── include - │ │ └── helloworld2.h - │ └── src - │ └── helloworld2.cpp - └── feature3 - ├── BUILD.gn - └── src - └── config.conf - - ``` - - 示例1:编写动态库gn脚本test/examples/partA/feature1/BUILD.gn,示例如下: - - ``` - - config("helloworld_lib_config") { - include_dirs = [ "include" ] - } - - ohos_shared_library("helloworld_lib") { - sources = [ - "include/helloworld1.h", - "src/helloworld1.cpp", - ] - public_configs = [ ":helloworld_lib_config" ] - part_name = "partA" - } - - ``` - - 示例2:编写可执行文件gn脚本test/examples/partA/feature2/BUILD.gn,示例如下: - - ``` - - ohos_executable("helloworld_bin") { - sources = [ - "src/helloworld2.cpp" - ] - include_dirs = [ "include" ] - deps = [ # 依赖部件内模块 - "../feature1:helloworld_lib" - ] - external_deps = [ "partB:module1" ] # (可选)如果有跨部件的依赖,格式为“部件名:模块名” - install_enable = true # 可执行程序缺省不安装,需要安装时需要指定 - part_name = "partA" - } - - ``` - - 示例3:编写etc模块gn脚本test/examples/partA/feature3/BUILD.gn,示例如下: - - ``` - - ohos_prebuilt_etc("feature3_etc") { - source = "src/config.conf" - relative_install_dir = "init" #可选,模块安装相对路径,相对于默认安装路径;默认在/system/etc目录 - part_name = "partA" - } - - ``` - - 示例4:在部件的bundle.json中添加模块配置:test/examples/bundle.json。每个部件都有一个bundle.json配置文件,在部件的根目录下。示例如下: - - ``` - { - "name": "@ohos/", # HPM部件英文名称,格式"@组织/部件名称" - "description": "xxxxxxxxxxxxxxxxxxx", # 部件功能一句话描述 - "version": "3.1", # 版本号,版本号与OpenHarmony版本号一致 - "license": "MIT", # 部件License - "publishAs": "code-segment", # HPM包的发布方式,当前默认都为code_segment - "segment": { - "destPath": "" - }, # 发布类型为code_segment时为必填项,定义发布类型code_segment的代码还原路径(源码路径) - "dirs": {}, # HPM包的目录结构,字段必填内容可以留空 - "scripts": {}, # HPM包定义需要执行的脚本,字段必填,值非必填 - "licensePath": "COPYING", # 指定该模块的版权申明路径 - "readmePath": { - "en": "README.rst" - }, # 该模块的reademe.opensource的路径 - "component": { # 部件属性 - "name": "", # 部件名称 - "subsystem": "", # 部件所属子系统 - "syscap": [], # 部件为应用提供的系统能力 - "features": [], # 部件对外的可配置特性列表,一般与build中的sub_component对应,可供产品配置 - "adapted_system_type": [], # 轻量(mini)小型(small)和标准(standard),可以是多个 - "rom": "xxxKB", # ROM基线,没有基线写当前值 - "ram": "xxxKB", # RAM基线,没有基线写当前值 - "deps": { - "components": [], # 部件依赖的其他部件 - "third_party": [] # 部件依赖的三方开源软件 - }, - "build": { # 编译相关配置 - "sub_component": [], # 部件编译入口,模块在此处配置 - "inner_kits": [], # 部件间接口 - "test": [] # 部件测试用例编译入口 - } - } - } - ``` - -2. 将部件添加到产品配置中。 - 在产品的配置中添加部件,产品对应的配置文件://vendor/{product_company}/{product-name}/config.json。 - - 在产品配置文件中添加 "subsystem_examples:partA",表示该产品中会编译并打包partA到版本中。 - -3. 编译。 - 以编译hispark_taurus_standard为例,编译命令如下: - - ``` - - ./build.sh --product-name hispark_taurus_standard --ccache - - ``` - -4. 编译输出。 - 编译所生成的文件都归档在out/hispark_taurus/目录下,结果镜像输出在 out/hispark_taurus/packages/phone/images/ 目录下。 - -## 常见问题 - -### 如何将一个模块编译并打包到版本中? - -- 模块要指定part_name,指定它归属的部件,一个模块只能属于一个部件; - -- 部件的模块,要在部件配置的component.build.sub_component中,或者可以被component.build.sub_component中的模块依赖到; - -- 部件要加到对应产品的部件列表中。 - -### 关于deps、external_deps的使用 - -在添加一个模块的时候,需要在BUILD.gn中声明它的依赖,为了便于后续处理部件间依赖关系,我们将依赖分为两种——部件内依赖deps和部件间依赖external_deps。 - -### 依赖分类: - -- 1.部件内依赖: 现有模块module1属于部件part1,要添加一个属于部件part1的模块module2,module2依赖于module1,这种情况就属于部件内依赖。 - -- 2.部件间依赖: 现有模块module1属于部件part1,要添加一个模块module2,module2依赖于module1,module2属于部件part2。模块module2与模块module1分属于两个不同的部件,这种情况就属于部件间依赖。 - -- 部件内依赖示例: - - ``` - import("//build/ohos.gni") - ohos_shared_library("module1") { - …… - part_name = "part1" # 必选,所属部件名称 - …… - } - ``` - - ``` - import("//build/ohos.gni") - ohos_shared_library("module2") { - …… - deps = [ - "module1的gn target", - …… - ] # 部件内模块依赖 - part_name = "part1" # 必选,所属部件名称 - } - ``` - -- 部件间依赖示例: - - ``` - import("//build/ohos.gni") - ohos_shared_library("module1") { - …… - part_name = "part1" # 必选,所属部件名称 - …… - } - ``` - -- 模块1所属部件的bundle.json文件 - - ``` - { - "name": "@ohos/", # HPM部件英文名称,格式"@组织/部件名称" - "description": "xxxxxxxxxxxxxxxx", # 部件功能一句话描述 - "version": "3.1", # 版本号,版本号与OpenHarmony版本号一致 - "license": "MIT", # 部件License - "publishAs": "code-segment", # HPM包的发布方式,当前默认都为code_segment - "segment": { - "destPath": "" - }, # 发布类型为code_segment时为必填项,定义发布类型code_segment的代码还原路径(源码路径) - "dirs": {}, # HPM包的目录结构,字段必填内容可以留空 - "scripts": {}, # HPM包定义需要执行的脚本,字段必填,值非必填 - "licensePath "licensePath": "COPYING", - ": "COPYING", - "readmePath": { - "en": "README.rst" - }, - "component": { # 部件属性 - "name": "", # 部件名称 - "subsystem": "", # 部件所属子系统 - "syscap": [], # 部件为应用提供的系统能力 - "features": [], # 部件对外的可配置特性列表,一般与build中的sub_component对应,可供产品配置 - "adapted_system_type": [], # 轻量(mini)小型(small)和标准(standard),可以是多个 - "rom": "xxxKB" # ROM基线,没有基线写当前值 - "ram": "xxxKB", # RAM基线,没有基线写当前值 - "deps": { - "components": [], # 部件依赖的其他部件 - "third_party": [] # 部件依赖的三方开源软件 - }, - "build": { # 编译相关配置 - "sub_component": ["part1"], # 部件编译入口,部件所有模块在此列表 - "inner_kits": [ # 部件间接口 - { - "header": { - "header_base": "头文件所属目录", # 头文件所属目录 - "header_files": [ - "头文件名" - ] # 头文件名列表 - }, - "name": "module1的gn target" - }, - ], - "test": [] # 部件测试用例编译入口 - } - } - } - ``` - - ``` - import("//build/ohos.gni") - ohos_shared_library("module2") { - …… - external_deps = [ - "part1:module1", - …… - ] # 部件间模块依赖,这里依赖的模块必须是依赖的部件声明在inner_kits中的模块 - part_name = "part2" # 必选,所属部件名称 - } - - ``` - -> ![icon-caution.gif](public_sys-resources/icon-caution.gif) **注意:** -> 部件间依赖要写在external_deps里面,格式为”部件名:模块名"的形式,并且依赖的模块必须是依赖的部件声明在inner_kits中的模块。 - - - - - -### 标准系统如何添加一个模块 - -要添加的模块可以分为以下三种情况,对原有的配置文件进行不同程度的修改。 - -- 在原有部件中添加一个模块 - -- 新建部件并在其中添加模块 - -- 新建子系统并在该子系统的部件下添加模块 - -**在原有部件中添加一个模块** - -1. 在模块目录下配置BUILD.gn,根据类型选择对应的模板。 - 这一步与在原有部件中添加一个模块的方法基本一致,只需注意该模块对应BUILD.gn文件中的part_name为新建部件的名称即可。 - -2. 修改bundle.json配置文件。"部件包含模块的gn目标" - - ``` - { - "name": "@ohos/", # HPM部件英文名称,格式"@组织/部件名称" - "description": "xxxxxxxxxxxxxxxxxxx", # 部件功能一句话描述 - "version": "3.1", # 版本号,版本号与OpenHarmony版本号一致 - "license": "MIT", # 部件License - "publishAs": "code-segment", # HPM包的发布方式,当前默认都为code_segment - "segment": { - "destPath": "third_party/nghttp2" - }, # 发布类型为code_segment时为必填项,定义发布类型code_segment的代码还原路径(源码路径) - "dirs": {}, # HPM包的目录结构,字段必填内容可以留空 - "scripts": {}, # HPM包定义需要执行的脚本,字段必填,值非必填 - "licensePath": "COPYING", - "readmePath": { - "en": "README.rst" - }, - "component": { # 部件属性 - "name": "", # 部件名称 - "subsystem": "", # 部件所属子系统 - "syscap": [], # 部件为应用提供的系统能力 - "features": [], # 部件对外的可配置特性列表,一般与build中的sub_component对应,可供产品配置 - "adapted_system_type": [], # 轻量(mini)小型(small)和标准(standard),可以是多个 - "rom": "xxxKB" # ROM基线,没有基线写当前值 - "ram": "xxxKB", # RAM基线,没有基线写当前值 - "deps": { - "components": [], # 部件依赖的其他部件 - "third_party": [] # 部件依赖的三方开源软件 - }, - - "build": { # 编译相关配置 - "sub_component": [ - "//foundation/arkui/napi:napi_packages", # 原有模块1 - "//foundation/arkui/napi:napi_packages_ndk" # 原有模块2 - "//foundation/arkui/napi:new" # 新增模块new - ], # 部件编译入口,模块在此处配置 - "inner_kits": [], # 部件间接口 - "test": [] # 部件测试用例编译入口 - } - } - } - ``` - - 注意无论哪种方式该bundle.json文件均在对应子系统所在文件夹下。 - -**新建部件并在其中添加一个模块** - -1. 在模块目录下配置BUILD.gn,根据类型选择对应的模板。这一步与新建部件并在其中添加模块中对应的步骤并无区别。 - -2. 新建一个bundle.json文件,bundle.json文件均在对应子系统所在文件夹下。bundle.json文件包含两个部分,第一部分subsystem说明了子系统的名称,parts定义了该子系统包含的部件,要添加一个部件,需要把该部件对应的内容添加进parts中去。添加的时候需要指明该部件包含的模块sub_component,假如有提供给其它部件的接口,需要在inner_kits中说明,假如有测试用例,需要在test中说明,inner_kits与test没有也可以不添加。 - -2. 在//vendor/{product_company}/{product-name}/config.json中添加对应的部件,直接添加到原有部件后即可。 - - ``` - "subsystems": [ - { - "subsystem": "部件所属子系统名", - "components": [ - { "component": "部件名1", "features":[] }, # 子系统下的原有部件1 - { "component": "部件名2", "features":[] }, # 子系统下的原有部件2 - { "component": "部件名new", "features":[] } # 子系统下的新增部件new - ] - }, - ....... - ] - ``` - -**新建子系统并在该子系统的部件下添加模块** - -1. 在模块目录下配置BUILD.gn,根据类型选择对应的模板。这一步与新建部件并在其中添加模块中对应的步骤并无区别。 - -2. 在新建的子系统目录下每个部件对应的文件夹下创建bundle.json文件,定义部件信息。这一步与新建部件并在其中添加模块中对应的步骤并无区别。 - -3. 修改build目录下的subsystem_config.json文件。 - - ``` - { - "子系统名1": { # 原有子系统1 - "path": "子系统目录1", - "name": "子系统名1" - }, - "子系统名2": { # 原有子系统2 - "path": "子系统目录2", - "name": "子系统名2" - }, - "子系统名new": { # 新增子系统new - "path": "子系统目录new", - "name": "子系统名new" - }, - ... - } - ``` - - 该文件定义了有哪些子系统以及这些子系统所在文件夹路径,添加子系统时需要说明子系统path与name,分别表示子系统路径和子系统名。 - -4. 在//vendor/{product_company}/{product-name}目录下的产品配置如product-name是hispark_taurus_standard时,在config.json中添加对应的部件,直接添加到原有部件后即可。 - - ``` - "subsystems": [ - { - "subsystem": "arkui", # 原有的子系统名 - "components": [ # 单个子系统下的所有部件集合 - { - "component": "ace_engine_standard", # 原有的部件名 - "features": [] - }, - { - "component": "napi", # 原有的部件名 - "features": [] - } - { - "component": "component_new1", # 原有子系统新增的的部件名component_new1 - "features": [] - } - ] - }, - { - "subsystem": "subsystem_new", # 新增的子系统名 - "components": [ - { - "component": "component_new2", # 新增子系统新增的的部件名component_new2 - "features": [] - } - ] - }, - ... - ] - ``` - 成功添加验证: - - 在输出文件夹的对应子系统文件夹下的部件文件夹下的BUILD.gn文件中module_list包含了新建模块的BUILD.gn中定义的目标。 - - 编译完成后打包到image中去,生成对应的so文件或者二进制文件。 - -**配置文件说明** - -OpenHarmony的配置文件主要有四个。 - -1. vendor\产品厂商\产品名\config.json - - ``` - { - "product_name": "MyProduct", - "version": "3.0", - "type": "standard", - "target_cpu": "arm", - "ohos_version": "OpenHarmony 1.0", - "device_company": "MyProductVendor", - "board": "MySOC", - "enable_ramdisk": true, - "subsystems": [ - { - "subsystem": "ace", - "components": [ - { "component": "ace_engine_lite", "features":[""] } - ] - }, - ... - ] - } - - ``` - 指明了产品名,产品厂商,产品设备,版本,要编译的系统类型,以及产品包含的子系统。 - -2. build目录下的subsystem_config.json文件。 - - ``` - { - "arkui": { - "path": "foundation/arkui", - "name": "arkui" - }, - "ai": { - "path": "foundation/ai", - "name": "ai" - }, - ...... - } - ``` - 该文件对子系统进行了说明,我们需要该子系统定义中的name与path,分别表示子系统的名称和所在文件夹路径。 - -3. 子系统中bundle.json文件。 - - ``` - { - "name": "@ohos/", # HPM部件英文名称,格式"@组织/部件名称" - "description": "xxxxxxxxxxxxxxxxxxx", # 部件功能一句话描述 - "version": "3.1", # 版本号,版本号与OpenHarmony版本号一致 - "license": "MIT", # 部件License - "publishAs": "code-segment", # HPM包的发布方式,当前默认都为code_segment - "segment": { - "destPath": "" - }, # 发布类型为code_segment时为必填项,定义发布类型code_segment的代码还原路径(源码路径) - "dirs": {}, # HPM包的目录结构,字段必填内容可以留空 - "scripts": {}, # HPM包定义需要执行的脚本,字段必填,值非必填 - "licensePath": "COPYING", - "readmePath": { - "en": "README.rst" - }, - "component": { # 部件属性 - "name": "", # 部件名称 - "subsystem": "", # 部件所属子系统 - "syscap": [], # 部件为应用提供的系统能力 - "features": [], # 部件对外的可配置特性列表,一般与build中的sub_component对应,可供产品配置 - "adapted_system_type": [], # 轻量(mini)小型(small)和标准(standard),可以是多个 - "rom": "xxxKB" # ROM基线,没有基线写当前值 - "ram": "xxxKB", # RAM基线,没有基线写当前值 - "deps": { - "components": [], # 部件依赖的其他部件 - "third_party": [] # 部件依赖的三方开源软件 - }, - "build": { # 编译相关配置 - "sub_component": ["部件包含模块的gn目标"], # 部件编译入口 - "inner_kits": [], # 部件间接口 - "test": [] # 部件测试用例编译入口 - } - } - } - ``` - bundle.json文件定义了子系统包含的部件。 - - 每个部件定义它所包含的模块目标component.build.sub_component,以及部件间交互的接口component.build.inner_kits,测试用例component.build.test_list。部件包含的 - 模块目标component.build.sub_component是必须要说明的。 - -4. 每个模块对应的BUILD.gn文件。 - 可以使用提供的模板,也可以使用gn语法规则自定义编写。 - -### hap的编译 - -**hap包的构成** - -OpenHarmony上的hap包由资源,raw assets,js assets,native库,config.json等部分构成。 - -**编译系统提供的模板** - -编译系统提供了4个模板,用来编译hap包。 - -模板集成在ohos.gni中,使用之前需要引用build/ohos.gni - -ohos_resources - -- 声明一个资源目标。资源目标被restool编译之后会生成index文件,hap中会打包资源源文件和index文件。 - -- 该目标会同时生成资源编译后的ResourceTable.h,直接依赖该目标就可以引用该头文件 - -- 资源目标的目标名必须以"resources"或"resource"或"res"结尾,否则编译检查时会报错 - -- 支持的变量: - - 1. sources: 资源的路径,变量类型是list,可以写多个路径 - 2. hap_profile: 编译资源时需要提供对应hap包的config.json - 3. deps: 当前目标的依赖,可选 - -ohos_assets - -- 声明一个资产目标 - -- 注意拼写:assets不是assert - -- assets目标的目标名必须以"assets"或"asset"结尾 - -- 支持的变量: - - 1. sources:raw assets所在路径,变量类型是list,可以写多个路径 - 2. deps: 当前目标的依赖,可选 - -ohos_js_assets - -- 声明一个JS 资源目标,JS资源是L2 hap包的可执行部分 - -- JS assets目标的目标名必须以"assets"或"asset"结尾 - -- 支持的变量: - - 1. source_dir: JS 资源的路径,变量类型是string,只能写一个 - 2. deps: 当前目标的依赖,可选 - -ohos_hap - -- 声明一个hap目标,该目标会生成一个hap包,最终将会打包到system镜像中 - -- 支持的变量: - - 1. hap_profile: hap包的config.json - 2. deps: 当前目标的依赖 - 3. shared_libraries: 当前目标依赖的native库 - 4. hap_name: hap包的名字,可选,默认为目标名 - 5. final_hap_path: 用户可以制定生成的hap的位置,可选,final_hap_path中会覆盖hap_name - 6. subsystem_name: hap包从属的子系统名,需要和bundle.json中的名字对应,否则将导致无法安装到system镜像中 - 7. part_name: hap包从属的部件名,同subsystem_name - 8. js2abc: 是否需要将该hap包转换为ARK的字节码 - 签名篇见:[配置应用签名]( https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ohos-debugging-and-running-0000001263040487#section17660437768) - 9. certificate_profile: hap对应的授权文件,用于签名 - 10. certificate_file: 证书文件,证书文件和授权文件,应用开发者需要去openharmony官网申请 - 11. keystore_path: keystore文件,用于签名 - 12. keystore_password: keystore的密码,用于签名 - 13. key_alias: key的别名 - 14. module_install_name:安装时的hap包名称 - 15. module_install_dir: 安装到system中的位置,默认安装在system/app目录下 - - **hap开发示例** - - ``` - import("//build/ohos.gni") # 引用ohos.gni - ohos_hap("clock") { - hap_profile = "./src/main/config.json" # config.json - deps = [ - ":clock_js_assets", # JS assets - ":clock_resources", # 资源 - ] - shared_libraries = [ - "//third_party/libpng:libpng", # native库 - ] - certificate_profile = "../signature/systemui.p7b" # Cer文件 - hap_name = "SystemUI-NavigationBar" # 名字 - part_name = "prebuilt_hap" - subsystem_name = "applications" - } - ohos_js_assets("clock_js_assets") { - source_dir = "./src/main/js/default" - } - ohos_resources("clock_resources") { - sources = [ "./src/main/resources" ] - hap_profile = "./src/main/config.json" - } - ``` - -### 开源软件Notice收集策略说明 - -**收集目标** - -只收集打包到镜像里面的模块对应的License;不打包的都不收集,比如构建过程使用的工具(如clang/python/ninja等)。 - -静态库本身是不会被打包的,一般是作为动态库或者可执行程序的一部分被打包到系统中的,为了确保完备,静态库的都会收集。 - -最终合并的NOTICE.txt要体现出镜像中每个文件都是用了哪些License,模块和License要有对应关系。 - -最终合并的NOTICE.txt文件在/system/etc/ 目录下。 - -**收集规则** - -按照优先级收集License - -1. 模块在BUILD.gn中直接声明自己使用的License文件,优先级最高。如下图示例: - - ``` - ohos_shared_library("example") { - ... - license_file = "path-to-license-file" - ... - } - ``` - -2. 如果模块没有显式声明,那么编译脚本会在BUILD.gn所在的当前目录中查找Readme.OpenSource文件,解析该文件,找出该文件中声明的license,将其作为模块的License。 - 如果Readme.OpenSource文件中配置的license文件不存在,直接报错。 - -3. 如果Readme.OpenSource文件不存在,编译脚本会从当前目录开始,向上层目录寻找(一直找到源码的根目录),默认查找License/Copyright/Notice三个文件,如果找到,则将其作为模块的License。 - -4. 如果上面三种方式都未找到license,则使用默认的license作为该模块的license;默认license是Apache2.0 License。 - -需要注意及检查的问题 - -1. 三方的开源软件,比如openssl,icu等,这部分软件基本上在源码目录下都是要求配置Readme.OpenSource,要检查Readme.OpenSource文件是否和BUILD.gn文件在同一个目录,以及Reame.OpenSource文件中配置的License文件是否存在以及真是有效。 - -2. 代码目录下,如果代码使用的不是Apache2.0 License,需要在目录下提供对应的License文件,或者直接在模块中指定license_file。 - -3. 如果BUILD.gn中添加的源码文件不是当前目录的,需要检查下源码文件所在仓下的license是否和BUILD.gn文件所在仓的一致,不一致的需要处理。 \ No newline at end of file diff --git a/zh-cn/device-dev/subsystems/subsys-build-subsystem.md b/zh-cn/device-dev/subsystems/subsys-build-subsystem.md new file mode 100644 index 0000000000..6314ee0bd6 --- /dev/null +++ b/zh-cn/device-dev/subsystems/subsys-build-subsystem.md @@ -0,0 +1,32 @@ +# 子系统 +### 子系统配置规则 + +通过build仓下的subsystem_config.json可以查看所有子系统的配置规则。 + +```json +{ + "arkui": { + "path": "foundation/arkui", # 路径 + "name": "arkui" # 子系统名 + }, + "ai": { + "path": "foundation/ai", + "name": "ai" + }, + "account": { + "path": "base/account", + "name": "account" + }, + "distributeddatamgr": { + "path": "foundation/distributeddatamgr", + "name": "distributeddatamgr" + }, + "security": { + "path": "base/security", + "name": "security" + }, + ... +} +``` + +子系统的配置规则主要是在build/subsystem_config.json中指定子系统的路径和子系统名称。 diff --git a/zh-cn/device-dev/subsystems/subsys-build.md b/zh-cn/device-dev/subsystems/subsys-build.md index 1652a6cf1a..e617d4d7af 100644 --- a/zh-cn/device-dev/subsystems/subsys-build.md +++ b/zh-cn/device-dev/subsystems/subsys-build.md @@ -2,8 +2,17 @@ -- **[轻量和小型系统编译构建指导](subsys-build-mini-lite.md)** -- **[标准系统编译构建指导](subsys-build-standard-large.md)** + +- **[编译构建指导](subsys-build-all.md)** +- **[产品](subsys-build-product.md)** +- **[子系统](subsys-build-subsystem.md)** +- **[部件](subsys-build-component.md)** +- **[模块](subsys-build-module.md)** +- **[芯片解决方案](subsys-build-chip_solution.md)** +- **[特性](subsys-build-feature.md)** +- **[HAP编译构建指导](subsys-build-gn-hap-compilation-guide.md)** - **[构建系统编码规范与最佳实践](subsys-build-gn-coding-style-and-best-practice.md)** - **[编译构建Kconfig可视化配置指导](subsys-build-gn-kconfig-visual-config-guide.md)** +- **[参考信息](subsys-build-reference.md)** +- **[FAQ](subsys-build-faq.md)** -- GitLab