NAPI篇【2】——OpenHarmony含NAPI工程cpp详解

ops/2024/9/25 3:57:39/

        NAPI篇【1】中,讲解如何创建一个支持NAPI的OpenHarmony工程,其中有一个步骤是在OpenHarmony工程添加Harmony的NAPI工程中的cpp文件夹。cpp文件夹包含支持NAPI所需要的c/c++源码、接口导出文件以及编译文件等。本文将进行详解其中各文件的作用,帮助熟悉NAPI的开发。

        本文基于笔者的开发经验和网上参考资料汇集而成,笔者也处于学习阶段,如有错误,欢迎指正。

一、cpp文件夹——基础文件

        1、cpp文件夹基本内容

        通过NAPI模板新建工程,cpp文件夹内容全展开,如下图所示。

        2、cpp的一级目录文件

         如下图所示,cpp的一级目录下有hello.cpp、CMakeLists.txt 和一个二级目录types。

        (1)CMakeLists.txt 文件

        CMakeLists.txt是cmake用来生成Makefile文件的一个描述编译链接的脚本文件。该文件的基本内容行注释如下所示:

#CMake的最低版本要求
#默认即可
cmake_minimum_required(VERSION 3.4.1)    # 用函数project(demo)指定的项目名称,可自行设置,这里变量的值为“napi”
project(napi)           #设置环境变量,设置库文件的输出地址。
#CMAKE_CURRENT_SOURCE_DIR:当前处理的CMakeLists.txt文件所在目录
#默认即可
set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})#给工程添加头文件,会为当前CMakeLists.txt的所有目标,
#以及之后添加的所有子目录的目标添加指定头文件搜索路径。
#默认即可
include_directories(${NATIVERENDER_ROOT_PATH}${NATIVERENDER_ROOT_PATH}/include)add_library(entry SHARED hello.cpp)   
#将源文件hello.cpp生成动态库文件,若有多个cpp文件,需要在此添加,以便生成动态库文件
# 生成目标库文件libentry.so,entry表示最终的库名称,SHARED表示生成的是动态链接库,
#
#add_library(生成的库名称 STATIC/SHARED 源文件1.cpp 源文件2.cpp)
#将源文件生成 静态/动态 库文件 
#STSTIC 表示静态库最终会编入到可执行文件中
#SHARED(常见参数)表示动态库(又称共享库)方式
#target_link_libraries(entry PUBLIC libace_napi.z.so)
# 把libentry.so链接到libace_napi.z.so上
#/
#target_link_libraries (库/可执行文件 library1 library2 ...)
#将目标文件(为库或者可执行文件)与库文件进行链接
#libace_napi.z.so库,默认即可
#/

        CMakeLists.txt 文件需要在 build-profile.json5 文件里做配置声明,代码如下所示,对应 NAPI篇【1】中的   二、2、(3)步。

{"apiType": 'stageMode',"buildOption": {
//在buildOption配置项中
//声明添加NAPI的编译目标,对CMakeLists.txt编译脚本进行声明执行"externalNativeOptions": {"path": "./src/main/cpp/CMakeLists.txt","arguments": "","cppFlags": "",}
/},"targets": [{"name": "default"},{"name": "ohosTest",}]
}

        (2).cpp源文件

        在cpp文件夹的一级目录文件下,可以有多个.cpp源代码文件,比如,加一个fun.cpp文件,这些文件用来实现某一功能,带需要在CMakeLists.txt 文件中,add_library(生成的库名称 STATIC/SHARED 源文件1.cpp 源文件2.cpp)这一函数中进行声明,方便参与生成库文件。

        在cpp文件夹的一级目录文件下,还以包含.h的头文件,方便多个.cpp文件的编写,相互调用。如下图所示:

        (3) NAPI函数的定义与注册(hello.cpp解读)

        利用NAPI模板生成的工程中,默认生成的hello.cpp文件中包含了NAPI函数编写、定义与注册,文本借助hello.cpp文件的解读,来梳理。(NAPI函数的编写,详见NAPI篇【3】)

        cpp 目录下默认生成的 hello.cpp 文件,源码如下所示:

#include "napi/native_api.h"static napi_value Add(napi_env env, napi_callback_info info)
{size_t requireArgc = 2;size_t argc = 2;napi_value args[2] = {nullptr};napi_get_cb_info(env, info, &argc, args , nullptr, nullptr);napi_valuetype valuetype0;napi_typeof(env, args[0], &valuetype0);napi_valuetype valuetype1;napi_typeof(env, args[1], &valuetype1);double value0;napi_get_value_double(env, args[0], &value0);double value1;napi_get_value_double(env, args[1], &value1);napi_value sum;napi_create_double(env, value0 + value1, &sum);return sum;}EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports)
{napi_property_descriptor desc[] = {{ "add", nullptr, Add, nullptr, nullptr, nullptr, napi_default, nullptr }};napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);return exports;
}
EXTERN_C_ENDstatic napi_module demoModule = {.nm_version = 1,.nm_flags = 0,.nm_filename = nullptr,.nm_register_func = Init,.nm_modname = "entry",.nm_priv = ((void*)0),.reserved = { 0 },
};extern "C" __attribute__((constructor)) void RegisterEntryModule(void)
{napi_module_register(&demoModule);
}
         (3.1)注册napi模块
static napi_module demoModule = {.nm_version =1,//nm_version:nm版本号,默认值为 1。.nm_flags = 0,//nm标记符,默认值为 0。.nm_filename = nullptr,//暂不关注,使用默认值即可。.nm_register_func = Init,//指定nm的入口函数,即napi定义模块.nm_modname = "entry",//指定 TS 页面导入的模块名,例如:`import testNapi from 'libentry.so'` 中的 testNapi //就是当前的nm_modname。.nm_priv = ((void*)0),//暂不关注,使用默认值即可。.reserved = { 0 },//暂不关注,使用默认值即可。
};extern "C" __attribute__((constructor)) void RegisterEntryModule(void)
{napi_module_register(&demoModule);
}//extern "C" 简单理解就是告诉编译器这部分代码按照 C 语言进行编译而不是 C++ 语言编译。
//__attribute__((constructor)) 声明方法的执行时机,它表示 RegisterEntryModule() 方法在 main() 
//方法执行前执行, RegisterEntryModule() 方法内调用了 napi_module_register() 方法,该方法是 
//NAPI 提供的模块注册方法,表示把定义的 demoModule 模块注册到系统中。
        (3.2)定义napi模块
EXTERN_C_START   //开始标志
static napi_value Init(napi_env env, napi_value exports)  //Init定义模块名
{napi_property_descriptor desc[] = {//需要引出的NAPI功能函数,这以Add函数为例,"add"对应 libentry 目录下index.d.ts 文件中//export const add: (a: number, b: number) => number;导出的函数名
//"add"自定义函数名,用于ets调用,注意与index.d.ts 文件中导出名一致;Add注册定义的函数名。{ "add", nullptr, Add, nullptr, nullptr, nullptr, napi_default, nullptr }
//...
//定义导出的函数可以有多个};napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);return exports;
}
EXTERN_C_END    //结束标志

3、二级目录types

    (1) 目录libentry基本内容

        目录types包含有一个三级目录libentry

4、三级目录libentry

      (1)目录libentry基本内容

        目录libentry包含有文件index.d.ts和oh-package.json5

        (2)index.d.ts文件

        libentry 目录下生成了 index.d.ts 文件,用来声明要导出的NAPI函数,它的源码如下所示:

export const add: (a: number, b: number) => number;

        export const 表示导出一个常量以便在其它文件中使用。add 是一个返回类型为 number 的方法,它的参数类为 number 类型。

        (3)oh-package.json5文件

        libentry目录下生成了 package.json 文件,该文件是打包的配置文件,内容如下所示:

{"name": "libentry.so","types": "./index.d.ts","version": "","description": "Please describe the basic information."
}

        设置 libentry.so 库和 index.d.ts 相关联,便于在 TS 文件中引入 libentry.so 时调用库中的相关方法。添加了d.ts模块,要想被ets在静态时检查到,需要配置entry/oh-package.json5下配置dependencies,对应NAPI篇【1】中的   二、2、(4)步。

二、NAPI函数的调用

        1、模块导入

        根据前边的编译配置,cpp 目录下的源码最终打包成了 libentry.so,因此,在ets或ts文件中使用前直接引入即可。例如:

import testNapi from 'libentry.so'

        2、函数调用

        引入 libentry.so 模块后,就可以直接调用在index.d.ts文件声明的NAPI函数,填入相应的参数即可,例如调用 add() 函数:

        参考链接:

        (1)CMakeLists.txt详解-CSDN博客

        (2)CMakeLists.txt常用指令总结与练习_创建cmakelists.txt.指令-CSDN博客

        (3)【坚果派-坚果】Napi入门_libnapi-CSDN博客

        (4)openHarmony使用Napi开发样例_napi 中如何引入 静态库-CSDN博客


http://www.ppmy.cn/ops/52999.html

相关文章

Master PDF Editor v5 解锁版安装教程(小巧多功能PDF )

前言 Master PDF Editor,小巧的多功能PDF编辑器,轻松查看,创建,修改,批注,签名,扫描,OCR和打印PDF文档。高级注释工具,可以添加任意便笺指示对象突出显示,加…

mac 安装mysql启动报错 ERROR!The server quit without update PID file

发现问题: mac安装mysql初次启动报错: 一般出现这种问题,大多是文件夹权限,或者以前安装mysql卸载不干净导致。首先需要先确定问题出在哪?根据提示我们可以打开mysql的启动目录,查看启动日志。 问题解决&a…

Day8 —— 大数据技术之HBase

HBase快速入门系列 HBase的概述什么是HBase?主要特点和功能包括使用场景 HBase的架构HBase部署与启动HBase基本操作前提条件数据库操作表操作数据的CRUD操作 HBase的不足 HBase的概述 什么是HBase? HBase 是一个开源的、分布式的、面向列的 NoSQL 数据…

上古世纪战争台服官网地址+台服预约+预创建角色教程

上古世纪战争台服上线啦,在《上古世纪战争》中,通过主要势力和地区,剧情和角色可以想起原作。《上古世纪战争》的主要背景为,原大陆消失之后,完成移民的种族们定居在诺伊大陆之后遇到的多个势力之间的冲突。同时&#…

PPT可以转换成Word吗?归纳了三种转换方式

PPT可以转换成Word吗?在当今快节奏的工作和学习环境中,不同格式文件之间的转换变得日益重要。PPT作为演示文稿制作的首选工具,广泛应用于会议演讲、教育培训等多个场景,而Word则是文档编辑与编排的基石。为了便于进一步编辑、分享…

video_多个m3u文件合并成一个m3u文件

主要是用#EXT-X-DISCONTINUITY进行拼接,用简单的例子说明: 第一个文件: #EXTM3U #EXT-X-VERSION:3 #EXT-X-TARGETDURATION:69 #EXT-X-MEDIA-SEQUENCE:1001 #EXTINF:60.000000, xmt202406_11001.ts #EXTINF:60.000000, xmt202406_11002.ts #EXTINF:60.000000, xmt202406_11…

前端写代码真的有必要封装太好么?

前言 封装、代码复用、设计模式…… 这些都是方法,业务才是目的。技术始终是为业务服务的。能够满足业务需求,并且用起来舒服的,都是好方法。 不存在一套适用于所有项目的最佳代码组织方法,你需要结合业务,去不断地…

由浅入深,走进深度学习(3)

今天分享的学习内容主要是完整构建神经网络, 包括:训练、测试、损失函数呀,计算精度呀,等等~ 用到的框架就是torch 在这里我也是对自己做一个学习记录,如果不符合大家的口味,大家划走就可以啦 可能没有…