android的ndk下,解决两个so相互调用的问题

在Android的NDK环境中,遇到A、B两个C语言实现的模块,各自编译为liba.so和libb.so,两者相互调用函数导致编译失败。为了解决这个问题,采用了动态加载库的方式,利用dlopen和dlsym在运行时加载函数,避免编译时的依赖。这样,即使a.c需要调用b.c的GetStringB(),b.c调用a.c的GetStringA(),也能成功编译并运行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

A、B两个模块,主要都是用C实现的,需要用ndk编译成两个a.so、b.so,但是a.so内调用b.so中的函数,b.so内也调用了a.so中的函数,而且由于某些原因A、B必须分开编译。问题是无论先编译那个模块都会编译不通过,因为它们相互依赖。

为了编译通过,必须在编译时取消这种依赖关系,下面程序中使用dlopen打开so,dlsym获取函数指针,就避免了这种编译依赖关系。

a.c

#include <stdio.h> 

#include <stdlib.h> 

#include <stdarg.h> 

#include <dlfcn.h> 

#include <jni.h> 



char * GetStringA(void) 

{ 

    return "i am in a.so"; 

} 

 

jstring Java_com_ckl_SoCallSo_SoCallSoActivity_fucntionInA(JNIEnv* env, jobject thiz) 

{ 

    return (*env)->NewStringUTF(env, GetStringA()); 

} 



jstring Java_com_ckl_SoCallSo_SoCallSoActivity_AcallB(JNIEnv* env, jobject thiz) 

{ 

    jstring ret; 

    //so路径:/data/data/我的程序的包名/lib/我的so文件名 

    void *  filehandle = dlopen("/data/data/com.ckl.SoCallSo/lib/libb.so", RTLD_LAZY ); 

    if (filehandle) 

    { 

        char * ( * funcPtrB)(void) = NULL; 

        funcPtrB = dlsym(filehandle, "GetStringB"); 

        if (funcPtrB) 

        { 

            ret = (*env)->NewStringUTF(env, funcPtrB()); 

        } 

        else 

        { 

            ret = (*env)->NewStringUTF(env, "dlsym GetStringB failed!"); 

        } 

        dlclose(filehandle); 

    } 

    else 

    { 

        ret = (*env)->NewStringUTF(env, "dlopen failed!"); 

    } 



    return ret; 

} 


b.c

#include <stdio.h> 

#include <stdlib.h> 

#include <stdarg.h> 

#include <dlfcn.h> 

#include <jni.h> 



char * GetStringB(void) 

{ 

    return "i am in b.so"; 

} 

 

jstring Java_com_ckl_SoCallSo_SoCallSoActivity_fucntionInB(JNIEnv* env, jobject thiz) 

{ 

    return (*env)->NewStringUTF(env, GetStringB()); 

} 



jstring Java_com_ckl_SoCallSo_SoCallSoActivity_BcallA(JNIEnv* env, jobject thiz) 

{ 

    jstring ret; 

    //so路径:/data/data/我的程序的包名/lib/我的so文件名 

    void *  filehandle = dlopen("/data/data/com.ckl.SoCallSo/lib/liba.so", RTLD_LAZY ); 

    if (filehandle) 

    { 

        char * ( * funcPtrA)(void) = NULL; 

        funcPtrA = dlsym(filehandle, "GetStringA"); 

        if (funcPtrA) 

        { 

            ret = (*env)->NewStringUTF(env, funcPtrA()); 

        } 

        else 

        { 

            ret = (*env)->NewStringUTF(env, "dlsym GetStringA failed!"); 

        } 

        dlclose(filehandle); 

    } 

    else 

    { 

        ret = (*env)->NewStringUTF(env, "dlopen failed!"); 

    } 

    return ret; 

} 


Android.mk

LOCAL_PATH := $(call my-dir) 

include $(CLEAR_VARS) 

LOCAL_MODULE := a 

LOCAL_SRC_FILES := a.c 

include $(BUILD_SHARED_LIBRARY) 



include $(CLEAR_VARS) 

LOCAL_MODULE := b 

LOCAL_SRC_FILES := b.c 

include $(BUILD_SHARED_LIBRARY) 




a.c、b.c分别生成liba.so、libb.so,liba.so要调用libb.so中的GetStringB()函数,libb.so要调用liba.so中的GetStringA()函数。

 

另外,so文件的路径为 /data/data/我的程序的包名/lib/我的so文件名。


\

 



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值