#夏日挑战赛#【FFH】OpenHarmony设备开发基础(三)编译依赖 原创 精华
一、前言
本文将简单介绍一下轻量和小型系统使用到的编译工具,详细讲解新增模块后编译依赖的三种配置方式。
<br>
二、gn和ninja
轻量级和小型系统是一个基于gn和ninja的构建系统,以支持OpenHarmony组件化开发为目标,支持组件拼装产品并编译,独立构建芯片解决方案源码,独立构建单个组件。新增组件开发完成后,需要基于gn语法配置构建信息,并保存在BUILD.gn文件中。大家可以借助唐老师的这篇文章进一步了解鸿蒙中的Gn和Ninja:浅析鸿蒙的Gn与Ninja
<br>
三、开发准备
尚未安装开发环境的可以参考这篇文章step by step进行配置:
DevEco Device Tool一站式集成开发环境搭建
从源码获取,编译,烧录到串口调试的一站式集成开发,可以参考这篇:
DevEco Device Tool设备开发全流程概述
做完以上准备后,相信大家已经能轻松完成工程编译、代码烧录等工作并跑通整个流程了。以上工作准备完成后就可以进入到开发环节了。
其实,功能开发一般是大家比较熟悉地,除了新增接口的使用外,技术上没有太多难度,很多时候都是在移植原有功能。功能开发完成后,怎么集成到系统里面,应该是大家比较关心的问题,这也是OpenHarmony设备开发区别于其他嵌入式开发不同的地方。
<br>
四、编译依赖的三种配置方式
首先,我们先来了解编译和编译依赖。简单来说,编译时被依赖的模块或代码都会参与到编译中来,OpenHarmony中引入依赖有以下三种方式:
- 产品配置config.json中增加组件依赖。
- 已有模块BUILD.gn中deps配置组件依赖。
- 已有模块中增加源码路径,通过文件引入依赖。
接下来我们需要先增加一个组件演示组件依赖的配置和文件依赖的配置
在applications/sample/wifi-iot/app目录下增加my_first_demo组件,配置如下图:
demo01.c代码如下
#include <stdio.h>
#include "ohos_init.h"
#include "ohos_types.h"
void demo(void)
{
printf("开源项目 OpenHarmony\n是每个人的OpenHarmony\n");
}
SYS_RUN(demo);
显然,C文件是三种编译依赖方式都需要的,关系到功能开发。
接下来,就让我们一个个来剖析三种编译依赖方式吧。
1.产品配置config.json中增加组件依赖
首先,我们需要编写用于将业务构建成静态库的 BUILD.gn 文件。demo001即为静态库名称(后面会用到):
static_library("demo001"){
sources = [
"demo01.c"
]
include_dirs = [
"//utils/native/lite/include"
]
}
BUILD.gn是构建配置文件,定义了构建目标,是前两个组件依赖方式必须要有的。于是组件目录变成了这样
从设备开发的角度来看,我们增加的功能一般属于应用层,一般会配置在应用子系统中信息保存在applications.json中,如下图左半部分所示。为了在建产品的时候能够形成依赖把my_first_demo组件一起编译进来,我们需要在config.json中配置子系统依赖,加上下图蓝色圈起来的信息。
注意看上图的文件路径和指向对应关系。
上篇文章我们介绍过config.json是产品解决方案的构建入口,产品解决方案需要的组件都会参与到编译过程。所以在config.json中配置子系统和组件信息可以促使my_first_demo工程参与到编译过程中,并打包进固件。
但是,我们每次创建工程改代码都要跑到config.json中去进行修改,而config.json上还不能直接修改,得一层层文件打开去找到application.json找到对应的组件后修改目标文件位置,光是看上图的箭头和文件目录都应该知道这个过程有点麻烦了吧
其实,有一些教程提供了更简便的方案:
例如,在连老师的《OpenHarmony设备开发入门》书中的HelloWorld例程就是在app模块BUILD.gn文件中进行编译依赖配置,在features字段中增加索引,使目标模块参与编译。
::: hljs-center
图源《OpenHarmony设备开发第一版》
:::
若按相对路径的格式写就是这样的:
同时,不要忘记删除前面那种方法中蓝字圈起来的部分呦!
此时一张非常顺滑的依赖指向图就可以整理出来了
当我们理解这个过程后,再写类似的程序就可以在模块app的BUILD.gn中加上短短的一行“组件名:静态库名称”即可了,是不是轻松很多?
其实两种方法的意思是一样的,只是一个层级的问题,类似于我在上层已经指明了,下层就不用再详细指路了。
<br>
2.已有模块BUILD.gn中deps配置组件依赖
这种方式需要在现有参与编译的模块中配置deps依赖。这里以在hal_token_static中增加my_first_demo为例,被依赖的模块my_first_demo会一起参与编译,并打包到最终的固件中。
具体步骤为:将之前在app模块BUILD.gn中写的“my_first_demo:demo001”注释掉,右键单击my_first_demo文件夹复制相对路径,然后打开
vendor/hisilicon/hispark_pegasus/hals/utils/token/BUILD.gn添加deps:
static_library("hal_token_static") {
sources = [ "hal_token.c" ]
include_dirs = [
"//base/startup/syspara_lite/hals",
"//utils/native/lite/include",
]
deps = [
"//applications/sample/wifi-iot/app/my_first_demo:demo001" # 添加此行
]
}
然后编译,烧录,查看监视器可以得到demo.c中打印的语句:
当控制变量删去deps配置时将不会有该语句打印出。
这种方式是一种隐式依赖,不难看出,此依赖方式必须依赖已编译的模块才能执行,所以只有两模块相关度比较高,直接依赖了my_first_demo时才使用这种方式,否则还是推荐使用前面所说的方式。
<br>
3.已有模块中增加源码路径,通过文件引入依赖
最后一种是文件依赖,是最简单的一种方式,只需要在现有的模块中增加源文件即可一起参与编译。
再次以在hal_token_static模块中进行操作为例:
static_library("hal_token_static") {
sources = [
"hal_token.c",
"//applications/sample/wifi-iot/app/my_first_demo/demo01.c"
]
include_dirs = [
"//base/startup/syspara_lite/hals",
"//utils/native/lite/include",
]
deps = [
#"//applications/sample/wifi-iot/app/my_first_demo:demo001"
]
}
此时,删除了my_first_demo目录下的BUILD.gn文件(可有可无,反正不会用到)后依然成功打印出了目标语句!
这种方式,一般用于耦合关系比较大的功能,相互调用较多或者接口依赖较强。此时可以把文件放在同一个模块中一起编译,减少配置的复杂度
五、后记
参考文档及教程:
OpenHarmony基础
《OpenHarmony设备开发入门》
不知道大家看完本篇文章,对于编译依赖有没有更深层次的理解呢?
这三种依赖方式各有优劣,大家不妨每一个方法都去试验一下。我们需要在以后的开发过程中多多体会,充分利用好OpenHarmony的模块化、可裁剪的优势,根据需要进行配置。
这里再提一嘴,我不允许有人还没用DevEco Device Tool搞南向开发!简直太好用了!不信你看这篇文章然后自己体验一下如果不是我前些天改用了这个开发环境的话,反复跳转工具编译烧录开串口等等,得浪费多少时间啊
总之,希望本文能帮到大家,如果有没有考虑到的、不对的地方,欢迎交流探讨~
感谢楼主分享,DevEco Device Tool确实好用
不错不错
还是用原声环境好,这种环境实在是不想用
不错不错