From 03fc793c0a20271687aae07017a6cf45f6e605bb Mon Sep 17 00:00:00 2001 From: zhongluping <278527840@qq.com> Date: Mon, 24 Oct 2022 09:23:12 +0800 Subject: [PATCH] modify port_thirdparty doc Signed-off-by: zhongluping <278527840@qq.com> --- .../port_thirdparty/README.md | 213 ++++++++---------- 1 file changed, 96 insertions(+), 117 deletions(-) diff --git a/docs/openharmony_getstarted/port_thirdparty/README.md b/docs/openharmony_getstarted/port_thirdparty/README.md index 2aada75..5634b13 100755 --- a/docs/openharmony_getstarted/port_thirdparty/README.md +++ b/docs/openharmony_getstarted/port_thirdparty/README.md @@ -4,77 +4,77 @@ 三方库指其他公司或者组织提供的服务或者模块,能持续繁荣 OpenAtom OpenHarmony(简称“OpenHarmony”)的生态建设 。 本文介绍如何在OpenHarmony标准系统上移植一个C/C++三方库并将该三方库提交到社区。 - - ## 三方库移植问题与解决方案 - - ![移植问题分析](media/requirement.png) 由上图可以看出,三方库移植最主要的两个问题:运行时依赖与编译结构不兼容。 -#### 运行时依赖 +### 运行时依赖 运行时依赖主要包括系统API,运行C库以及硬件相关。一般的库都不会有这方面的依赖,除非一些专门针对硬件处理的库(比如针对GPU加速),介于这硬件依赖关系,本文不对这类库做详细讲解,我们只需通过API扫描工具对库进行扫描,分析是否有这类依赖。 -#### 编译结构不兼容 +### 编译结构不兼容 如今的编译结构种类繁多,如何加入到OpenHarmony编译构建系统,这是移植过程中比较常见,也是无法避免的一个问题。OpenHarmony编译构建如今支持几种形式: -1. 纯GN编译 -2. GN加action/exec_script ++ 纯GN编译 ++ GN加action/exec_script 现今大部分的三方库都是通过cmake编译,我们是可以通过上面第二种方式加入到OpenHarmony的编译构建系统中的。但是在标准系统中,通过action方式无法自动将生成的库文件拷贝到系统固件中,因此本文将重点介绍通过 - 分析cmake过程,手动构建GN规则进行移植并编译一个三方库。 - - ## 三方库移植流程 三方库的移植大致可以分为4个部分,如下图所示: - ![移植流程](media/porting.png) -接下来我们将以手动构建gn的方式移植openjpeg到OpenHamony 3.2 Beta1为例具体介绍整个移植流程。 - -验证该库的开发板我们选用rk3568. - -关于OpenHamony 3.2 Beta代码下载参考官方文档:[OpenHarmony 3.2 Beta1](https://gitee.com/openharmony/docs/blob/OpenHarmony-3.2-Beta1/zh-cn/release-notes/OpenHarmony-v3.2-beta1.md)。 - +接下来我们将以手动构建gn的方式移植openjpeg到OpenHamony 3.2 Beta1为例具体介绍整个移植流程。
+验证该库的开发板我们选用rk3568.
+关于OpenHamony 3.2 Beta代码下载参考官方文档:[OpenHarmony 3.2 Beta1](https://gitee.com/openharmony/docs/blob/OpenHarmony-3.2-Beta1/zh-cn/release-notes/OpenHarmony-v3.2-beta1.md)。
环境搭建参照:[润和RK3568开发板标准设备快速上手](https://gitee.com/openharmony-sig/knowledge_demo_temp/tree/master/docs/rk3568_helloworld). -#### 原生库准备 +### 原生库准备 -##### 下载代码 +#### 下载代码 - 在 OpenHarmony/third_party 目录下,输入以下命令下载 openjpeg的源代码(建议下载最新分支代码): + 在 OpenHarmony/third_party 目录下,输入以下命令下载 openjpeg的源代码(建议下载最新分支代码): -``` +```shell cd OpenHarmony/third_party/ git clone git@github.com:uclouvain/openjpeg.git -b openjpeg-2.1 ``` -##### 生成Makefile +#### 生成Makefile 从源码目录结构可以分析出,openjpeg是通过Cmake方式进行编译的,所以我们生成Makefile的话,需要执行以下几个步骤: -``` +```shell cd OpenHarmony/third_party/openjpeg mkdir build cd build cmake .. -DCMAKE_BUILD_TYPE=Release ``` -##### 分析编译依赖 +#### 分析编译依赖 -###### 原文件依赖分析 +##### 外部看依赖分析 -执行make指令进行编译,通过编译过程可以分析对应库以及可执行文件需要的依赖文件: +分析生成Makefile过程中的日志信息,找到本库对其他库的依赖关系,分析日志过程中,一般存在如下几种情况: -``` ++ 在日志中找不到库名,有部分三方库在生成Makefile文件时,能够在系统下找到相对应的库时,并不会在日志中打印出来,该类情况在移植到OpenHarmony后,编译过程会报错中体现出来,比较典型的就是,找不到头文件路径或者链接时提示函数符号缺失。 ++ 在日志中找不到库名,有部分三方库在生成Makefile文件时,能够在系统下找到相对应的库时,并不会在日志中打印出来,该类情况在移植到OpenHarmony后,编译过程会报错中体现出来,比较典型的就是,找不到头文件路径或者链接时提示函数符号缺失 + 1. os已开发的库,这些库可以在OpenHarmony的third_party目录下找到。 + 2. 未开发的库,且在计划内的库,可以优先移植这些库,上报并重新评估工作量。 + 3. 未开发的库,且未在计划内的库,分析这些库,一般这些库分为两大类,①对库功能存在影响,②对库功能不存在影响; 这部分需要找到库相关的地方分析代码,若对功能不影响,可以考虑忽略,否则上报,重新评估工作量问题。 + +每一个依赖的三方库,一般都对应有相应的宏定义来控制库中代码的编译,在移植三方库过程中,若有较多的库依赖,需要注意这些宏定义的开关。 +##### 原文件依赖分析 + +执行make指令进行编译,通过编译过程可以分析对应库以及可执行文件需要的依赖文件: + +```shell water@ubuntu:~/openjpeg/openjpeg/build$ make [ 1%] Building C object src/lib/openjp2/CMakeFiles/openjp2_static.dir/thread.c.o [ 2%] Building C object src/lib/openjp2/CMakeFiles/openjp2_static.dir/bio.c.o @@ -152,7 +152,7 @@ water@ubuntu:~/openjpeg/openjpeg/build$ make 由上面过程可看出,每个编译目标(Built target)所依赖的文件由上一个目标(如果上一个目标由的话)生成后以及该目标生成前的文件组成,如生成libopenjp2.so(Built target openjp)的文件是Built target openjp2_static之后以及Built target openjp之前的文件: -``` +```shell [ 35%] Building C object src/lib/openjp2/CMakeFiles/openjp2.dir/thread.c.o [ 37%] Building C object src/lib/openjp2/CMakeFiles/openjp2.dir/bio.c.o [ 38%] Building C object src/lib/openjp2/CMakeFiles/openjp2.dir/cio.c.o @@ -177,7 +177,7 @@ water@ubuntu:~/openjpeg/openjpeg/build$ make [ 67%] Building C object src/lib/openjp2/CMakeFiles/openjp2.dir/sparse_array.c.o ``` -###### 依赖库及 cflag 标志 分析 +##### 依赖库及 cflag 标志 分析 执行make编译完后,在build的目录下会生成对应源码目录结构的目录,且在该目录CMakeFiles/xxx.dir内会有build.make以及 depend.make、flags.make, link.txt 。通过分析这四个文件我们可以找到对应的依赖库以及cflag 标志。 @@ -187,20 +187,18 @@ water@ubuntu:~/openjpeg/openjpeg/build$ make | flags.make | cflags相关的一些标记 | | link.txt | 链接库相关信息 | - - 如openjpeg中生成libopenjp2的源码目录下是src/lib/openjp2,则build中会生成对应的文件夹src/lib/CMakeFiles/openjp2 .dir,且该文件夹中可以查看到 build.mak ,depend.make、flags.make,link.txt四个文件,其相关内容如下: depend.make: -``` +```shell # Empty dependencies file for openjp2. # This may be replaced when dependencies are built. ``` flags.make: -``` +```shell # CMAKE generated file: DO NOT EDIT! # Generated by "Unix Makefiles" Generator, CMake Version 3.16 @@ -214,13 +212,13 @@ C_INCLUDES = -I/home/water/openjpeg/openjpeg/build/src/lib/openjp2 link.txt: -``` +```shell /usr/bin/cc -fPIC -O3 -DNDEBUG -shared -Wl,-soname,libopenjp2.so.7 -o ../../../bin/libopenjp2.so.2.5.0 CMakeFiles/openjp2.dir/thread.c.o CMakeFiles/openjp2.dir/bio.c.o CMakeFiles/openjp2.dir/cio.c.o CMakeFiles/openjp2.dir/dwt.c.o CMakeFiles/openjp2.dir/event.c.o CMakeFiles/openjp2.dir/ht_dec.c.o CMakeFiles/openjp2.dir/image.c.o CMakeFiles/openjp2.dir/invert.c.o CMakeFiles/openjp2.dir/j2k.c.o CMakeFiles/openjp2.dir/jp2.c.o CMakeFiles/openjp2.dir/mct.c.o CMakeFiles/openjp2.dir/mqc.c.o CMakeFiles/openjp2.dir/openjpeg.c.o CMakeFiles/openjp2.dir/opj_clock.c.o CMakeFiles/openjp2.dir/pi.c.o CMakeFiles/openjp2.dir/t1.c.o CMakeFiles/openjp2.dir/t2.c.o CMakeFiles/openjp2.dir/tcd.c.o CMakeFiles/openjp2.dir/tgt.c.o CMakeFiles/openjp2.dir/function_list.c.o CMakeFiles/openjp2.dir/opj_malloc.c.o CMakeFiles/openjp2.dir/sparse_array.c.o -lm -lpthread ``` -从以上文件可以分析出 libopenjp2.so依赖库以及 C_FLAGS 信息 +从以上文件可以分析出 libopenjp2.so依赖库以及 C_FLAGS 信息 -``` +```shell 需要链接的库: -lm -lpthread 编译器需要添加的C_FLAGS标记: @@ -229,22 +227,19 @@ link.txt: 测试用例以及对应的静态库也是通过这种方法分析。 +#### 构建gn - -##### 构建gn - -通过以上分析得出的信息,我们可以构建出基于OpenHarmony编译系统的libopenjp2.so的BUILD.gn文件。 - +通过以上分析得出的信息,我们可以构建出基于OpenHarmony编译系统的libopenjp2.so的BUILD.gn文件。
在openjpeg目录新建一个BUILD.gn。 -``` +```shell cd OpenHarmony/third_party/openjpeg touch BUILD.gn ``` 将上面分析的源文件以及依赖库和FLAG都添加到BUILD.gn中 -``` +```shell import("//build/ohos.gni") #编译CFLAG标记和需要链接的库 @@ -304,23 +299,23 @@ ohos_source_set("libopenjpeg_source") { ##生成动态库 ohos_shared_library("openjpeg") { - deps = [ ":libopenjpeg_source" ] #依赖的源文件 + deps = [ ":libopenjpeg_source" ] #依赖的源文件 public_configs = [ ":openjpeg_config" ] #依赖的头文件配置信息 configs = [ ":openjpeg_cflag_config" ] #依赖的CFLAGS配置信息 - part_name = "openjpeg_lib" + part_name = "openjpeg_lib" } ``` 参照以上方法,可以构建出openjpg2所有测试用例的gn文件,以test_title_decoder为例: -``` +```shell cd OpenHarmony/third_party/openjpeg/tests/ touch BUILD.gn ``` 根据测试用例的依赖分析添加以下代码到BUILD.gn中: -``` +```shell import("//build/ohos.gni") #需要包含的头文件 @@ -335,13 +330,13 @@ config("openjpeg_config") { ##生成可执行文件 ohos_executable("test_title_decoder") { - sources = [ - "test_title_decoder.c", - "../src/bin/common/opj_getopt.c" - ] - deps = [ "//third_party/openjpeg:openjpeg" ] #依赖的openjp2库 - configs = [ ":openjpeg_config" ] #依赖的头文件配置信息 - part_name = "openjpeg_lib" + sources = [ + "test_title_decoder.c", + "../src/bin/common/opj_getopt.c" + ] + deps = [ "//third_party/openjpeg:openjpeg" ] #依赖的openjp2库 + configs = [ ":openjpeg_config" ] #依赖的头文件配置信息 + part_name = "openjpeg_lib" } ``` @@ -355,63 +350,55 @@ ohos_executable("test_title_decoder") { ##### 定义子系统并加入到编译框架 -- 在系统源码根目录下创建一个目录作为子系统目录,子系统目录可创建在OpenHarmony源码目录任意位置。 ++ 在系统源码根目录下创建一个目录作为子系统目录,子系统目录可创建在OpenHarmony源码目录任意位置。 本项目以 third_party/openjpeg 做为子系统目录,子系统名字即为openjpeg 。 -- 子系统目录下创建ohos.build文件,构建时会先读取该文件。 ++ 子系统目录下创建ohos.build文件,构建时会先读取该文件。 - ``` + ```shell ##third_party/openjpeg/ohos.build文件内容: { "subsystem": "openjpeg", "parts": { "openjpeg_lib": { - "module_list":[ - "//third_party/openjpeg/tests:test_tile_decoder", #新增测试文 test_tile_decoder + "module_list":[ + "//third_party/openjpeg/tests:test_tile_decoder", #新增测试文 test_tile_decoder "//third_party/openjpeg/tests:test_tile_encoder", #新增测试文 test_tile_encoder - ........... #添加其他测试文件 + ........... #添加其他测试文件 ] } } } ``` - ++ 把子系统配置到build/subsystem_config.json. -- 把子系统配置到build/subsystem_config.json. - - ``` + ```shell "openjpeg": { "path": "third_party/openjpeg", "name": "openjpeg" } ``` - - ##### 定义组件并加入子系统 在定义子系统的时添加的ohos.build文件中,我们已经定义好了对应的组件openjpeg_lib,module_list所定义的为该组件的目标,目标可以为动态库,静态库,可执行文件。 - - ##### 定义目标并加入组件 在构建gn的时候,我们定义的动态库以及可执行程序都是我们的目标模块,在每个目标模块中添加对应的组件名后即将我们的目标模块加入到该组件中: -``` +```shell part_name = "openjpeg_lib" ``` - - #### 产品引用 添加完子系统后,我们还需要将子系统及其组件加入产品定义中,以rk3568为例,产品定义文件存在vendor/hihope/rk3568/config.json,我们需要将以下内容添加到config.json中: -``` +```shell { "subsystem":"thirdparty", "component":[ @@ -438,29 +425,27 @@ part_name = "openjpeg_lib" 所有内容添加完后,执行以下命令进行编译: -``` -hb set ## 选择产品类型,此处我们选择rk3568 +```shell +hb set ## 选择产品类型,此处我们选择rk3568 hb build -f ## 全量编译,如果编译64位的系统,执行 hb build --target-cpu arm64 ``` - 编译完成以后可以在 /out/rk3568/packages/phone/system/lib 目录下看到编译生成的 libopenjpeg.z.so 文件。 + 编译完成以后可以在 /out/rk3568/packages/phone/system/lib 目录下看到编译生成的 libopenjpeg.z.so 文件。 -``` +```shell ls -l out/rk3568/packages/phone/system/lib/libopenjpeg.z.so -rwxr-xr-x 1 root root 286148 Mar 23 18:59 libopenjpeg.z.so ``` 在out/rk3568/packages/phone/system/bin 目录下看到我们编译的测试文件 test_tile_encoder 等 -``` +```shell ls -l out/rk3568/packages/phone/system/bin/test_* -rwxr-xr-x 1 root root 286148 Mar 23 18:59 test_decode_area -rwxr-xr-x 1 root root 286148 Mar 23 18:59 test_tile_decoder -rwxr-xr-x 1 root root 286148 Mar 23 18:59 test_tile_encoder ``` - - #### 测试 在开源库的 tests 目录下有很多测试用例,在 test 目录下的 CMakeLists.txt 文件会生成一些测试文件来进行验证,其中会给出一些测试方法,具体如下: @@ -473,31 +458,31 @@ ls -l out/rk3568/packages/phone/system/bin/test_* 1. 重加载系统,为了可以将压缩包push到开发板 - ``` - hdc_std shell ## 进入开发板系统 - mount -o remount,rw / ## 重新加载系统为可读写 - mkdir openjpeg ## 创建openjpeg文件夹用来存放测试用例 - exit ## 退出开发板系统 + ```shell + hdc_std shell ## 进入开发板系统 + mount -o remount,rw / ## 重新加载系统为可读写 + mkdir openjpeg ## 创建openjpeg文件夹用来存放测试用例 + exit ## 退出开发板系统 ``` 2. 将压缩包push到开发板 - ``` + ```shell hdc_std file send openjpej.tar /openjpeg ``` 3. 解压压缩包并将库文件拷贝到对应的目录 - ``` + ```shell hdc_std shell cd openjpeg tar -xvf openjpej.tar - cp libopenjp2.z.so /system/lib/ ## 如果系统为64位: cp libopenjp2.z.so /system/lib64 + cp libopenjp2.z.so /system/lib/ ## 如果系统为64位: cp libopenjp2.z.so /system/lib64 ``` 4. 执行测试程序 - ``` + ```shell ./test_tile_encoder 3 2000 2000 1000 1000 8 1 tte1.j2k 64 64 4 1 1 1 256 256 ``` @@ -507,46 +492,44 @@ ls -l out/rk3568/packages/phone/system/bin/test_* 至此,整个库的移植就完成了。 - - ## 三方库提交 移植完一个三方库后我们需要将该库提交到社区,[OpenHarmony C/C++ 三方库SIG仓](https://gitee.com/openharmony-sig/tpc_c_cplusplus)。目前该仓库存放移植完后三方库的相关适配脚本文件。 ### 提交内容 -- README.OpenSource,记录三方库的开源信息的文档,基本内容如下: ++ README.OpenSource,记录三方库的开源信息的文档,基本内容如下: - ``` + ```shell [ { - "Name": "", ## 库名 - "License": "", ## 开源协议 - "License File": ", ## 开源文件,一般开源项目都会自带该文件 - "Version Number": "", ## 库的版本 - "Owner": "", ## 作者 - "Upstream URL": "", ## 开源库的地址 - "Description": "" ## 库的描述 + "Name": "", ## 库名 + "License": "", ## 开源协议 + "License File": "", ## 开源文件,一般开源项目都会自带该文件 + "Version Number": "", ## 库的版本 + "Owner": "", ## 作者 + "Upstream URL": "", ## 开源库的地址 + "Description": "" ## 库的描述 } ] ``` -- 适配编译脚本 ++ 适配编译脚本 适配脚本分为2种 1. gn脚本:适合OpenHarmony源码上编译的应用调用的三方库,此时三方库编译的so最终会打包到rom中。 2. cmake脚本:适合IDE上开发NAPI接口时调用,此时三方库编译的so会和应用一起打包到hap中。 -- 配置文件 ++ 配置文件 原生库通过make或者cmake时生成的一些配置文件。如比较通用的config.h配置文件,config.h文件为原生库生成文件,原则上也不做修改,为了避免文件上仓进行代码扫码,可以将文件文件修改后缀名(config.h.in)。相关文档中需要将配置文件使用方法说明。 -- 改动的代码文件 ++ 改动的代码文件 如果移植的三方库中涉及到OpenHarmony不支持的API或驱动,需要重新适配相关代码,适配后的代码需要提交。 -- 适配使用说明文档 ++ 适配使用说明文档 文档需要明确以下几点: @@ -557,21 +540,19 @@ ls -l out/rk3568/packages/phone/system/bin/test_* 5. 文件有修改的需要说明修改点以及修改的原因 6. 配置文件的使用 -- 涉及源码提交的还需要提供OAT.xml, OAT开源审查配置,详细信息参考[ OAT开源审查](https://gitee.com/openharmony-sig/tools_oat). - - ++ 涉及源码提交的还需要提供OAT.xml, OAT开源审查配置,详细信息参考[OAT开源审查](https://gitee.com/openharmony-sig/tools_oat). ### 提交步骤 -- fork [OpenHarmony C/C++ 三方库SIG仓](https://gitee.com/openharmony-sig/tpc_c_cplusplus)到本地。 -- 将准备好的提交内容push到本地仓库。 -- 本地仓库提PR到主仓。 ++ fork [OpenHarmony C/C++ 三方库SIG仓](https://gitee.com/openharmony-sig/tpc_c_cplusplus)到本地。 ++ 将准备好的提交内容push到本地仓库。 ++ 本地仓库提PR到主仓。 详细步骤可以参照[如何提交PR的指导文档](https://gitee.com/zhong-luping/knowledge/blob/master/docs/openharmony_getstarted/push_pr/readme.md) 。 ## FAQ -- 我执行make指编译的时候,没有打印对应的目标及其依赖文件该如何处理? ++ 我执行make指编译的时候,没有打印对应的目标及其依赖文件该如何处理? 分析编译依赖时有提到过build.make文件,该文件中就有目标的定义以及依赖源文件。 @@ -579,19 +560,17 @@ ls -l out/rk3568/packages/phone/system/bin/test_* ![build.make](media/build_make.png) -- 我移植的库没有cmake怎么办? ++ 我移植的库没有cmake怎么办? 本文重点介绍通过cmake构建gn来移植三方库,针对其他方式可以通过分析Makefile文件来构建gn,具体方法可以参照[三方库移植依赖分析](https://gitee.com/huangminzhong/mytest/tree/master/OpenHarmony_ThirdParty)。 -- 编译的时候提示XXX接口没有定义怎么办? ++ 编译的时候提示XXX接口没有定义怎么办? 出现此问题有以下几点需要确认: 1. 确认源文件是否添加完全 2. 确认是否添加头文件以及头文件路径 - - ## 参考资料 [OpenHarmony 3.2 Beta1简介](https://gitee.com/openharmony/docs/blob/OpenHarmony-3.2-Beta1/zh-cn/release-notes/OpenHarmony-v3.2-beta1.md) @@ -604,6 +583,6 @@ ls -l out/rk3568/packages/phone/system/bin/test_* [OAT开源审查](https://gitee.com/openharmony-sig/tools_oat). -[如何提交PR的指导文档](https://gitee.com/zhong-luping/knowledge/blob/master/docs/openharmony_getstarted/push_pr/readme.md) +[如何提交PR的指导文档](https://gitee.com/zhong-luping/knowledge/blob/master/docs/openharmony_getstarted/push_pr/readme.md) -[知识体系](https://gitee.com/openharmony-sig/knowledge) \ No newline at end of file +[知识体系](https://gitee.com/openharmony-sig/knowledge) -- Gitee