研究目标
- 定位编译核心节点代码,利于自定义脚本辅助工程应用开发
- 加深对当前应用工程的目录结构使用的理解
预备知识
- 了解HarmonyOS应用开发
- 了解HarmonyOS应用的工程目录结构
- 了解HSP,HAR,HAP概念
- 见过hvigor和hvigor-ohos-plugin
试验环境
- MacBook Pro: Apple M1
- DevEco Studio 3.1.1 Release
- HarmonyOS SDK API 9
- hvigor版本: 2.4.2
- hvigor-ohos-plugin版本: 2.4.2
编译方式
HarmonyOS应用编译有两种方式:1. 通过DevEco Studio菜单 2. 通过脚本命令。
这两种方式最终都是通过启动 "@ohos/hvigor" 包中的index.js来完成操作的。
当前hvigor暂不支持全局命令行工具,依赖工程中的hvigorw工具。
命令运行时的参数:
- 官方在【'更新时间: 2024-03-30 10:25' "hvigor命令行"】 这篇文章中针对命令中的参数有所描述【文档对参数描述极少,不推荐】
- 通过运行 hvigorw 脚本,添加'--help'也可以看到相关参数的使用方法【推荐使用此种方式查看】
命令编译格式
./hvigorw [taskNames...] <options>
less
Options:
-v, --version 查看hvigor版本号
-e, --error 输出错误日志
-w, --warn 输出警告日志
-i, --info 输出信息日志
-d, --debug 输出调试日志
--stacktrace 输出所有堆栈信息
-p, --prop <value> 定义额外属性
-m, --mode <string> 指定编译范围: project, module
-s, --sync 同步插件信息
--enable-build-script-type-check 启用生成脚本hvigorfile.ts类型检查
--no-parallel 禁止并行编译
--no-incremental 禁止增量编译
--no-daemon 禁用守护进程
--stop-daemon 关闭当前工程的守护进程
--stop-daemon-all 关闭所有工程的守护进程
--status-daemon 展示工程中所有守护进程的状态
-h, --help 查看命令的使用方法
makefile
Commands:
version 显示Hvigor版本号
tasks 显示所有模块任务
taskTree 以树状形式,显示所有模块任务
命令编译演示
首先进入到应用工程根目录下(通过DevEco 中的Terminal可以直接进入到根目录)
查看 hvigor 版本号
以下命令任意一个均可以
sh hvigorw -v
sh hvigorw --version
sh hvigorw version
查看工程任务
sh hvigorw tasks
命令结果展示了HarmonyOS应用编译时,可以提供的服务类型.
任务分类
- Help tasks
- Other tasks
- hook tasks
- Sync tasks
hvigor将应用工程按照"应用","模块"划分方式来执行所有类型的任务分类。这一点从 "sh hvigorw tasks"和正常编译时的日志可以推测出来。
"sh hvigorw tasks"命令结果的结构如下
当前演示的应用工程共有3个模块:
- entry
- harlibrary
- hsplibrary
sql
--------------------------------------------------------------------------
All tasks from hvigor node 'entry' <= 模块'entry'
--------------------------------------------------------------------------
Help tasks <= tasks和taskTree为任务名称,即"命令编译格式"中的taskName
-------------
tasks - Displays the tasks of the HvigorNode.
taskTree - Displays the task dag tree of the HvigorNode.
Other tasks <= clean,default@PreBuild, ...为任务名称,即"命令编译格式"中的taskName
-------------
clean
PreviewBuild
buildHotReloadResource
HotReloadBuild
default@PreBuild
default@MergeProfile - Merge app config manifest files.
default@BuildNativeWithCmake - Compile cpp source with Cmake.
default@BuildNativeWithNinja - Compile cpp source with Ninja.
default@MakePackInfo - Generate module pack.info.
default@ProcessLibs
default@GenerateMetadata
default@ProcessProfile - Process app config manifest file
default@ProcessResource
default@GenerateLoaderJson - Generate loader.json.
default@CompileResource - Compile project resource.
default@CompileArkTS - Compile ArkTS components for rich device in Stage Mode.
default@CompileJS - Compile ArkTS or JS components using Node.js for rich device in Stage Mode.
default@PackageHap - Build the Hap package.
default@SignHap
default@PreviewHookCompileResource
default@ReplacePreviewerPage
default@PreviewUpdateAssets - Update main_pages.json and module.json before PreviewBuild.
default@PreviewArkTS
default@HotReloadArkTS
hook tasks
-------------
compileNative
assembleHap
buildPreviewerResource
Sync tasks
-------------
init
> hvigor Finished :entry:tasks... after 1 ms
--------------------------------------------------------------------------
All tasks from hvigor node 'harlibrary' <= 模块'harlibrary'
--------------------------------------------------------------------------
Help tasks
-------------
tasks - Displays the tasks of the HvigorNode.
taskTree - Displays the task dag tree of the HvigorNode.
Other tasks
-------------
clean
PreviewBuild
default@PreBuild
default@BuildNativeWithCmake - Compile cpp source with Cmake.
default@BuildNativeWithNinja - Compile cpp source with Ninja.
default@MergeProfile - Merge app config manifest files.
default@ProcessProfile - Process app config manifest file
default@ProcessResource
default@ProcessLibs
default@CompileResource - Compile project resource.
default@PackageHar - Build the har package.
default@GenerateLoaderJson - Generate loader.json.
default@PreviewHookCompileResource
default@PreviewUpdateAssets - Update main_pages.json and module.json before PreviewBuild.
default@PreviewArkTS
hook tasks
-------------
compileNative
assembleHar
buildPreviewerResource
Sync tasks
-------------
init
> hvigor Finished :harlibrary:tasks... after 1 ms
--------------------------------------------------------------------------
All tasks from hvigor node 'hsplibrary' <= 模块'hsplibrary'
--------------------------------------------------------------------------
Help tasks
-------------
tasks - Displays the tasks of the HvigorNode.
taskTree - Displays the task dag tree of the HvigorNode.
Other tasks
-------------
clean
buildHotReloadResource
PreviewBuild
HotReloadBuild
default@PreBuild
default@MergeProfile - Merge app config manifest files.
default@BuildNativeWithCmake - Compile cpp source with Cmake.
default@BuildNativeWithNinja - Compile cpp source with Ninja.
default@MakePackInfo - Generate module pack.info.
default@ProcessLibs
default@GenerateMetadata
default@ProcessProfile - Process app config manifest file
default@ProcessResource
default@GenerateLoaderJson - Generate loader.json.
default@CompileResource - Compile project resource.
default@CompileArkTS - Compile ArkTS components for rich device in Stage Mode.
default@CompileJS - Compile ArkTS or JS components using Node.js for rich device in Stage Mode.
default@PackageHsp - Build the Hsp package.
default@PrepareSharedHarResource
default@SignHsp
default@PackageSharedHar
default@PreviewHookCompileResource
default@ReplacePreviewerPage
default@PreviewUpdateAssets - Update main_pages.json and module.json before PreviewBuild.
default@PreviewArkTS
default@HotReloadArkTS
hook tasks
-------------
compileNative
assembleHsp
buildPreviewerResource
Sync tasks
-------------
init
> hvigor Finished :hsplibrary:tasks... after 1 ms
--------------------------------------------------------------------------
All tasks from hvigor node 'HarmonyLearn' <= 应用'hsplibrary'
--------------------------------------------------------------------------
Help tasks
-------------
tasks - Displays the tasks of the HvigorNode.
taskTree - Displays the task dag tree of the HvigorNode.
Other tasks
-------------
PreBuildApp
MakeProjectPackInfo - Generate project pack.info.
GeneratePackRes - Build the 'pack.res' file
PackageApp - Build the app package.
SignApp
clean
hook tasks
-------------
assembleApp
Sync tasks
-------------
init
> hvigor Finished ::tasks... after 1 ms
> hvigor BUILD SUCCESSFUL in 150 ms
正常的编译日志
PreBuildApp是任务名称,红色部分是模块名称,蓝色部分是任务名称
编译整个应用
sh hvigorw assembleApp -m project
命令执行完成后,最终会在根目录下生成一个build文件夹
编译hap模块
hap模块,即module.json5 文件中的type, 要么是entry, 要么是feature.
按照官方定义的特征就是:包含Ability的模块
sh hvigorw assembleHap -m module
命令执行完成后,仅仅在每个模块下生成一个build文件夹
编译Release版本
这里用到了 -p 参数,指的是自定义属性
debuggable是属性,true是属性值。
sh hvigorw assembleHap -m module -p debuggable=false
如下两张图,左图是Debug版本,右图是Release版本,即debuggable=false
编译输出Hvigor日志
sh hvigorw assembleHap -i -d -w -e
命令运行时的日志如下图,明显和我们平时编译时看到的日志形式不一样
如下这张图是sh hvigorw assembleHap
命令执行时的日志,正常开发过程中的样子
输出hvigor日志,对于分析 hvigor 和 hvigor-ohos-plugin 有一定的帮助-From harvey
菜单编译
操作路径
- Build -> "Build Hap(s)/APP(s)" -> Build Hap(s)
- Build -> "Build Hap(s)/APP(s)" -> Build App(s)
编译时,在控制台"Run"栏中,可以在第一行看到编译命令,精简一下就是:
arduino
xxx/node xxx/hvigor.js --mode module -p product=default assembleHap
编译时效果
xxx/node:其完整路径是已安装的node文件路径
xxx/hvigor.js:是处于工程缓存目录下,应用只要编译一次,其缓存目录以后是不会发生变化的
在DevEco Studio中配置应用编译参数
编译脚本
应用工程编译脚本
- 每个模块都有一个hvigorfile.ts, 这是编译模块任务的脚本
编译hap
javascript
export { hapTasks } from '@ohos/hvigor-ohos-plugin';
编译har
javascript
export { harTasks } from '@ohos/hvigor-ohos-plugin';
编译hsp
ini
module.exports = require('@ohos/hvigor-ohos-plugin').hspTasks
- 根目录下的hvigorfile.ts, 这是编译应用任务的脚本
编译APP
javascript
export { appTasks } from '@ohos/hvigor-ohos-plugin';
- 根目录下的hvigor文件夹
hvigor-config.json5: 配置 hvigor 和 hvigor-ohos-plugin
hvigor-wrapper.js: 采用hvigorw / hvigorw.bat脚本编译时的启动脚本
脚本启动流程
工程根目录下的higorw脚本,通过shell命令加载 hvigor/hvigor-wrapper.js文件,hvigor-wrapper.js文件接收shell脚本传递过来的参数,启动.hvigor/.../hvigor.js编译入口文件,至此整个启动已完成。
如果需要在编译前插入js脚本,完全可以在higorw脚本中,使用"exec"命令先执行自己的js脚本。(From harvey)
hvigor-wrapper.js 文件中的部分内容
1.初始化工程目录
这些目录,在/Users/xxx/.hvigor
2.生成应用工程缓存名称,即 用户路径下/.hvigor/project_cache/xxx
生成规则:对工程完整路径进行md5加密
3.接收参数,hvigor-wrapper.js文件
4.启动hvigor.js
hvigor和hvigor-ohos-plugin概况
hvigor.js是一切编译任务启动的入口
ini
Object.defineProperty(exports, "__esModule", { value: true });
const init_project_workspace_js_1 = require("../src/cli/wrapper/init-project-workspace.js");
const prepare_node_path_js_1 = require("../src/cli/wrapper/prepare-node-path.js")from harvey_fly;
const cli_js_1 = require("../src/cli/main/cli.js");
const cliOptions = (0, cli_js_1.parseCommand)();
//1. 初始化工程,
(0, init_project_workspace_js_1.initProjectWorkSpace)();
//2. 初始化节点任务
(0, prepare_node_path_js_1.initNodePath)();
//3. 启动编译
(0, cli_js_1.startHvigorBuild)(cliOptions);
为了方便后续梳理,针对.hvigor文件夹中的如下两个包做个简单的类图
xxx是自己电脑的账户名 /Users/harvey/.hvigor/project_caches/46ba120c223ec60d2326a333bd18143a/workspace/node_modules/.pnpm/@ohos+hvigor-ohos-plugin@2.4.2_@ohos+hvigor@2.4.2/node_modules/@ohos
/Users/harvey/.hvigor/project_caches/46ba120c223ec60d2326a333bd18143a/workspace/node_modules/.pnpm/@ohos+hvigor-ohos-plugin@2.4.2_@ohos+hvigor@2.4.2/node_modules/@ohos/hvigor-ohos-plugin
图中,白色背景为@ohos包中的内容,绿色背景为hvigor-ohos-plugin包中的内容。如下这张图不包含FA模式
.hvigor内部编译流程
从应用开发角度看,整个应用编译流程是比较清晰和简单的:1. 配置信息 2.启动任务通道
整体编译过程中,通过DevEco Studio打开应用工程可知,有两个插件依赖:1. @hvigor 2. @hvigor-ohos-plugin。 有一个应用工程入口脚本:hvigor-wrapper.js。有多个模块任务脚本:hvigorfile.ts。这些文件之间的关系是如何处理的?看下图
通过上边这个流程可以确认的是,hvigorfile.ts文件就是HarmonyOS留给应用开发者的自定义脚本入口,仅仅是如何克服在 hvigor2.4.2 编译系统中的使用问题而已。不过这点也没有多大的担心,在HarmonyOS Next中,应该已支持自定义编译脚本了。
在"开始执行pipeline"时,前期的配置信息阶段,会实例化一个ProjectImpl对象, 里边包含了关键的任务信息,hvigor将其称之为_taskContainer
"开始执行pipeline"完成后,真正的任务执行调度是通过TaskExecutor中的setInterval循环触发的。
结尾
如果还想继续深入了解hvigor编译应用流程,可以按照你所了解到的hap/har/hsp/app概念,沿着一个任务慢慢的研究。
注意:守护进程启动过程中,所产生的日志,都在 "xxx/.hvigor/daemon/log/2.4.2/"文件夹中,每启动一次工程会生成两个命名为 "daemon-进程号.log" 的文件,一个代表刚启动的主进程,一个代表守护进程。
祝好运!