GMSSL2.x编译鸿蒙静态库和动态库及使用

一、编译环境准备

1.1 开发工具

DevEco-Studio下载。

1.2 SDK下载

下载编译第三方库的SDK有两种方式,第一种方式从官方渠道根据电脑系统选择对应的SDK版本,第二种方式通过DevEco-Studio下载SDK。本文只介绍通过DevEco-Studio下载SDK的方式。

  • 安装SDK到本地
  • 根据SDK安装位置获取SDK
  • 将SDK复制到GMSSL的同级目录并更名为ohos-sdk

二、编译鸿蒙架构

​ 第三方库编译鸿蒙架构有两种方式。一种是使用C/C++原生构建工具configure、makefile编译,一种是使用lycium框架快速交叉编译。本文只详细介绍通过configure、makefile编译的方式。

2.1 原生工具构建

  • 编写编译脚本

    复制代码
    #!/bin/bash
    
    # Define paths and environment variables
    # 获取脚本当前所在路径
    CURRENT_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
    # 获取GmSSL源码路径
    GMSSL_DIR=$CURRENT_PATH/GmSSL2.5.4
    # 取脚本执行的第一个参数
    OHOS_TARGET_ABI=$1
    # 获取鸿蒙SDK路径
    export OHOS_SDK=$CURRENT_PATH/ohos-sdk
    
    # 编译64位架构
    if [ "$OHOS_TARGET_ABI" == "arm64-v8a" ]
    then
        export AS=${OHOS_SDK}/native/llvm/bin/llvm-as
        export CC=${OHOS_SDK}/native/llvm/bin/aarch64-unknown-linux-ohos-clang
        export CXX=${OHOS_SDK}/native/llvm/bin/aarch64-unknown-linux-ohos-clang++
        export LD=${OHOS_SDK}/native/llvm/bin/ld.lld
        export STRIP=${OHOS_SDK}/native/llvm/bin/llvm-strip
        export RANLIB=${OHOS_SDK}/native/llvm/bin/llvm-ranlib
        export OBJDUMP=${OHOS_SDK}/native/llvm/bin/llvm-objdump
        export OBJCOPY=${OHOS_SDK}/native/llvm/bin/llvm-objcopy
        export NM=${OHOS_SDK}/native/llvm/bin/llvm-nm
        export AR=${OHOS_SDK}/native/llvm/bin/llvm-ar
        export CFLAGS="-DOHOS_NDK -fPIC -D__MUSL__=1"
        export CXXFLAGS="-DOHOS_NDK -fPIC -D__MUSL__=1"
        
        outdir=arm64-v8a
        cd ${GMSSL_DIR}
        ./Configure linux-aarch64
        
    elif [ "$OHOS_TARGET_ABI" == "armeabi-v7a" ]
    then
    #编译32位架构
        export AS=${OHOS_SDK}/native/llvm/bin/llvm-as
        export CC=${OHOS_SDK}/native/llvm/bin/armv7-unknown-linux-ohos-clang
        export CXX=${OHOS_SDK}/native/llvm/bin/armv7-unknown-linux-ohos-clang++
        export LD=${OHOS_SDK}/native/llvm/bin/ld.lld
        export STRIP=${OHOS_SDK}/native/llvm/bin/llvm-strip
        export RANLIB=${OHOS_SDK}/native/llvm/bin/llvm-ranlib
        export OBJDUMP=${OHOS_SDK}/native/llvm/bin/llvm-objdump
        export OBJCOPY=${OHOS_SDK}/native/llvm/bin/llvm-objcopy
        export NM=${OHOS_SDK}/native/llvm/bin/llvm-nm
        export AR=${OHOS_SDK}/native/llvm/bin/llvm-ar
        export CFLAGS="-DOHOS_NDK -fPIC -D__MUSL__=1"
        export CXXFLAGS="-DOHOS_NDK -fPIC -D__MUSL__=1"
    
        outdir=armeabi-v7a
        cd ${GMSSL_DIR}
        ./Configure linux-generic32
        
    elif [ "$OHOS_TARGET_ABI" == "x86_64" ]
    then
    #编译32位架构
        export AS=${OHOS_SDK}/native/llvm/bin/llvm-as
        export CC=${OHOS_SDK}/native/llvm/bin/x86_64-unknown-linux-ohos-clang
        export CXX=${OHOS_SDK}/native/llvm/bin/x86_64-unknown-linux-ohos-clang++
        export LD=${OHOS_SDK}/native/llvm/bin/ld.lld
        export STRIP=${OHOS_SDK}/native/llvm/bin/llvm-strip
        export RANLIB=${OHOS_SDK}/native/llvm/bin/llvm-ranlib
        export OBJDUMP=${OHOS_SDK}/native/llvm/bin/llvm-objdump
        export OBJCOPY=${OHOS_SDK}/native/llvm/bin/llvm-objcopy
        export NM=${OHOS_SDK}/native/llvm/bin/llvm-nm
        export AR=${OHOS_SDK}/native/llvm/bin/llvm-ar
        export CFLAGS="-DOHOS_NDK -fPIC -D__MUSL__=1"
        export CXXFLAGS="-DOHOS_NDK -fPIC -D__MUSL__=1"
    
        outdir=x86_64
        # Navigate to OpenSSL directory
        ./Configure linux-x86_64
        
    else
        echo "Unsupported target ABI: $ANDROID_TARGET_ABI"
        exit 1
    fi
    
    make
    
    # Copy the outputs
    OUTPUT_INCLUDE=$CURRENT_PATH/ohos_libs/include
    OUTPUT_LIB=$CURRENT_PATH/ohos_libs/lib/${outdir}
    mkdir -p $OUTPUT_INCLUDE
    mkdir -p $OUTPUT_LIB
    cp -RL include/openssl $OUTPUT_INCLUDE
    cp libcrypto.so.1.1 $OUTPUT_LIB
    cp libcrypto.a $OUTPUT_LIB
    cp libssl.so.1.1 $OUTPUT_LIB
    cp libssl.a $OUTPUT_LIB

    将编写好的脚本文件命名为ohos.sh。文件之间的目录结构如下:

  • 执行脚本

    cd到HarmonyOS-SDK目录下,依次执行如下命令,分别编译64位、32位、x86_64的鸿蒙架构。

    复制代码
    ohos.sh  arm64-v8a
    
    ohos.sh  armeabi-v7a
    
    ohos.sh  x86_64
  • 编译问题

    解决方案:删除GMSSL2.5.4源码中对getcontext、makecontext、setcontext等函数的引用。

三、使用库文件

​ 鸿蒙工程可以使用.a的静态库和.so的动态库,两种类型的库引用一种即可。

3.1 创建NAPI工程

​ NAPI是OpenHarmony系统中的原生模块扩展开发框架,提供JavaScript与C/C++模块之间相互调用的交互能力。

  • 添加二进制文件到工程

如果该三方库二进制文件为so文件,还需要将so文件拷贝到工程目录的entry/libs/${OHOS_ARCH}/目录下,如下图:

3.2 配置链接

​ 添加二进制文件后需要在cpp目录的CMakeLists.txt文件中添加对应target_link_libraries才能被工程引用。

  • 配置静态库链接

    复制代码
    target_link_libraries(product PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/gmssl/${OHOS_ARCH}/lib/libcrypto.a)
    target_link_libraries(product PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/gmssl/${OHOS_ARCH}/lib/libssl.a)
  • 配置动态库链接

    复制代码
    target_link_libraries(product PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/gmssl/${OHOS_ARCH}/lib/libcrypto.so)
    target_link_libraries(product PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/gmssl/${OHOS_ARCH}/lib/libssl.so)
  • 配置头文件

    复制代码
    target_include_directories(product PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/gmssl/${OHOS_ARCH}/include)

四、编写NAPI接口

​ 配置完三方库的链接和头文件路径后,可以根据各自的业务逻辑调用三方库对应的接口完成NAPI接口的编写,NAPI接口开发可以参照以下文档学习。

  1. 使用Node-API实现跨语言交互开发流程

  2. C/C++三方库使用

4.1 NAPI编写示例

​ NAPI接口编写的基本思路是将从JavaScript层传入的参数转成C/C++数据类型,然后调用第三方库接口执行业务逻辑,最后将执行的结果转成JavaScript数据类型返回给JavaScript层。

  • 编写接口

    napi_init.cpp文件中编写NAPI接口。

第一步:获取JS层传入的参数转成C/C++数据类型并将转换的结果作为参数传入第三方库函数中。

复制代码
static napi_value gm_post(napi_env env, napi_callback_info info){
    size_t argc = 4;
    napi_value args[4];
    // 获取JS参数
    napi_get_cb_info(env, info, &argc, args , nullptr, nullptr);
    char url[512] = {0},parameter[MAX_BUF] = {0}, filePath[1024] = {0};
    size_t url_len,parameter_len,filePath_len;
    double timeOut;
    // 获取请求地址 napi(JS)数据类型转c/c++数据类型
    napi_get_value_string_utf8(env, args[0], url, sizeof(url), &url_len);
    // 获取请求参数 napi(JS)数据类型转c/c++数据类型
    napi_get_value_string_utf8(env, args[1], parameter, sizeof(parameter), &parameter_len);
    // 获取超时时间
    napi_get_value_double(env, args[2], &timeOut);
    // 获取证书路径
    napi_get_value_string_utf8(env, args[3], filePath, sizeof(filePath), &filePath_len);
    // 调用gmssl库的post请求方法
    resp_t *resp = infosecPost(url, parameter, timeOut, NULL, filePath);
    // 格式转换后返回响应数据
    return transformRespToNapi(env, resp);
}

第二步:将第三方库返回的结果转成JavaScript数据类型

复制代码
static napi_value transformRespToNapi(napi_env env,resp_t *resp){
    napi_value res_obj;
    // 1.创建对象
    napi_status status = napi_create_object(env, &res_obj);
    if (status != napi_ok) {
        napi_throw_error(env,"-1","创建响应数据对象异常");
        return nullptr;
    }
    // 2.创建data属性值
    napi_value res_data;
    status = napi_create_string_utf8(env, resp->data, NAPI_AUTO_LENGTH, &res_data);
    if (status != napi_ok) {
        napi_throw_error(env,"-2","创建属性值异常");
        return nullptr;
    }
    status = napi_set_named_property(env, res_obj, "data", res_data);
    if (status != napi_ok) {
        napi_throw_error(env,"-3","设置对象的属性异常");
        return nullptr;
    }
    // 3.创建code属性
    napi_value res_code;
    status = napi_create_double(env, resp->code, &res_code);
     if (status != napi_ok) {
        napi_throw_error(env,"-2","创建属性值异常");
        return nullptr;
    }
    status = napi_set_named_property(env, res_obj, "code", res_code);
    if (status != napi_ok) {
        napi_throw_error(env,"-3","设置对象的属性异常");
        return nullptr;
    }
    resp_free(resp);
    return res_obj;
}

第三步:ArkTS接口与C/C++接口绑定和映射

复制代码
EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports)
{
    napi_property_descriptor desc[] = {
        { "send_gm_post", nullptr, gm_post, nullptr, nullptr, nullptr, napi_default, nullptr }
    };
    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
    return exports;
}
EXTERN_C_END

​ 说明:send_gm_post是ArkTS的函数名,gm_post是C/C++函数名。

  • 声明ArkTS侧的方法

Index.d.ts文件中声明ArkTS侧的方法。

复制代码
export const send_gm_post: (url: string,parameters:string,timeOut:number,caPath:string) => object;
相关推荐
聪明的笨猪猪5 小时前
企业知识库AI架构选型:落地导向的架构决策与组件清单
经验分享·面试·架构·embedding·数据库架构
Go Work7 小时前
两个等值条件摆着,MySQL 偏要全表扫
经验分享·笔记
深圳智根网络程序开发12 小时前
WordPress固定链接怎么设?改不对谷歌收录直接崩
经验分享
德思特12 小时前
如何提升 5G 移动性切换验证效率?德思特 Amarisoft Callbox 新增 NR SA LTM 测试功能详解
经验分享·无线通信·车载通信
虹科数字化与AR15 小时前
农业机械AR质检ROI怎么算?从搬运、测量、返工和交付成本入手
经验分享·ar·质检·农业机械
聪明的笨猪猪1 天前
Java 工程案例:AI 生成 @Async 异步线程池踩坑
java·经验分享·面试·ai编程
仓库日记2 天前
Excel进销存何时该换?用3项检查判断是否需要软件
经验分享·excel·进销存·开单软件
AI工具挖掘机2 天前
开源!2个Skill复刻带货视频、图文和Live,做百号矩阵
经验分享
虹科网络安全2 天前
Redis Radar:在统一视图中掌握 Redis 部署、健康与容量
经验分享·redis·艾体宝·艾体宝it·艾体宝redis
聪明的笨猪猪2 天前
实际工程问题:AI 生成 Spring Cache(@Cacheable / @CachePut / @CacheEvict)缓存注解踩坑
java·经验分享·面试·ai编程