在Java Eclipse(Linux)上使用JNI,我正在加载一个名为first.so的动态共享库。到目前为止一切顺利。
问题是first.so还加载了一个名为second.so的动态库,运行程序时我会得到许多有关second.so中符号未定义的错误信息。
似乎在Java环境下使用JNI加载的库无法在运行时加载其他C库。我的假设是否正确?
我需要特殊的编译标志来编译first.so库吗?还是需要特殊参数告诉eclipse在运行时将尝试加载一个.so?
提前感谢!
似乎使用JNI加载的库无法在运行时加载其他C库,因为我们处于Java环境中。我的假设是正确的吗?
不是。
libsecond.so
是由 libfirst.so
使用的吗?它是一个链接依赖项还是通过 dlopen
加载的?
我发现类似以下内容:
static {
System.loadLibrary("second");
System.loadLibrary("first");
}
通常使用JNI的类可以正常工作。
编辑:现在我知道你是如何加载libsecond.so
的,这个对我有效:
Test.java
public class Test {
public static void main (String args[]) {
test();
}
private native static void test();
static {
System.loadLibrary("first");
}
}
first.c -- libfirst.so
的唯一翻译单元
#include <jni.h>
#include "Test.h"
#include <dlfcn.h>
#define LIBNAME "libsecond.so"
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: Test
* Method: test
* Signature: ()V
*/
JNIEXPORT void JNICALL
Java_Test_test(JNIEnv *env , jclass cls)
{
void* h;
void (*sym)(void);
h = dlopen(LIBNAME, RTLD_LAZY|RTLD_GLOBAL);
if (h) {
printf("dlopen " LIBNAME " worked\n");
sym = (void (*)(void))dlsym(h,"second");
sym();
} else {
printf("dlopen " LIBNAME " failed\n");
}
}
#ifdef __cplusplus
}
#endif
second.c是libsecond.so
唯一的翻译单元。
#include <stdio.h>
void
second(void)
{
printf("hello from second\n");
}
Makefile
CFLAGS=-fPIC
all : libfirst.so libsecond.so
libsecond.so : second.o
$(CC) -shared -Wl,-soname,libsecond.so.0 -o $@ $^ -lc
libfirst.so : first.o
$(CC) -shared -Wl,-soname,libfirst.so.0 -o $@ $^ -ldl -lc
clean:
rm -f *.o *.so
Test.h
可以通过javah Test
生成。请注意,libfirst.so
和libsecond.so
没有链接在一起。
System.loadLibrary("second"); System.loadLibrary("first");
)。 - pevik对于从Java加载的库中的dopen()
,所有通常规则都适用。特别是,您需要检查LD_LIBRARY_PATH、rpath、runpath等内容。另请参见dlopen failed:cannot open shared object file: No such file or directory。
second.so
是另一个JNI库还是仅由first.so
使用的普通C库?如果它是一个JNI库,我认为您可能需要使用System.loadLibrary()
从Java中加载它,而不是使用dlopen()
从C中加载,尽管我不确定。 - Adam Rosenfieldfirst.so
时,将libsecond.so
链接到其中。 - Basile Starynkevitch