多so相互依赖场景下如何解耦

A模块包含a.so,B模块包含b.so。a.so中有调用b.so的函数,b.so中也有调用a.so的函数。如果按照正常编译步骤,无论先编译哪个so,均会编译失败。

HarmonyOS
2024-01-19 14:54:58
浏览
收藏 0
回答 1
待解决
回答 1
按赞同
/
按时间
rcshi

通过dlopen和dlsym接口进行so编译依赖解耦,将隐式依赖转为显式依赖。

示例代码

1. 修改代码和CMakeLists.txt文件,利用Native侧dlopen方法编译出liba.so、libb.so。生成的.so文件在build/default/intermediates/cmake/default/obj目录下。

(注意一定要用extern "C" {}括起来、不然不能识别到对应的函数导致编译出错)

// a.cpp 
extern "C" {     // 一定要用extern "C" {}括起来 
#include "a.h" 
#include <dlfcn.h> 
#include "stdio.h" 
typedef int (*FUNC_SUB)(int, int); 
int add(int a, int b) { return a + b; } 
int getb(char *path, int a, int b) {       // path:从ArkTS侧传递So文件的沙箱路径(注意路径要从arkts侧传递、不然有可能找不到路径、具体代码后续会列出) 
    void *handle = dlopen(path, RTLD_LAZY);  // 打开一个动态链接库.路径为path 
    if (!handle) { 
        return 0; 
    } 
    FUNC_SUB sub_func = (FUNC_SUB)dlsym(handle, "sub"); // 获取函数名为sub的函数 
    int res = sub_func(a, b);                           // 调用函数 
    dlclose(handle);                                    // close动态链接库 
    return res; 
} 
} 
// a.h 
extern "C" { 
#ifndef DemoSO_a_H 
#define DemoSO_a_H 
int add(int a, int b); 
int getb(char *path, int a, int b); 
#endif // DemoSO_a_H 
} 
// b.cpp 
extern "C" {     // 一定要用extern "C" {}括起来 
#include "b.h" 
#include <dlfcn.h> 
#include "stdio.h" 
typedef int (*FUNC_ADD)(int, int); 
int sub(int a, int b) { return a - b; } 
int geta(char *path, int a, int b) {    // path:从ArkTS侧传递So文件的沙箱路径(注意路径要从arkts侧传递、不然有可能找不到路径、具体代码后续会列出) 
    void *handle = dlopen(path, RTLD_LAZY);    // 打开一个动态链接库.路径为path 
    if (!handle) { 
        return 0; 
    } 
    FUNC_ADD add_func = (FUNC_ADD)dlsym(handle, "add");      // 获取函数名为add的函数 
    int res = add_func(a, b);                                // 调用函数 
    dlclose(handle);                                         // close动态链接库 
    return res; 
} 
} 
// b.h 
extern "C" { 
#ifndef DemoSO_b_H 
#define DemoSO_b_H 
int sub(int a, int b); 
int geta(char *path, int a, int b); 
#endif // DemoSO_b_H 
} 
// CMakeLists.txt 
cmake_minimum_required(VERSION 3.4.1) 
project(liba) 
add_library(a SHARED a.cpp)                  // 编译库liba.so 
target_link_libraries(a PUBLIC libace_napi.z.so libhilog_ndk.z.so) 
project(libb) 
add_library(b SHARED b.cpp)                  // 编译库libb.so 
target_link_libraries(b PUBLIC libace_napi.z.so libhilog_ndk.z.so)

2. 将生成的.so文件(相对路径:build/default/intermediates/cmake/default/obj)移动到libs目录下。

移动完之后的目录结构如下:

3. 修改CMakeLists.txt文件将编译生成的.so引入到工程中编译使用即可。

// CMakeLists.txt 
cmake_minimum_required(VERSION 3.4.1) 
project(DemoSO) 
set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}) 
include_directories(${NATIVERENDER_ROOT_PATH} 
                    ${NATIVERENDER_ROOT_PATH}/include) 
add_library(demoso SHARED hello.cpp)                        // 添加libdemoso.so文件 
// 添加依赖库liba.so、libb.so。 注意需要带上路径、不然无法找到对应的so库 
target_link_libraries(demoso PUBLIC libace_napi.z.so ${CMAKE_CURRENT_SOURCE_DIR}/../../../libs/${OHOS_ARCH}/liba.so ${CMAKE_CURRENT_SOURCE_DIR}/../../../libs/${OHOS_ARCH}/libb.so) 
 
// index.ets 
import { hilog } from '@kit.LancetKit'; 
import testNapi from 'libdemoso.so'; 
@Entry 
@Component 
struct Index { 
  @State message: string = 'Hello World'; 
  private path: string = ''; 
 
  build() { 
    Row() { 
      Column() { 
        Text(this.message) 
          .fontSize(50) 
          .fontWeight(FontWeight.Bold) 
          .onClick(() => { 
            this.path = getContext(this).bundleCodeDir;   // 获取路径 
            hilog.info(0x0000, 'testTag', 'Test NAPI 5 + 3 = %{public}d', testNapi.add(5, 3, this.path + '/libs/arm64/liba.so'));  // 调用native侧函数 
            hilog.info(0x0000, 'testTag', 'Test NAPI 5 - 3 = %{public}d', testNapi.sub(5, 3, this.path + '/libs/arm64/libb.so')); 
          }) 
      } 
      .width('100%') 
    } 
    .height('100%') 
  } 
} 
 
// index.d.ts 
export const add: (a: number, b: number, path: string) => number; 
export const sub: (a: number, b: number, path: string) => number; 
 
// hello.cpp 
#include "a.h" 
#include "b.h" 
#include "napi/native_api.h" 
 
static napi_value Add(napi_env env, napi_callback_info info) { 
    size_t requireArgc = 3; 
    size_t argc = 3; 
    napi_value args[3] = {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); 
    napi_valuetype valuetype2; 
    napi_typeof(env, args[2], &valuetype2); 
    int value0; 
    napi_get_value_int32(env, args[0], &value0); 
    int value1; 
    napi_get_value_int32(env, args[1], &value1); 
    char path[255]; 
    size_t size = 255; 
    napi_get_value_string_utf8(env, args[2], path, 255, &size); 
    int res = geta(path, value0, value1);                    // 调用函数并传递沙箱路径 
    napi_value sum; 
    napi_create_int32(env, res, &sum); 
    return sum; 
} 
static napi_value Sub(napi_env env, napi_callback_info info) { 
    size_t requireArgc = 3; 
    size_t argc = 3; 
    napi_value args[3] = {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); 
    napi_valuetype valuetype2; 
    napi_typeof(env, args[2], &valuetype2); 
    int value0; 
    napi_get_value_int32(env, args[0], &value0); 
    int value1; 
    napi_get_value_int32(env, args[1], &value1); 
    char path[255]; 
    size_t size = 255; 
    napi_get_value_string_utf8(env, args[2], path, 255, &size); 
    int res = getb(path, value0, value1);                 // 调用函数并传递沙箱路径 
    napi_value sum; 
    napi_create_int32(env, res, &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}, 
                                       {"sub", nullptr, Sub, 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 = "demoso", 
    .nm_priv = ((void *)0), 
    .reserved = {0}, 
}; 
extern "C" __attribute__((constructor)) void RegisterDemosoModule(void) { napi_module_register(&demoModule); }
分享
微博
QQ
微信
回复
2024-01-19 20:54:09
相关问题
如何解决module相互依赖问题
564浏览 • 1回复 待解决
module场景Hvigor自定义扩展咨询
346浏览 • 1回复 待解决
如何设备情况使用hdc
325浏览 • 1回复 待解决
so放在libs文件后需要如何调用
803浏览 • 1回复 待解决
PolarDB在云用的吗?
2500浏览 • 1回复 待解决
win11安装hpm报错如何解决?
4885浏览 • 2回复 待解决
什么情况会使用Module
1174浏览 • 1回复 待解决
什么场景需要使用到多个UIAbility
872浏览 • 1回复 待解决
flutter和鸿蒙如何相互调用?
12660浏览 • 3回复 待解决
px和vp之间如何相互转换
771浏览 • 1回复 待解决