Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/311.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/71.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 加载带有JNI:未定义符号的C插件系统_Java_C_Dll - Fatal编程技术网

Java 加载带有JNI:未定义符号的C插件系统

Java 加载带有JNI:未定义符号的C插件系统,java,c,dll,Java,C,Dll,我想在Linux的Java程序中运行我的C插件系统,我已经在Java程序中编写了绑定和库加载 插件系统提供了一个加载插件的命令,该命令被包装成Java,这样我就可以在我的Java shell中调用I,它就可以工作了 当插件试图从插件系统运行命令时,出现了一个未定义的符号错误。然而,我已经仔细地将插件使用的所有函数链接到库中,系统是使用-fPIC和-shared编译的。我还使用objdump-T查看了符号表,并列出了函数 我觉得这个过程有点疯狂,我加载了C代码,用Java加载了C代码。。。可能吗

我想在Linux的Java程序中运行我的C插件系统,我已经在Java程序中编写了绑定和库加载

插件系统提供了一个加载插件的命令,该命令被包装成Java,这样我就可以在我的Java shell中调用I,它就可以工作了

当插件试图从插件系统运行命令时,出现了一个未定义的符号错误。然而,我已经仔细地将插件使用的所有函数链接到库中,系统是使用
-fPIC
-shared
编译的。我还使用
objdump-T
查看了符号表,并列出了函数

我觉得这个过程有点疯狂,我加载了C代码,用Java加载了C代码。。。可能吗

如果有人曾经遇到过这个问题,或者想分享关于可能的解决方案的想法,我将非常感谢

多谢各位

编辑:在这个例子中,我尽可能地模仿我的程序。我也得到了一个错误,但它是完全不同的

// plugin_system.c
#include <dlfcn.h>
#include <stdio.h>

int load_and_run_plugin() {
  void *lib = dlopen("/home/kowa/code/c/test_dir/jni/plug/plugin.so", RTLD_LAZY);
  if (lib == NULL) {
    fprintf(stderr, "Cannot open library.\n");
    return -1;
  }
  void (*plug_func)(void) = dlsym(lib, "plug_function");
  if (plug_func == NULL) {
    dlclose(lib);
    fprintf(stderr, "Cannot find plugin function.\n");
    return -1;
  }
  plug_func();
  return 0;
}

// PluginSystem.c
#include "PluginSystem.h"
#include "plugin_system.h"

/*
 * Class:     PluginSystem
 * Method:    cmdPlug
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_PluginSystem_cmdPlug
  (JNIEnv *env, jclass this)
{
  printf("Calling load_and_run function...\n");
  load_and_run_plugin();
  printf("End of call to load_and_run function\n");
}

// plugin_user_api.c
#include <stdio.h>

static void verbose_stdout(char *str)
{
  printf("%s", str);
}

void (*verbose) (char *str) = verbose_stdout;

// plugin.c
#include "plugin_user_api.h"

int plug_function() {
  verbose("I'm a plugin and I use external functions.\n");
  return 0;
}

// PluginSystem.java
public class PluginSystem
{
  static { 
    System.load("/home/kowa/code/c/test_dir/jni/plug/plugin_system.so");
  }
  public static native void cmdPlug();

  public static void main(String args[]) {
    PluginSystem.cmdPlug();
  }
}

// Makefile
JAVA_HOME      = /usr/lib/jvm/java-8-openjdk
C_INCLUDE_PATH = $(JAVA_HOME)/include $(JAVA_HOME)/include/linux
INCLUDE        = $(foreach i, $(C_INCLUDE_PATH), -I$i)
CFLAGS         = -Wall -O2 -std=gnu99

all:
    gcc $(CFLAGS) -fPIC -c plugin.c
    gcc $(CFLAGS) -Wl,-soname,plugin.so -shared -o plugin.so plugin.o
    gcc $(CFLAGS) $(INCLUDE) -fPIC -c plugin_system.c
    gcc $(CFLAGS) $(INCLUDE) -fPIC -c plugin_user_api.c
    gcc $(CFLAGS) $(INCLUDE) -fPIC -c PluginSystem.c
    gcc $(CFLAGS) -Wl,-soname,plugin_system.so -shared -o plugin_system.so plugin_system.o plugin_user_api.o PluginSystem.o
    sed -i "s:System.load(.*):System.load(\"$(shell echo `pwd`)/plugin_system.so\"):" PluginSystem.java
    javac PluginSystem.java


clean:
    rm *.o *.so *.class

日志文件很长(654行!),所以不要怪我没有发布它

您的示例代码适用于我,但有以下注意事项:

  • 我运行了
    javah
    来生成自己版本的
    PluginSystem.h
    ,并编写了自己的
    plugin\u system.h
    ,因为这些都没有发布

  • 我将硬编码的共享库路径更改为适合本地系统的路径

  • 为了方便起见,我将
    plugin\u-user\u-api.c
    合并到
    plugin.c
    中,并删除了
    plugin\u-user\u-api.h
    (反正没有提供)

  • 我用更惯用的风格重写了你的
    Makefile

如果我构建本机库、插件和Java类,然后运行它会产生以下结果:

$ /usr/lib/jvm/java-1.8.0/bin/java PluginSystem
Calling load_and_run function...
I'm a plugin and I use external functions.
End of call to load_and_run function

更新: 如果不是将
plugin\u user\u api.c
合并到
plugin.c
中,而是将其合并到
plugin\u system.c
,我就能够复制您的问题。在这种情况下,我可以实现一个C驱动程序能够加载插件的结果,但Java无法这样做。这表明Java正在加载带有
RTLD_LOCAL
标志的库,这样它的符号就不会暴露给随后加载的库,比如插件

至少有三种可能的解决方案:

  • 在Java和
    plugin\u系统之间插入另一个加载程序。因此
    使您能够控制
    plugin\u系统的范围。因此
    的符号
  • 将插件所需的所有支持功能移出plugin_system.so,并放入一个单独的动态库中,所有插件都可以链接到该库
  • 通过让插件系统使用指向所需函数和数据的指针来初始化插件,从而使插件不再需要与插件系统动态链接
其中,第一个需要对现有代码进行最少的修改,但最后一个是最安全的,并且与Java有意避免暴露库的动态符号的努力最一致。事实上,你可能会考虑让你的插件系统做同样的事情,以减少插件相互干扰的风险。 这里是您的原始代码的一个变体,它演示了第三种方法。它增加了一个每个插件的初始化函数,该函数必须在插件加载后调用;这避免了对任何现有插件函数的签名进行任何更改。这种变体还避免了向Java(或C)碰巧加载的其他库公开插件的符号。Java端不需要任何更改:

plugin\u system.h

plugin\u system.c

#包括
#包括
#包括“plugin_system.h”
typedef int(*init_函数)(结构插件_上下文*);
静态无效详细数据(char*str)
{
printf(“%s”,str);
}
静态结构插件上下文={.verbose=verbose\u stdout};
int load_和_run_插件(){
void*lib=dlopen(“/home/kowa/code/c/test\u dir/jni/plug/plugin.so”,
RTLD_LAZY | RTLD_LOCAL);
if(lib==NULL){
fprintf(stderr,“无法打开库。\n”);
返回-1;
}
init_函数plug_init=dlsym(lib,“plug_init”);
if(plug_init==NULL){
dlclose(lib);
fprintf(stderr,“找不到插件初始化函数。\n”);
返回-1;
}
plug_init(&context);//省略错误检查
void(*plug_func)(void)=dlsym(lib,“plug_函数”);
if(plug_func==NULL){
dlclose(lib);
fprintf(stderr,“找不到插件函数。\n”);
返回-1;
}
plug_func();//忽略错误检查
返回0;
}
plugin.c

包括
#包括“plugin_system.h”
静态无效(*详细)(字符*str);
int plug_init(结构插件_上下文*上下文){
详细=上下文->详细;
返回0;
}
int plug_函数(){
如果(详细){
详细(“我是一个插件,使用外部函数。\n”);
返回0;
}否则{
返回-1;
}
}

我看不出有任何理由说明像您正在尝试做的事情是不可能的。至于你的案子到底出了什么问题,你还没有给我们提供任何线索。如果你准备了a,你获得帮助(或帮助自己)的机会会大大增加。我试图在帖子中添加的示例中吸取系统的精华,但我得到了不同的错误,因此我可能在该示例中犯了错误。我发布的示例不太准确,它可能适用于较小的项目,我不知道,但在我的项目中,链接器无法解析插件系统库中函数的链接。一种可能的解决方案是将函数指针发送到插件,其缺点是,如果一个函数从同一阶段调用另一个函数,链接器仍然会失败。似乎
System.load
加载库时,符号仅出现在同一命名空间和插件中
$ /usr/lib/jvm/java-1.8.0/bin/java PluginSystem
Calling load_and_run function...
I'm a plugin and I use external functions.
End of call to load_and_run function
#ifndef PLUGIN_SYSTEM_H
#define PLUGIN_SYSTEM_H

struct plugin_context {
    void (*verbose) (char *str);
};

#endif
#include <dlfcn.h>
#include <stdio.h>
#include "plugin_system.h"

typedef int (*init_function)(struct plugin_context *);

static void verbose_stdout(char *str)
{
  printf("%s", str);
}

static struct plugin_context context = { .verbose = verbose_stdout };

int load_and_run_plugin() {
  void *lib = dlopen("/home/kowa/code/c/test_dir/jni/plug/plugin.so",
      RTLD_LAZY | RTLD_LOCAL);
  if (lib == NULL) {
    fprintf(stderr, "Cannot open library.\n");
    return -1;
  }
  init_function plug_init = dlsym(lib, "plug_init");
  if (plug_init == NULL) {
    dlclose(lib);
    fprintf(stderr, "Cannot find plugin initialization function.\n");
    return -1;
  }
  plug_init(&context);  // error checking omitted

  void (*plug_func)(void) = dlsym(lib, "plug_function");
  if (plug_func == NULL) {
    dlclose(lib);
    fprintf(stderr, "Cannot find plugin function.\n");
    return -1;
  }
  plug_func();         // error checking omitted
  return 0;
}
include <stdio.h>
#include "plugin_system.h"

static void (*verbose) (char *str);

int plug_init(struct plugin_context *context) {
  verbose = context->verbose;
  return 0;
}

int plug_function() {
  if (verbose) {
    verbose("I'm a plugin and I use external functions.\n");
    return 0;
  } else {
    return -1;
  }
}