从另一个库调用一个库函数

Posted

技术标签:

【中文标题】从另一个库调用一个库函数【英文标题】:Calling one library function from another library 【发布时间】:2015-09-19 08:39:58 【问题描述】:

我有一个库说 libraryOne.so (File1.c),它包含纯 C 代码。 现在我想从我的 Java 文件中访问这段代码。为此,我将使用标准的 JNI 程序。 但是为了使用 JNI,我还应该修改 File1.c 中的 C 代码(比如包括 JNI 的头文件和一些标准的 JNIEXPORT 东西)。 所以我正在创建一个包装库(libraryWrapper.so 由 File2.c 制成)。 此库将包含所需的 JNI 声明,并将与我的 Java 文件交互。 现在我想知道如何从 File2.c 调用 File1.c 的纯 C 函数

【问题讨论】:

如果你有 File1.c 源代码然后为 android 编译两者 你能告诉我这样做的详细方法吗? 你知道如何用ndk构建吗? 我害怕但我不害怕:( 你应该先看看android ndk教程。 【参考方案1】:

首先,您应该阅读 ndk-tutorial。因为你需要设置ndk等等。之后你可以寻找 ndk 示例来学习如何做事。以及如何构建

其实上面就是你的答案。 来回答你的问题。

你应该有 libraryOne.so 的源代码。正如你所说的那样。导致android的目标平台很多,你的so不能运行,所以需要用ndk编译

好的,让我们成为我们的文件 File1.c

int myfunction(const char* st)
int answer=0;
  //stufs here
return answer;

首先,添加我们要访问的Java类

package example.com.myapplication;

public class JniClass 
    static 
        System.loadLibrary("libraryWrapper");
    

    public   native int myFunction(String a );

现在我们需要包装器。为此,我们应该知道 jni 接口。幸运的是,有一个名为 javah 的工具可以为我们生成它,并使我们不必为所有调用手动执行它。 我们应该构建我们的 android 项目,以便生成类文件。 我使用调试构建它,因此我生成的文件将位于此 /app/build/intermediates/classes/debug 文件夹中。

好的,然后我们运行 javah javah -jni example.com.myapplication.JniClass

如果您有错误,请参阅Javah error while using it in JNI

它生成了名为example_com_myapplication_JniClass.h的头文件,其中包含

#include <jni.h>
/* Header for class example_com_myapplication_JniClass */

#ifndef _Included_example_com_myapplication_JniClass
#define _Included_example_com_myapplication_JniClass
#ifdef __cplusplus
extern "C" 
#endif
/*
 * Class:     example_com_myapplication_JniClass
 * Method:    myFunction
 * Signature: (Ljava/lang/String;)I
 */
JNIEXPORT jint JNICALL Java_example_com_myapplication_JniClass_myFunction
  (JNIEnv *, jobject, jstring);

#ifdef __cplusplus

#endif
#endif

好的,现在你的答案。 简单的方法是复制生成的代码并将其粘贴到 File1.c 代码的底部。并实施它: 请注意,我在粘贴并清理 cmets 后将参数命名为 env、obj 和 str

//..here your File1.c source code content
//
#include <jni.h> 
#ifdef __cplusplus
extern "C" 
#endif 
JNIEXPORT jint JNICALL Java_example_com_myapplication_JniClass_myFunction
  (JNIEnv * env, jobject obj, jstring str)

       const char * x=(*env)->GetStringUTFChars(env,str,0);
      //call our function
       int ret=  myfunction(x);
       (*env)->ReleaseStringUTFChars(env,str, x);

       return ret;

     
#ifdef __cplusplus

#endif

但实际上你可能会在你的 c 代码中使用头文件。 例如,您可以添加生成的头文件并在 .c 文件上实现它。在 .c 文件上,您可以包含您的 File1.c 标头。而且这种方式更干净。

假设您已经阅读了 ndk 教程。并且您设置了 ndk 工具并知道如何构建

最后我们将 File1.c 添加到 jni 文件夹并更改 Android.mk 文件

LOCAL_MODULE := libraryWrapper LOCAL_SRC_FILES := File1.c 和

APP_MODULES := libraryWrapper

然后我们使用 ndk-build 构建它,它将我们的 so 文件添加到 libs

Op 只需要 File1.c 和 File2.c 在 File2.c 中

//declaration of funtions inside File1.c
extern int myfunction(const char* st);
#include <jni.h> 
    #ifdef __cplusplus
    extern "C" 
    #endif 
    JNIEXPORT jint JNICALL Java_example_com_myapplication_JniClass_myFunction
      (JNIEnv * env, jobject obj, jstring str)

           const char * x=(*env)->GetStringUTFChars(env,str,0);
          //call our function
           int ret=  myfunction(x);
           (*env)->ReleaseStringUTFChars(env,str, x);

           return ret;

         
    #ifdef __cplusplus
    
    #endif

并更改 Android.mk

LOCAL_SRC_FILES := File1.c 
LOCAL_SRC_FILES += File2.c 

【讨论】:

你说的最后一部分“简单的方法是复制生成的代码并将其粘贴到 File1.c 代码的底部。并实现它:”。我认为这应该写入 File2.c??我的实际要求是不对 File1.c 做任何更改 是的,因为您必须以其他方式添加前向声明。但最好使用头文件 代替 File1.c 添加 #include "File1.h" 这将是您的 File1.c 头文件 我想我们将生成的头文件添加到File2.c中。为什么你说要把它添加到 File1.c 中?我不想对 File1.c 进行任何更改。 在 File1.c 中添加要调用的函数的声明。 compile 将查找它们并找到定义

以上是关于从另一个库调用一个库函数的主要内容,如果未能解决你的问题,请参考以下文章

调用@plt函数时在dlopen / static init上共享库SIGSEGV

来自另一个云函数的可调用函数

Grails:从另一个标签库中调用一个标签库

如何从另一个汇编文件中调用汇编函数?

调用一个动态库中的函数,这个函数有一个参数是结构体指针,我如何使用这个指针?

keilc中怎么使一个库函数不调用时不编译