OpenHarmony开发者论坛

标题: OpenHarmony应用开发引入开源C/C++库---之Lycium使用经验总结 [打印本页]

作者: 深开鸿_王石    时间: 2024-6-27 10:17
标题: OpenHarmony应用开发引入开源C/C++库---之Lycium使用经验总结
[md]论坛里好多人在问,我有c,c++库,怎么在so里调用,这边介绍个可行方案,供大家参考

### lycium 交叉编译框架

**lycium是一款协助开发者通过shell语言实现C/C++三方库快速交叉编译,并在OpenHarmony 系统上快速验证的编译框架工具。开发者只需要设置对应C/C++三方库的编译方式以及编译参数,通过lycium就能快速的构建出能在OpenHarmony 系统运行的二进制文件。**

* **原则**
  **移植过程,不可以改源码(即不patchc/cpp文件,不patch构建脚本)。如移植必须patch,patch必须评审,给出充分理由。(不接受业务patch)**
* **目录结构**
  ```
  .
  ├── docs                            #说明使用文档
  ├── LICENSE
  ├── lycium                          #编译工具
  │   ├── build.sh                    #编译的入口脚本
  │   ├── Buildtools
  │   ├── CItools
  │   ├── community
  │   ├── doc
  │   ├── lycium_build_intl.log
  │   ├── ohos-sdk                    #我解压的sdk,然后export配置了路径,后面会说
  │   ├── OpenHarmony_4.0.8.tar.gz    #我自己下载的sdk
  │   ├── README.md
  │   ├── script
  │   ├── template
  │   ├── test.sh
  │   └── usr                         #编译后的头文件和lib库会安装在此目录下
  ├── README_zh.md
  └── thirdparty                      #改过编译配置文件的三方库
  ```

### 通过Lycium工具构建C/C++三方库

1. **编译环境准备**
   > 1. **安装缺少的库:**`lycium`框架支持多种构建方式的三方库,为了保障三方库能正常编译,我们需要保证编译环境中包含以下几个基本编译命令: `gcc`, `cmake`, `make`, `pkg-config`, `autoconf`, `autoreconf`, `automake`, 如若缺少相关命令,可通过官网下载对应版本的工具包,也可以在编译机上通过命令安装,如若 `Ubuntu`系统上缺少 `cmake`可以通过以下命令安装:
   >
   > ```
   > sudo apt install cmake
   > ```
   >
   > **  其他都一样,比如我编译ffmpeg的时候出现了以下报错,这个其实就是要不缺少nasm,要不缺少yasm,确认下**
   >
   > ```
   >   nasm/yasm not found or too old. Use --disable-x86asm for a crippled build.
   >
   >   xx@XX_ZLL:~/xx/tpc_c_cplusplus/lycium$ nasm
   >   Command 'nasm' not found, but can be installed with:
   >   sudo apt install nasm
   >   xx@XX_ZLL:~/xx/tpc_c_cplusplus/lycium$ yasm
   >   Command 'yasm' not found, but can be installed with:
   >   sudo apt install yasm
   >
   > ```
   >
   > 2. **下载OHOS\_SDK,**[官方下载路径](https://gitee.com/openharmony-si ... -Testing-Version.md) 。 SDK分Full SDK 和 Public SDK,对交叉编译一样,所以随便下,这里给两个我下的链接。
   >
   > ```
   > sdk(windows+linux): http://download.ci.openharmony.c ... full_monthly.tar.gz
   > ohos-sdk-public: http://download.ci.openharmony.c ... blic_monthly.tar.gz
   > ```
   >
   > **  下载完毕后需要部署好,我是在\~/xx/tpc\_c\_cplusplus/lycium这个里面下的,所以就原地解压了,命令如下:**
   >
   > ```
   >   # 解压sdk
   >   tar -zxvf version-Master_Version-OpenHarmony_4.0.8.1-20230608_091016-ohos-sdk-full.tar.gz
   >
   >   # 进入sdk里的linux目录
   >   cd ohos-sdk/linux/
   >
   >   # 解压目录里的zip文件,解完后可以进到native目录里去看有没有arm工具链,你会失望的发现,没有
   >   for i in *.zip;do unzip ${i};done
   >
   >   # 进入到工具包目录
   >   cd lycium/Buildtools    
   >
   >   # 可校验工具包是否正常, 若输出"toolchain.tar.gz: OK"则说明工具包正常,否则说明工具包异常,需重新下载
   >   sha512sum -c SHA512SUM              
   >
   >   # 解压拷贝编译工具,这个里面其实就是arm工具链
   >   tar -zxvf toolchain.tar.gz          
   >
   >   # 将命令拷贝到工具链的native/llvm/bin目录下
   >   cp toolchain/* ${OHOS_SDK}/native/llvm/bin  
   > ```
   >
   > **  如上全做完,你的工具链就在ohos-sdk/linux/native下装好了**
   >
   > ```
   > lycium/ohos-sdk/linux/native
   > ├── build
   > │   └── cmake
   > │       ├── ohos.toolchain.cmake
   > │       └── sdk_native_platforms.cmake
   > ├── build-tools
   > │   └── cmake
   > │       ├── bin
   > │       ├── doc
   > │       ├── man
   > │       └── share
   > ├── docs
   > ├── llvm
   > │   ├── bin
   > │   │   ├── aarch64-linux-ohos-clang
   > │   │   ├── aarch64-linux-ohos-clang++
   > │   │   ├── arm-linux-ohos-clang                      #拷贝来的工具
   > │   │   ├── arm-linux-ohos-clang++
   > │   │   ├── ......
   > │   │   ├── sanstats
   > │   │   ├── scan-build
   > │   │   ├── scan-view
   > │   │   └── yaml2obj
   > │   ├── include
   > │   ├── lib
   > │   │   ├── aarch64-linux-ohos
   > │   │   ├── arm-linux-ohos
   > │   │   ├── arm-liteos-ohos
   > │   │   ├── clang
   > │   │   ├── ......
   > │   │   ├── mipsel-linux-ohos
   > │   │   ├── riscv64-linux-ohos
   > │   │   ├── x86_64-linux-ohos
   > │   │   └── x86_64-unknown-linux-gnu
   > │   ├── libexec
   > │   │   ├── analyze-c++
   > │   │   ├── analyze-cc
   > │   │   ├── c++-analyzer
   > │   │   ├── ccc-analyzer
   > │   │   ├── intercept-c++
   > │   │   └── intercept-cc
   > │   ├── NOTICE
   > │   └── share
   > ├── nativeapi_syscap_config.json
   > ├── ndk_system_capability.json
   > ├── NOTICE.txt
   > ├── oh-uni-package.json
   > └── sysroot
   >     └── usr
   >         ├── include
   >         └── lib
   > ```
   >
   > 3. **native 目录介绍**
   >
   > ```
   >   build 目录存放的是 构建时 cmake 依赖的配置文件
   >
   >   build-tools 目录存放的是 构建工具包含 cmake 和 ninja,我们后面采用 make 进行构建。
   >
   >   docs 目录存放 使用说明
   >
   >   llvm 目录存放 clang 编译器
   >
   >   sysroot 目录为编译器的 sysroot 目录,存放 SDK 内部的已经包含的库和对应的头文件
   >
   >   oh-uni-package.json 为 SDK 信息描述,如版本
   >
   >   NOTICE.txt 为注意事项,内容多为 SDK 的详细描述
   >
   >   ndk_system_capability.json 记录 SDK 提供的能力
   >
   >   nativeapi_syscap_config.json 记录 SDK 提供的能力对应的头文件
   > ```
   >
   > **  ****build和build-tools目录提供构建时的 cmake,ninja,以及 toolchain 依赖。llvm 提供编译工具链。sysroot 提供 usr 系统资源**
   >
2. **编译现成三方库**
   > **装完SDK后就可以编译了,在**[lycium](https://gitee.com/openharmony-si ... /blob/master/lycium)目录执行./build.sh 【pkgname】,进行自动编译三方库,并打包安装到当前目录的 usr/【pkgname】/ARCH 目录
   >
   > **所以我们就去thirdparty目录下挑选了个比较熟悉的库:DLib**
   >
   > ```
   > xx@XX_ZLL:~/xx/tpc_c_cplusplus/lycium$ ./build.sh DLib
   > Build OS linux
   > OHOS_SDK=/home/xx/wshikh/tpc_c_cplusplus/lycium/ohos-sdk/linux
   > CLANG_VERSION=15.0.4
   > DLib not ready. wait boost opencv_3.4.1
   > Build boost 1.81.0 start!
   > % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
   >                             Dload  Upload   Total   Spent    Left  Speed
   > 0     0    0     0    0     0      0      0 --:--:--  0:00:01 --:--:--     0
   > 100  133M  100  133M    0     0  3419k      0  0:00:40  0:00:40 --:--:-- 4113k
   > boost_1_81_0.tar.gz: OK
   >
   >
   > Compile OpenHarmony armeabi-v7a boost 1.81.0 libs...
   > ```
   >
3. **测试现成三方库**
   > 1. **准备CI环境**
   >
   > **  业界内C/C++三方库测试框架多种多样,我们无法将其统一,因此为了保证原生库功能完整,我们基于原生库的测试用例进行测试验证。为此,我们需要集成了一套可以在OH环境上进行cmake, ctest等操作的环境,具体请阅读 **[lycium CItools](https://gitee.com/openharmony-si ... Itools/README_zh.md),在此验证下具体步骤:
   >
   > 1. **直接用编译好的二进制,请点击**[下载链接](https://gitee.com/han_jin_fei/lycium-citools) ,解压:
   >    ```
   >    # 下载库
   >    git clone https://gitee.com/han_jin_fei/lycium-citools.git
   >
   >    # 进入lycium-citools解压库
   >    for i in *.tar.gz;do tar zxvf ${i};done
   >
   >    $ hdc_std file send lyciumCI-armeabi-v7a-perl.tar.gz /data/local/tmp
   >    FileTransfer finish, Size:21347830, File count = 1, time:5833ms rate:3659.84kB/s
   >    $ hdc_std file send lyciumCI-armeabi-v7a-busybox.tar.gz /data/local/tmp
   >    FileTransfer finish, Size:972992, File count = 1, time:275ms rate:3538.15kB/s
   >    $ hdc_std file send lyciumCI-armeabi-v7a-shell_cmd.tar.gz /data/local/tmp
   >    FileTransfer finish, Size:6389194, File count = 1, time:1760ms rate:3630.22kB/s
   >    $ hdc_std file send lyciumCI-armeabi-v7a-cmake_make.tar.gz /data/local/tmp
   >    FileTransfer finish, Size:44749407, File count = 1, time:11773ms rate:3801.02kB/s
   >    $ hdc_std file send lyciumCI-armeabi-v7a-gdb.tar.gz /data/local/tmp
   >    FileTransfer finish, Size:11666656, File count = 1, time:3231ms rate:3610.85kB/s
   >
   >    $ hdc_std shell
   >    # mount -o remount,rw /
   >
   >    # mkdir /usr
   >
   >    # cd /data/local/tmp
   >
   >    # tar zxvf lyciumCI-armeabi-v7a-cmake_make.tar.gz
   >
   >    # tar zxvf lyciumCI-armeabi-v7a-gdb.tar.gz
   >
   >    # tar zxvf lyciumCI-armeabi-v7a-shell_cmd.tar.gz
   >
   >    # tar zxvf lyciumCI-armeabi-v7a-busybox.tar.gz
   >
   >    # cp -rf armeabi-v7a-cmake_make/* /usr/
   >
   >    # cp -rf perl/* /usr/
   >
   >    # cp -rf armeabi-v7a-shell_cmd/* /usr/
   >
   >    # tar zxvf lyciumCI-armeabi-v7a-perl.tar.gz
   >
   >    # cp -rf perl/* /usr/                                            
   >
   >    # cmake -version                                                              
   >    cmake version 3.26.0-rc5
   >
   >    CMake suite maintained and supported by Kitware (kitware.com/cmake).
   >    ```
   >
   > ```
   >  # make -v
   >  GNU Make 4.4
   >  Built for arm-unknown-linux-gnueabihf
   >  Copyright (C) 1988-2022 Free Software Foundation, Inc.
   >  License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>
   >  This is free software: you are free to change and redistribute it.
   >  There is NO WARRANTY, to the extent permitted by law.
   >
   >  # perl -v
   >  This is perl 5, version 34, subversion 1 (v5.34.1) built for arm-linux
   >
   >  Copyright 1987-2022, Larry Wall
   >
   >  Perl may be copied only under the terms of either the Artistic License or the
   >  GNU General Public License, which may be found in the Perl 5 source kit.
   >
   >  Complete documentation for Perl, including FAQ lists, should be found on
   >  this system using "man perl" or "perldoc perl".  If you have access to the
   >  Internet, point your browser at http://www.perl.org/, the Perl Home Page.
   >
   >  # cp -rf armeabi-v7a-busybox/bin/busybox /bin/                                
   >  # cd /bin
   >
   >  # mv toybox toybox_bak                                          
   >
   >  # toybox_bak mv busybox toybox                                                
   >  # diff -v
   >  diff: invalid option -- 'v'
   >  BusyBox v1.36.0 (2023-03-10 02:22:28 UTC) multi-call binary.
   >
   >  Usage: diff [-abBdiNqrTstw] [-L LABEL] [-S FILE] [-U LINES] FILE1 FILE2
   >
   >  Compare files line by line and output the differences between them.
   >  This implementation supports unified diffs only.
   >
   >     -a  Treat all files as text
   >     -b  Ignore changes in the amount of whitespace
   >     -B  Ignore changes whose lines are all blank
   >     -d  Try hard to find a smaller set of changes
   >     -i  Ignore case differences
   >     -L  Use LABEL instead of the filename in the unified header
   >     -N  Treat absent files as empty
   >     -q  Output only whether files differ
   >     -r  Recurse
   >     -S  Start with FILE when comparing directories
   >     -T  Make tabs line up by prefixing a tab when necessary
   >     -s  Report when two files are the same
   >     -t  Expand tabs to spaces in output
   >     -U  Output LINES lines of context
   >     -w  Ignore all whitespace
   >
   > ```
   >
   > ```
   >
   >
   > 2. **测试脚本确认**
   >
   > **  lycium框架提供了**[HPKCHECK](https://gitee.com/openharmony-si ... m/template/HPKCHECK)文件供开发者对相应的C/C++三方库的自动化测试,如果现成三方库里有这个脚本就可以测试。
   >
   >
   > 3. **测试运行:**
   >
   > **  因为是交叉编译的结果,所以需要将所有东西打包放到设备上进行验证。因此我们需要将原生库的源码及生成文件都作为测试资源打包到开发板进行测试(直接将tpc\_c\_cplusplus直接打包成一个测试资源,并且保证测试资源在开发板的测试路径与编译路径保持一致,避免部分原生库因编译时对测试文件配置了路径而导致测试不过),然后在**[lycium](https://gitee.com/openharmony-si ... /blob/master/lycium)目录下执行脚本./test.sh,自动运行thridparty目录下已编译的三方库,并在终端显示已测试三方库总数以及通过和未通过的三方库。
   >
   >
   > 4. **之前找的DLib没有测试项目,所以找了个简单的,比如cJSON,所以测试下:**
   >
   > ```
   >
   >  # 编译cJSON
   > xx@NJKH_ZLL:~/xx/tpc_c_cplusplus/lycium$ ./build.sh cJSON
   > Build OS linux
   >  OHOS_SDK=/home/xx/xx/tpc_c_cplusplus/lycium/ohos-sdk/linux
   >  CLANG_VERSION=15.0.4
   > Build cJSON v1.7.15 start!
   >    % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
   >                                   Dload  Upload   Total   Spent    Left  Speed
   >    0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
   >  100  344k    0  344k    0     0   229k      0 --:--:--  0:00:01 --:--:--  463k
   > cJSON-1.7.15.tar.gz: OK
   > Compile OpenHarmony armeabi-v7a cJSON v1.7.15 libs...
   > The test must be on an OpenHarmony device!
   > Compile OpenHarmony arm64-v8a cJSON v1.7.15 libs...
   > The test must be on an OpenHarmony device!
   > Build cJSON v1.7.15 end!
   > ALL JOBS DONE!!!
   >
   >  # 确认编译目录,注意是编译目录,不是输出目录
   > xx@NJKH_ZLL:~/xx/tpc_c_cplusplus/lycium$ ls ../thirdparty/cJSON/cJSON-1.7.15/armeabi-v7a-build/ -lh
   > total 336K
   >  -rw-rw-r-- 1 xx xx 125K Mar 26 14:55 build.log
   >  -rw-rw-r-- 1 xx xx  777 Mar 26 14:55 cJSONConfig.cmake
   >  -rw-rw-r-- 1 xx xx  368 Mar 26 14:55 cJSONConfigVersion.cmake
   >  -rwxrwxr-x 1 xx xx  47K Mar 26 14:55 cJSON_test                           # 测试程序
   >  -rw-rw-r-- 1 xx xx  20K Mar 26 14:55 CMakeCache.txt
   > drwxrwxr-x 9 xx xx 4.0K Mar 26 14:55 CMakeFiles
   >  -rw-rw-r-- 1 xx xx  11K Mar 26 14:55 cmake_install.cmake
   >  -rw-rw-r-- 1 xx xx  764 Mar 26 14:55 CTestTestfile.cmake
   > drwxrwxr-x 3 xx xx 4.0K Mar 26 14:55 fuzzing
   >  -rw-rw-r-- 1 xx xx  837 Mar 26 14:55 install_manifest.txt
   >  -rw-rw-r-- 1 xx xx  377 Mar 26 14:55 libcjson.pc
   > lrwxrwxrwx 1 xx xx   13 Mar 26 14:55 libcjson.so -> libcjson.so.1         # 库文件
   > lrwxrwxrwx 1 xx xx   18 Mar 26 14:55 libcjson.so.1 -> libcjson.so.1.7.15
   >  -rwxrwxr-x 1 xx xx  76K Mar 26 14:55 libcjson.so.1.7.15
   >  -rw-rw-r-- 1 xx xx  19K Mar 26 14:55 Makefile
   > drwxrwxr-x 4 xx xx 4.0K Mar 26 14:55 tests
   >
   >
   >  # 设定库路径,运行测试用例
   >
   >  # LD_LIBRARY_PATH=./ ./cJSON_test                                              
   > Version: 1.7.15
   > {
   > "name": "Jack (\"Bee\") Nimble",
   > "format":   {
   > "type": "rect",
   > "width":    1920,
   > "height":   1080,
   > "interlace":    false,
   > "frame rate":   24
   > }
   > }
   > ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
   > [[0, -1, 0], [1, 0, 0], [0, 0, 1]]
   > {
   > "Image":    {
   > "Width":    800,
   > "Height":   600,
   > "Title":    "View from 15th Floor",
   > "Thumbnail":    {
   > "Url":  "http:/*www.example.com/image/481989943",
   > "Height":   125,
   > "Width":    "100"
   > },
   > "IDs":  [116, 943, 234, 38793]
   > }
   > }
   > [{
   > "precision":    "zip",
   > "Latitude": 37.7668,
   > "Longitude":    -122.3959,
   > "Address":  "",
   > "City": "SAN FRANCISCO",
   > "State":    "CA",
   > "Zip":  "94107",
   > "Country":  "US"
   > }, {
   > "precision":    "zip",
   > "Latitude": 37.371991,
   > "Longitude":    -122.026,
   > "Address":  "",
   > "City": "SUNNYVALE",
   > "State":    "CA",
   > "Zip":  "94085",
   > "Country":  "US"
   > }]
   > {
   > "number":   null
   > }
   >
   > ```
   >
   >
   >
   > ```
   >

### 解析Lycium运行规则

##### 解析编译构建脚本build.sh

* **原则:****移植过程,不可以改源码(即不patchc/cpp文件,不patch构建脚本)。如移植必须patch,patch必须评审,给出充分理由。(不接受业务patch)**
* **工作原理:**
  * **输入 build.sh pkgname**
  * **根据 pkgname 从 ../thirdparty/cJSON/HPKBUILD 里执行编译命令**
    ```
    #!/bin/bash

    ......

    main() {
        # 检查编译环境
        checkbuildenv

        # 编译过的库都放到这个csv里,下次可以不编译
        readdonelibs "$LYCIUM_ROOT/usr/hpk_build.csv"

        # 创建lib库,从HPKBUILD里读需要编译的库,并加入hpkPaths队列
        if [ $# -ne 0 ]
        then
            makelibsdir $*
        else
            findmainhpkdir $LYCIUM_ROOT/$hpksdir
            # exit 2
        fi

        # 进入前面构造的hpkPaths对应的编译目录,然后把build_hpk.sh链接进编译目录
        prepareshell ${hpkPaths[@]}
        
        # 开始编译,一般会编译两个 armeabi 和 arm64
        buildhpk

        # 把 prepareshell 做的build链接删掉
        cleanhpkdir
        
        unset LYCIUM_BUILD_OS LYCIUM_ROOT LYCIUM_BUILD_CHECK CLANG_VERSION
    }

    main $*

    # 编译任务不成功, 返回-1
    if [ ${#buildfalselist
  • } -ne 0 -o ${#nextroundlist
  • } -ne 0 ]
        then
            exit -1
        fi
        ```
      * **HPKBUILD解析,**
        * **CMAKE 例子,用cJSON做例子 **
          ```
          # Contributor: Jeff Han <hanjinfei@foxmail.com>
          # Maintainer: Jeff Han <hanjinfei@foxmail.com>

          # 库名称
          pkgname=cJSON

          # 编译版本
          pkgver=v1.7.15
          pkgrel=0
          pkgdesc=""
          url=""

          # 编译架构
          archs=("armeabi-v7a" "arm64-v8a")
          license=("MIT")
          depends=()
          makedepends=()

          # 对应的下载路径,
          source="https://github.com/DaveGamble/$pkgname/archive/refs/tags/$pkgver.tar.gz"

          autounpack=true
          downloadpackage=true

          builddir=$pkgname-${pkgver:1}
          packagename=$builddir.tar.gz

          # 对应的shell脚本动作 prepare
          prepare() {
              mkdir -p $builddir/$ARCH-build
          }

          # 对应的shell脚本动作 build
          build() {
              cd $builddir
              ${OHOS_SDK}/native/build-tools/cmake/bin/cmake "$@" -DOHOS_ARCH=$ARCH -B$ARCH-build -S./ -L > `pwd`/$ARCH-build/build.log 2>&1
              make -j4 -C $ARCH-build >> `pwd`/$ARCH-build/build.log 2>&1
              ret=$?
              cd $OLDPWD
              return $ret
          }

          # 对应的shell脚本动作 package
          package() {
              cd $builddir
              make -C $ARCH-build install >> `pwd`/$ARCH-build/build.log 2>&1
              cd $OLDPWD
          }

          check() {
              echo "The test must be on an OpenHarmony device!"
          }

          # 清理环境
          cleanbuild(){
              rm -rf ${PWD}/$builddir #${PWD}/$packagename
          }
          ```
        * **Make 例子,用CUnit做例子**
          ```
          # Contributor: Jeff Han <hanjinfei@foxmail.com>
          # Maintainer: Jeff Han <hanjinfei@foxmail.com>
          pkgname=CUnit
          pkgver=2.1-3
          pkgrel=0
          pkgdesc=""
          url=""
          archs=("armeabi-v7a" "arm64-v8a")
          license=()
          depends=()
          makedepends=()
          install=
          source="https://sourceforge.net/projects/cunit/files/$pkgname/$pkgver/$pkgname-$pkgver.tar.bz2"

          autounpack=false
          downloadpackage=true
          buildtools="configure"

          builddir=$pkgname-${pkgver}
          packagename=$builddir.tar.bz2

          source envset.sh
          host=
          prepare() {
              mkdir $pkgname-$ARCH-build
              tar -jxf $packagename -C $pkgname-$ARCH-build
              if [ $ARCH == "armeabi-v7a" ]
              then
                  setarm32ENV
                  host=arm-linux
              fi
              if [ $ARCH == "arm64-v8a" ]
              then
                  setarm64ENV
                  host=aarch64-linux
              fi
              cd $pkgname-$ARCH-build/$builddir
              ./bootstrap > `pwd`/build.log 2>&1
              cd $OLDPWD
          }

          build() {
              cd $pkgname-$ARCH-build/$builddir
              ./configure "$@" --host=$host --enable-debug --enable-automated --enable-basic --enable-console --enable-examples --enable-test >> `pwd`/build.log 2>&1
              make -j4 >> `pwd`/build.log 2>&1
              ret=$?
              cd $OLDPWD
              return $ret
          }

          package() {
              cd $pkgname-$ARCH-build/$builddir
              make install >> `pwd`/build.log 2>&1
              cd $OLDPWD
              if [ $ARCH == "armeabi-v7a" ]
              then
                  unsetarm32ENV
              fi
              if [ $ARCH == "arm64-v8a" ]
              then
                  unsetarm64ENV
              fi

              unset host
          }

          check() {
              echo "The test must be on an OpenHarmony device!"
              # 在OpenHarmony开发板中执行用例
              # ./test_cunit
          }

          # 清理环境
          cleanbuild(){
              rm -rf ${PWD}/$pkgname-armeabi-v7a-build ${PWD}/$pkgname-arm64-v8a-build #${PWD}/$packagename
          }
          ```
        * **Make 例子,用CUnit做例子**
          ```
          #!/bin/bash

          # 执行HPKBUILD里对应的方法,如:prepare,build,package,check,cleanbuild
          sure() {
              eval $*
              err=$?
              if [ "$err" != "0" ]
              then
                  echo "ERROR during : $*"
                  echo "ERROR during : $*: $err" > last_error
                  exit 1
              fi
          }

          PKGBUILD_ROOT=$(cd $(dirname ${BASH_SOURCE[0]}); pwd)

          # 下载库压缩包
          # 参数1 链接地址
          # 参数2 压缩包名
          download() {
              if [ -s ${PWD}/$2 ]
              then
                  echo ${PWD}/$2",存在"
              else
                  curl -f -L -k -- "$1" > ${PWD}/$2
                  return $?
              fi
          }

          # 解压库
          # 参数1 压缩包名
          unpack() {
              ......
          }

          # 加载库的编译信息
          source ${PWD}/HPKBUILD

          # 库的完整性校验
          checksum() {
              ......
          }

          ......

          main() {
              # 清理上次的环境
              sure cleanhpk
              # 编译 PKG
              sure builpackage $*
          }

          main $*
          ```

    ### 解析编译结果应用到HAP

    1. **创建native C++工程项目,这个教程太多,不讲了;**
    2. **拷贝编译结果到libs,tpc\_c\_cplusplus/lycium/usr/cJSON里的 armeabi-v7a(32位),arm64-v8a(64位),将里面的so库拷贝到工程路径下(\\entry\\libs)**
       ```
       cjsontes\entry\libs> tree
       ├─arm64-v8a
       │  ├─libcjson.so
       │  ├─libcjson.so.1
       │  └─libcjson.so.1.7.15
       └─armeabi-v7a
          ├─libcjson.so
          ├─libcjson.so.1
          └─libcjson.so.1.7.15

       ```
    3. **拷贝对应的头文件到cpp/thirdparty目录下**
       ```
       cjsontes\entry\src\main\cpp\thirdparty> tree
       ├─arm64-v8a
       │  ├─include
       │    ├─cjson
       └─armeabi-v7a
       │  ├─include
       │    ├─cjson

       ```
    4. **改对应的 CMakeLists.txt**
       ```
       # the minimum version of CMake.
       cmake_minimum_required(VERSION 3.4.1)
       project(cjsontes)

       set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
       set(CJSON_LIB_PATH ${NATIVERENDER_ROOT_PATH}/../../../libs/${OHOS_ARCH})

       include_directories(${NATIVERENDER_ROOT_PATH}
                           ${NATIVERENDER_ROOT_PATH}/include
                           ${NATIVERENDER_ROOT_PATH}/thirdparty/cJSON/${OHOS_ARCH}/include)

       add_library(entry SHARED hello.cpp)
       target_link_libraries(entry PUBLIC
           libace_napi.z.so
           libace_ndk.z.so
           librawfile.z.so
           libhilog_ndk.z.so
           ${CJSON_LIB_PATH}/libcjson.so)
       ```
    5. **改 build-profile.json5 文件**
       ```
       {
         "apiType": "stageMode",
         "buildOption": {
           "externalNativeOptions": {
             "path": "./src/main/cpp/CMakeLists.txt",
             "arguments": "",
             "cppFlags": "",
             # 增加适配的平台
             "abiFilters": [
               "arm64-v8a"
             ]
           }
         },
         "targets": [
           {
             "name": "default",
             "runtimeOS": "HarmonyOS"
           },
           {
             "name": "ohosTest",
           }
         ]
       }
       ```
    6. **改 hello.cpp **
       ```
       #include "napi/native_api.h"
       #include "hilog/log.h"
       #include "cjson/cJSON.h"

       #define GLOBAL_RESMGR (0xFFEE)

       static const char *TAG = "[cjsontest]";

       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);

           // 增加cjson测试代码
           cJSON *parsed = NULL;
           char *content = "[\"Sunday\", \"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\", \"Saturday\"]";
           OH_LOG_Print(LOG_APP, LOG_ERROR, GLOBAL_RESMGR, TAG, "content %{public}s.", content);
           
           parsed = cJSON_Parse(content);

           char *jsonmsg = cJSON_Print(parsed);
           OH_LOG_Print(LOG_APP, LOG_ERROR, GLOBAL_RESMGR, TAG, "jsonprint %{public}s.", jsonmsg);

           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_END

       static 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);
       }

       ```
    7. **测试输出**
       ```
       com.example.cjsontest  E  content ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"].
       com.example.cjsontest  E  jsonprint ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"].
       ```
    [/md]




    欢迎光临 OpenHarmony开发者论坛 (https://forums.openharmony.cn/) Powered by Discuz! X3.5