OpenHarmony Tripartite library porting

Getting your Trinity Audio player ready...

Tutorial on tripartite library porting process for OpenHarmony systems.

1. Download the native library

When downloading the native library, do not download the master branch, but download the latest version branch.

2. Generate a Makefile

Downloading different native third-party libraries may provide different compilation methods, according to the README file of the native third-party library, you can know how to compile, the following two compilation methods:

Living In Harmony is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.

Subscribed

1.cmake build
In the root directory of the downloaded method library, CMakeLists exists.txt file
#Create a new build directory
mkdir mybuild && cd mybuild
Through cmake.. Build, at this time, the Makefile file will be generated according to the default configuration options
Through cmake-gui.. Build, the build optional pop-up box will pop up at this time, and the Makefile file will be generated with optional configuration
2.Makefile.am build
Generally, Makefile.am is used to build, and the autogen.sh and configure.ac files exist in the native library.
./autogen.sh
./configure
A Makefile will be generated at this time

3. Analyze the dependence of the library on external libraries

Analyze the log information in the process of generating the Makefile and find the dependencies of this library on other libraries. During the log analysis process, the following situations generally exist:
1. The library name cannot be found in the log. When some third-party libraries generate Makefile files, if the corresponding library can be found in the system, it will not be printed in the log. This kind of situation will be transplanted to OpenHarmony. The compilation process will be reflected in errors. Typically, the header file path cannot be found or the function symbol is missing when linking;
2. Found or not found libraries can be found in the log. By default, these libraries do not exist on OpenHarmony, so these libraries need to be analyzed.
1. os-developed libraries, which can be found in the third_party directory of OpenHarmony;
2. Undeveloped libraries and libraries that are in the plan can be transplanted first, reported and the workload re-evaluated;
3. Undeveloped libraries and libraries that are not planned. Analyze these libraries. Generally, these libraries are divided into two categories. ① There is an impact on the library function, ② There is no impact on the library function. In this part, you need to find the library-related Local analysis code, if it does not affect the function, you can consider ignoring it, otherwise report it and re-evaluate the workload problem;
Each dependent third-party library generally has a corresponding macro definition to control the compilation of the code in the library. During the process of transplanting the third-party library, if there are many library dependencies, you need to pay attention to the switches of these macro definitions.

You can refer to minizip library dependency analysis

四、编译库,并分析Makefile

By analyzing the Makefile,
1. Find the source code required to generate the library, header file path, cflags/cflags_cc, macro definitions, and dependent libraries
2. Find the source code required to generate test/demo, header file path, cflags/cflags_cc, macro definitions, and dependent libraries

5. GNIZATION

The results obtained from the analysis are compiled into the OHOS system, and refer to the compilation and construction guide on the official website.

Explain with zxing-cpp-1.2.0, download zxing-cpp-1.2.0 from github and put it in the third_party of OpenHarmony-3.2-Beta1. Warehouse address.

Modify the following file to add zxing-cpp-1.2.0 to the RK3568 board:

vendor/hihope/rk3568/config.json

Add code:

{
      "subsystem": "zxing-cpp-1.2.0",
      "components": [
        {
          "component": "zxing-cpp-1.2.0",
          "features": []
        }
      ]
    },

Modify the following file to add zxing-cpp-1.2.0 to the subsystem:

build/subsystem_config.json

Add code:

 "zxing-cpp-1.2.0": {
    "path": "third_party/zxing-cpp-1.2.0",
    "name": "zxing-cpp-1.2.0"
  },

Create zxing-cpp-1.2.0 to create the compilation component ohos.build:

third_party/zxing-cpp-1.2.0/ohos.build

Add code:

{
  "subsystem": "zxing-cpp-1.2.0",
  "parts": {
    "zxing-cpp-1.2.0": {
      "module_list": [
        "//third_party/zxing-cpp-1.2.0/example:ZXingReader",
        "//third_party/zxing-cpp-1.2.0/example:ZXingWriter"
      ],
      "inner_kits": [
              ],
      "system_kits": [
      ],
      "test_list": [
      ]
    }
  }
}

Create a GNN file of zxing-cpp-1.2.0 test:

third_party/zxing-cpp-1.2.0/example/BUILD.gn

Add the code as follows:

#Copyright (c) 2021 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import("//build/ohos.gni")

config("public"){
    cflags_cc = [
    "-fexceptions",
    "-O3",
    "-DNDEBUG",
    "-std=c++11",
    ]
}


config("libnl_config") {
    include_dirs = [
        "//third_party/zxing-cpp-1.2.0/core",
        "//third_party/zxing-cpp-1.2.0/thirdparty/stb"
    ]
}

ohos_executable("ZXingReader") {
    sources = [
        "ZXingReader.cpp"
    ]
    public_configs = [ ":libnl_config" ]
    deps = [
        "//third_party/zxing-cpp-1.2.0:zxing_share"
    ]
    configs = [ ":public" ]
    part_name = "zxing-cpp-1.2.0"
}

ohos_executable("ZXingWriter") {
    sources = [
        "ZXingWriter.cpp"
    ]
    public_configs = [ ":libnl_config" ]
    deps = [
        "//third_party/zxing-cpp-1.2.0:zxing_share"
    ]
    configs = [ ":public" ]
    part_name = "zxing-cpp-1.2.0"
}

Create a dynamic library GNN file for zxing-cpp-1.2.0:

third_party/zxing-cpp-1.2.0/BUILD.gn

Add the code as follows:


# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation version 2.1
# of the License.
#
# Copyright(c) 2021-2022 Huawei Device Co., Ltd.

if (!defined(ohos_lite)) {
  import("//build/ohos.gni")
}
config("public"){
    cflags_cc = [
    "-fexceptions",
    "-O3",
    "-DNDEBUG",
    "-fPIC",
    "-Wall",
    "-Wextra",
    "-Wno-missing-braces",
    "-Werror=undef",
    "-pthread",
    "-std=c++17",
    "-Wno-error=deprecated-declarations",
    "-Wno-deprecated-declarations",
    "-Wno-error=sign-compare"
    ]
}

if (!defined(ohos_lite)) {
  config("libnl_config") {
    include_dirs = [
        "core/src",
        "core/aztec",
        "core/datamatrix",
        "core/maxicode",
        "core/oned",
        "core/pdf417",
        "core/qrcode",
        "core/textcodex",
    ]
  }

ohos_shared_library("zxing_share") {
    public_configs = [ ":libnl_config" ]
    sources = [
        "core/src/CharacterSetECI.cpp",
        "core/src/BitSource.cpp",
        "core/src/ZXBigInteger.cpp",
        "core/src/TextUtfEncoding.cpp",
        "core/src/HybridBinarizer.cpp",
        "core/src/TextEncoder.cpp",
        "core/src/BitMatrixIO.cpp",
        "core/src/textcodec/KRTextEncoder.cpp",
        "core/src/textcodec/Big5TextDecoder.cpp",
        "core/src/textcodec/JPTextDecoder.cpp",
        "core/src/textcodec/KRHangulMapping.cpp",
        "core/src/textcodec/JPTextEncoder.cpp",
        "core/src/textcodec/Big5MapTable.cpp",
        "core/src/textcodec/GBTextEncoder.cpp",
        "core/src/textcodec/Big5TextEncoder.cpp",
        "core/src/textcodec/KRTextDecoder.cpp",
        "core/src/textcodec/GBTextDecoder.cpp",
        "core/src/MultiFormatReader.cpp",
        "core/src/GenericGF.cpp",
        "core/src/qrcode/QRFormatInformation.cpp",
        "core/src/qrcode/QRErrorCorrectionLevel.cpp",
        "core/src/qrcode/QRCodecMode.cpp",
        "core/src/qrcode/QRMatrixUtil.cpp",
        "core/src/qrcode/QRMaskUtil.cpp",
        "core/src/qrcode/QRReader.cpp",
        "core/src/qrcode/QRWriter.cpp",
        "core/src/qrcode/QRDataBlock.cpp",
        "core/src/qrcode/QRBitMatrixParser.cpp",
        "core/src/qrcode/QRDecoder.cpp",
        "core/src/qrcode/QREncoder.cpp",
        "core/src/qrcode/QRDetector.cpp",
        "core/src/qrcode/QRVersion.cpp",
        "core/src/PerspectiveTransform.cpp",
        "core/src/pdf417/PDFModulusPoly.cpp",
        "core/src/pdf417/PDFBarcodeValue.cpp",
        "core/src/pdf417/PDFDetector.cpp",
        "core/src/pdf417/PDFCodewordDecoder.cpp",
        "core/src/pdf417/PDFBoundingBox.cpp",
        "core/src/pdf417/PDFDecodedBitStreamParser.cpp",
        "core/src/pdf417/PDFWriter.cpp",
        "core/src/pdf417/PDFModulusGF.cpp",
        "core/src/pdf417/PDFReader.cpp",
        "core/src/pdf417/PDFHighLevelEncoder.cpp",
        "core/src/pdf417/PDFEncoder.cpp",
        "core/src/pdf417/PDFDetectionResult.cpp",
        "core/src/pdf417/PDFScanningDecoder.cpp",
        "core/src/pdf417/PDFDetectionResultColumn.cpp",
        "core/src/GTIN.cpp",
        "core/src/GenericLuminanceSource.cpp",
        "core/src/GenericGFPoly.cpp",
        "core/src/Result.cpp",
        "core/src/BinaryBitmap.cpp",
        "core/src/ConcentricFinder.cpp",
        "core/src/datamatrix/DMHighLevelEncoder.cpp",
        "core/src/datamatrix/DMDetector.cpp",
        "core/src/datamatrix/DMVersion.cpp",
        "core/src/datamatrix/DMReader.cpp",
        "core/src/datamatrix/DMECEncoder.cpp",
        "core/src/datamatrix/DMDataBlock.cpp",
        "core/src/datamatrix/DMDecoder.cpp",
        "core/src/datamatrix/DMSymbolInfo.cpp",
        "core/src/datamatrix/DMBitLayout.cpp",
        "core/src/datamatrix/DMWriter.cpp",
        "core/src/MultiFormatWriter.cpp",
        "core/src/BarcodeFormat.cpp",
        "core/src/GlobalHistogramBinarizer.cpp",
        "core/src/WhiteRectDetector.cpp",
        "core/src/TextDecoder.cpp",
        "core/src/LuminanceSource.cpp",
        "core/src/BitMatrix.cpp",
        "core/src/DecodeStatus.cpp",
        "core/src/ReedSolomonDecoder.cpp",
        "core/src/oned/ODMultiUPCEANReader.cpp",
        "core/src/oned/ODCode128Patterns.cpp",
        "core/src/oned/ODUPCAWriter.cpp",
        "core/src/oned/ODDataBarExpandedReader.cpp",
        "core/src/oned/rss/ODRSSGenericAppIdDecoder.cpp",
        "core/src/oned/rss/ODRSSFieldParser.cpp",
        "core/src/oned/rss/ODRSSExpandedBinaryDecoder.cpp",
        "core/src/oned/ODDataBarReader.cpp",
        "core/src/oned/ODDataBarCommon.cpp",
        "core/src/oned/ODRowReader.cpp",
        "core/src/oned/ODCode93Reader.cpp",
        "core/src/oned/ODCode128Reader.cpp",
        "core/src/oned/ODCode93Writer.cpp",
        "core/src/oned/ODEAN13Writer.cpp",
        "core/src/oned/ODCode39Writer.cpp",
        "core/src/oned/ODCode128Writer.cpp",
        "core/src/oned/ODITFWriter.cpp",
        "core/src/oned/ODITFReader.cpp",
        "core/src/oned/ODEAN8Writer.cpp",
        "core/src/oned/ODUPCEANCommon.cpp",
        "core/src/oned/ODCodabarReader.cpp",
        "core/src/oned/ODCode39Reader.cpp",
        "core/src/oned/ODCodabarWriter.cpp",
        "core/src/oned/ODWriterHelper.cpp",
        "core/src/oned/ODUPCEWriter.cpp",
        "core/src/oned/ODReader.cpp",
        "core/src/ReadBarcode.cpp",
        "core/src/DecodeHints.cpp",
        "core/src/ResultMetadata.cpp",
        "core/src/ResultPoint.cpp",
        "core/src/ReedSolomonEncoder.cpp",
        "core/src/BitArray.cpp",
        "core/src/maxicode/MCBitMatrixParser.cpp",
        "core/src/maxicode/MCDecoder.cpp",
        "core/src/maxicode/MCReader.cpp",
        "core/src/aztec/AZHighLevelEncoder.cpp",
        "core/src/aztec/AZReader.cpp",
        "core/src/aztec/AZDetector.cpp",
        "core/src/aztec/AZWriter.cpp",
        "core/src/aztec/AZEncoder.cpp",
        "core/src/aztec/AZToken.cpp",
        "core/src/aztec/AZDecoder.cpp",
        "core/src/GridSampler.cpp",
    ]
    defines = [
        "NL_DEBUG",
        "ZXing_EXPORTS",
    ]

    configs = [ ":public" ]
    part_name = "zxing-cpp-1.2.0"
  }
}

6. Test on the board

Enter HB SET, select RK3568, and then enter HB Build to compile.

For the programming program, refer to RK3568 programming

After the compilation is completed on the PC side, two test programs will be generated: ZXingReader and ZXingWriter, and you can run the program directly to view the functions:

image-20220530145450977

Writing a shell script through the program’s functions is actually running all the functions supported by the program (file zxing-cpp-1.2.0/test/libzxing_test.sh).

Verification on the PC side

Run the following without error:

image-20220530150348471

OpenHarmony3.2_Beta verify the following in the RK3568 board:

image-20220531143400262

7. API interface export

Run this API interface export script on the PC side, and use the dynamic library SO to run the export script.

1. Create allHeads.h, which contains the header files exported from all libraries. zxing-cpp has two test programs, ZXingReader and ZXingWriter, and the header files of the libZXing.so used are as follows:

image-20220530113003137

2. Add the allDySos directory, which places all generated dynamic libraries:

image-20220530113557352

3. Add the allTests directory, which places all the generated test files:

image-20220530113605200

4. Create a new automated test script export_interface.sh, the script code is as follows, and when executing, you need to pass the parameters of the compilation header file to the script, such as ./export_interface.sh -I The path where the header file is located -D macro definition (the parameters in cflags/cflags_cc when compiling all dynamic libraries).

where cxx=”1″ indicates that the export is based on the cpp file:

#!/bin/sh
#C++库
cxx="1"

mixed_api() {
    
    while read line
    do
        if [ $cxx != "1" -o "$4" == "1" ];then
            tmp=$line
        else
            tmp=`echo $line | sed "s/(.*$//g" | sed "s/^.*:://g"`
        fi
        res=`cat $2 |grep "$tmp" -F`
        if [ "$res" != "" ];then
            echo "$line" >> $3
        fi
    done < $1
}

remove_standard_api() {
    flag="0"
    while read line
    do
        tmp1=`echo $line |grep ".*#.*\/usr\/"`
        tmp2=`echo $line |grep ".*#.*[0-9].*\".*\""`
        if [ "$tmp1" != "" ];then
            flag="0"
        elif [ "$tmp2" != "" ];then
            flag="1"
        elif [ $flag == "1" ];then
            echo "$line" >> $2
        fi
    done < $1
}

src1="allHeads.h"
src2="allDySos"
src3="allTests"

if [ $cxx == "1" ];then
    flags_D="-DC"
    flags_DU="-DCu"
    CC=g++
else
    flags_D="-D"
    flags_DU="-Du"
    CC=gcc
fi

if [ ! -e $src1 ];then
    echo "$src1 is not exist!"
    exit 1
fi

if [ ! -e $src2 ];then
    echo "$src2 is not exist!"
    exit 1
fi

if [ ! -e $src3 ];then
    echo "$src3 is not exist!"
    exit 1
fi

rm -rf $src1.i* $src2.txt $src3.txt export_api.txt tested_api.txt

$CC -E $* $src1 -o $src1.i

if [ "$?" != "0" ];then
    exit 1
fi

remove_standard_api $src1.i $src1.i.tmp

nm $src2/* $flags_D | sort -u | grep " T " | sed "s/^.* T //g" >> $src2.txt
nm $src3/* $flags_DU | sort -u | sed "s/^.* U //g" >> $src3.txt

mixed_api $src2.txt $src1.i.tmp export_api.txt 0
mixed_api export_api.txt $src3.txt  tested_api.txt 1

rm -rf $src1.i* $src2.txt $src3.txt

In the export zxing-cpp field, enter the following command:

./export_interface.sh -I../core/src/ -I../thirdparty/stb/ -DZXing_EXPORTS

Generate export_api.txt (export SO external API interface) and testd_api.txt (export SO external export API interface used by export test program).

image-20220530114321245

8. Go to the warehouse

At present, the sig repository is not ready, after the migration is completed, temporarily upload the personal repository, the uploaded content includes the native library code (except for the part that needs to modify the native library code, nothing else can be uploaded, such as the intermediate file generated during compilation), BUILD.gn, README.Opensource, all API interface export_api.txt exported from the library, and the tested API interface tested_api.txt

README. Opensource, the format is as follows:

[
    {
        "Name"            : "zxing-cpp",
        "License"         : "Apache License"
        "License File"    : "LICENSE",
        "Version Number"  : "1.2.0",
        "Owner"           : "zhangrong50@h-partners.com",
        "Upstream URL"    : "https://github.com/nu-book/zxing-cpp",
        "Description"     : "ZXing-C++ ("zebra crossing") is an open-source, multi-format 1D/2D barcode image processing library implemented in C++"
    }
]