快捷搜索: 王者荣耀 脱发

鸿蒙开发从hello world开始

按照官方教程操作没有坑,我使用的编译环境是 VM12+Ubuntu18.04,并且配置了SSH和Samba。

在Windows下使用VSCODE和ssh,这样的好处是只要虚拟机开机,其他的操作都可以在Windows下进行,并且可以不用在同一台电脑上,有需要可以在云上搭建。

(让人难过的是,我家里用的电脑出现了故障,在公司用的又不能安装VM,所以之后准备换成docker)

下面这个代码树就是拿到开发板后,玩板子的人操作的空间,所有你打算写的代码都在这个。

​1、新建文件夹

2、编写业务代码

这段代码引用了三个头文件:

stdio.h:学过C语言的都知道,调用printf的时候就需要使用;

ohos_types.h:将C语言的变量做了重新定义;

ohos_types.h: SYS_RUN这个宏就在这个文件里定义。

在例程的gn文件中提示了头文件的路径:

//utils/native/lite/include

我们主要来看一下关于SYS_RUN的定义:

这段代码需要从下往上看:

LAYER_INITCALL有一个条件编译宏,

    定义了LAYER_INIT_SHARED_LIB:

整理得:

这里运用GUN文档中对构造属性的说明 :

就是在这里定义了一个函数BOOT_ run2HelloWorld,在这个函数里调用应用层中的HelloWorld,且这个函数的执行顺序是在main之前,其优先级为702。

    没定义LAYER_INIT_SHARED_LIB

整理得

最终得:

InitCall是一个没有参数没有返回值的函数指针类型,#define USED_ATTR __attribute__((used))用来修饰一个变量或者函数,目的是告诉编译器,修饰的这个变量或者函数是被使用的,即使没有使用也不要优化掉:

__attribute__((p(".zinitcall.run2.init")))

用来修饰一个变量或者函数,目的是告诉编译器,修饰的这个变量或者函数要被编译连接到.zinitcall.run2.init这个代码段里,在系统运行后,.zinitcall.run2.init代码段的内容会被逐个执行,就会执行到我们的HelloWorld函数。

那么原宏定义就是定义了一个静态常量 __zinitcall_run_HelloWorld,这个常量的类型是个InitCall的指针类型,这个常量的值为HelloWorld,对应一个函数,就是这个函数的地址。并将这个常量编译连接到.zinitcall.run2.init代码段中。

熟悉Linux的都知道,这个是Linux的常规操作,将一系列初始化函数编译链接到一起,运行时候整块取出去执行。

包含下面内容:

刚刚被定义的那个函数指针,编译后就会按照声明的位置,保存在目标代码.zinitcall.run2.init 代码段中.

结合连老师的链接更清晰:

分析 helloworld程序是如何被调用,SYS_RUN做什么事情

补充一下关于宏定义#和##

#:字符串化 ##:把宏参数连接在一起,参数在中间两边都需要## 宏定义用#和##的地方宏参数不会再展开,如果需要将传入参数的宏再次展开,需要中间增加一层转换,把所有宏的参数在这层里全部展开,在最下层使用#或者##。

3、业务构建成静态库的BUILD.gn文件,跟刚刚的.c文件在同一个目录下

BUILD.gn文件由三部分内容(目标、源文件、头文件路径)构成:

    static_library中指定业务模块的编译结果,为静态库文件libmyapp.a,开发者根据实际情况完成填写。 sources中指定静态库.a所依赖的.c文件及其路径,若路径中包含"//"则表示绝对路径(此处为代码根路径),若不包含"//"则表示相对路径。 include_dirs中指定source所需要依赖的.h文件路径。

4、编写模块BUILD.gn文件,指定需参与构建的特性模块,在app这个目录下,和刚刚新建的那个文件夹(my_first_app)在同一个文件夹下

将"my_first_app:myapp"添加到features字段中,刚刚写的那个代码就能被编译了。

    my_first_app是相对路径,指向./applications/sample/wifi-iot/app/my_first_app/BUILD.gn。 myapp是目标,指向./applications/sample/wifi-iot/app/my_first_app/BUILD.gn中的static_library("myapp")。

编译后进行烧录,效果如下:

经验分享 程序员 微信小程序 职场和发展