JNI 绑定 - 未定义符号:gcj_personality_v0

发布于 2024-10-19 09:47:29 字数 4536 浏览 1 评论 0原文

我正在尝试将有效的 C JNI 绑定转换为 C++,因为我想从一些 Java 代码链接到 C++ 源代码(图像处理算法的开源实现)。我让一切都在 C 中运行,这包括 Java 类、JNI 绑定的 C 版本和构建系统,并且排除使用 C++ 源代码。

我现在尝试将 JNI 绑定转换为 C++,以便可以将 C++ 源添加到构建系统并从绑定中调用它,但我遇到了未定义的符号。

我的 Makefile 非常简单:

GCC = gcc -Wall -g -std=gnu99
CXX = g++ -Wall -g
LIBOBJS = parallelsurf_jni.o

LIB=libparallelsurf.so
DESTLIB=../../lib/$(LIB)

all: $(DESTLIB)


$(DESTLIB): $(LIB)
    cp $(LIB) $(DESTLIB)

libparallelsurf.so: parallelsurf_ParallelSURF.h $(LIBOBJS)
    ld --shared $(LIBOBJS) -o libparallelsurf.so 

parallelsurf_ParallelSURF.h:
    echo "Rebuilding JNI headers. Ensure java file has been recently built."
    javah -classpath ../../parallelsurf.jar -jni parallelsurf.ParallelSURF

clean:
    rm -f $(LIBOBJS) *~ parallelsurf_ParallelSURF.h $(LIB) $(DESTLIB) $(LIBOBJS)

JNI_INCLUDES = -I/usr/lib/jvm/java-6-sun/include/ -I/usr/lib/jvm/java-6-sun/include/linux -I/usr/lib/jvm/java-6-openjdk/include/

%.o: %.cpp
    $(CXX) -shared -O2 -c -fPIC -fno-omit-frame-pointer -fno-stack-protector -D_REENTRANT $< $(JNI_INCLUDES)

我的头文件是使用 javah 自动生成的,并且在从 .h 复制到 .cpp 时,我似乎没有损坏它。我的 .cpp 文件中没有 extern "C" 块,按照 这篇文章

我还按照这篇文章的指导添加了一个编译指示:链接上未定义的符号 _gxx_personality_v0。 pragma 是 #pragma GCC java_exceptions

现在,该未定义符号 (gxx_personality) 似乎在网络上得到了很好的引用/记录。许多帖子都指向 C++/Java 异常处理 的评论,这建议使用该编译指示。然而,在包含该编译指示之后,我得到了另一个未定义的符号,该符号没有被很好地覆盖(我得到了 1 个 Google 命中): _gcj_personality_v0

Exception in thread "main" java.lang.UnsatisfiedLinkError: /home/chardson/chardson/parallelsurf/lib/libparallelsurf.so: /home/chardson/chardson/parallelsurf/lib/libparallelsurf.so: undefined symbol: __gcj_personality_v0
    at java.lang.ClassLoader$NativeLibrary.load(Native Method)
    at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1750)
    at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1675)
    at java.lang.Runtime.loadLibrary0(Runtime.java:840)
    at java.lang.System.loadLibrary(System.java:1047)
    at parallelsurf.ParallelSURF.<clinit>(ParallelSURF.java:17)
    at testpsurf.<init>(testpsurf.java:11)
    at testpsurf.main(testpsurf.java:23)

我不知道如何处理这个未定义的符号,并且我有不知道还能去哪里。也许我的 JNI 代码中有一个错误可以通过修复来解决这个问题?为了完整起见,我的 JNI C++ 代码包含在下面。

#include <jni.h>
#include <stdio.h>
#include <assert.h>

#pragma GCC java_exceptions

/*
 * Class:     parallelsurf_ParallelSURF
 * Method:    parallelsurf_get_keypoints
 * Signature: (II[FZ)Ljava/util/ArrayList;
 */
JNIEXPORT jobject JNICALL Java_parallelsurf_ParallelSURF_parallelsurf_1get_1keypoints
  (JNIEnv *jenv, jclass jcls, jint width, jint height, jfloatArray gray, jboolean rotInvariant)
{
    // init arraylist class
    jclass arrayListClass = jenv->FindClass("java/util/ArrayList");
    assert(arrayListClass != NULL);

    jmethodID alInitMethodId = jenv->GetMethodID(arrayListClass, "<init>", "()V");
    assert(alInitMethodId != NULL);

    jobject arrayList = jenv->NewObject(arrayListClass, alInitMethodId);

    jmethodID alAddMethodId = jenv->GetMethodID(arrayListClass, "add", "(Ljava/lang/Object;)Z");
    assert(alAddMethodId != NULL);

    // init keypoint class
    jclass keypointClass = jenv->FindClass("parallelsurf/Keypoint");
    assert(keypointClass != NULL);

    jmethodID kpInitMethodId = jenv->GetMethodID(keypointClass, "<init>", "(DDDDID[D)V");
    assert(kpInitMethodId != NULL);

    jdoubleArray descriptor = jenv->NewDoubleArray(10);
    assert(descriptor != NULL);

    jdouble vals[10];
    for (int i=0; i < 10; i++) {
        vals[i] = (jdouble) i;
    }

    jenv->SetDoubleArrayRegion(descriptor, 0, 10, vals);

    // create keypoint
    jobject kp = jenv->NewObject(keypointClass, kpInitMethodId,
                                    (jdouble) 1, (jdouble) 2, (jdouble) 3,
                                    (jdouble) 4, (jint) 5, (jdouble) 6,
                                    descriptor);

    // add to arraylist
    jenv->CallBooleanMethod(arrayList, alAddMethodId, kp);
    jenv->DeleteLocalRef(kp);

    return arrayList;
}

感谢您的关注。非常感谢您的帮助。

I'm trying to convert a valid C JNI binding to C++ because I want to link to C++ source (open source implementation of an image processing algorithm) from some Java code. I got everything working in C, this includes the Java class, the C version of the JNI binding and the build system and excludes using the C++ source.

I am now trying to convert the JNI binding to C++ so I can add the C++ source to the build system and call it from the binding, but I'm running into an undefined symbol.

My Makefile is pretty straightforward:

GCC = gcc -Wall -g -std=gnu99
CXX = g++ -Wall -g
LIBOBJS = parallelsurf_jni.o

LIB=libparallelsurf.so
DESTLIB=../../lib/$(LIB)

all: $(DESTLIB)


$(DESTLIB): $(LIB)
    cp $(LIB) $(DESTLIB)

libparallelsurf.so: parallelsurf_ParallelSURF.h $(LIBOBJS)
    ld --shared $(LIBOBJS) -o libparallelsurf.so 

parallelsurf_ParallelSURF.h:
    echo "Rebuilding JNI headers. Ensure java file has been recently built."
    javah -classpath ../../parallelsurf.jar -jni parallelsurf.ParallelSURF

clean:
    rm -f $(LIBOBJS) *~ parallelsurf_ParallelSURF.h $(LIB) $(DESTLIB) $(LIBOBJS)

JNI_INCLUDES = -I/usr/lib/jvm/java-6-sun/include/ -I/usr/lib/jvm/java-6-sun/include/linux -I/usr/lib/jvm/java-6-openjdk/include/

%.o: %.cpp
    $(CXX) -shared -O2 -c -fPIC -fno-omit-frame-pointer -fno-stack-protector -D_REENTRANT 
lt; $(JNI_INCLUDES)

My header file is thus automatically generated with javah and I don't appear to have mangled it when copying from .h to .cpp. I do not have extern "C" blocks in the .cpp file, as guided by this post.

I also included a pragma as guided by this post: Undefined Symbol _gxx_personality_v0 on link. The pragma is #pragma GCC java_exceptions

Now, that undefined symbol (gxx_personality) seems to be well referenced/documented on the web. A number of posts point to this comment on C++/Java exception handling, which suggests using that pragma. However, after including that pragma, I get another undefined symbol that is not well covered (I get exactly 1 Google hit): _gcj_personality_v0

Exception in thread "main" java.lang.UnsatisfiedLinkError: /home/chardson/chardson/parallelsurf/lib/libparallelsurf.so: /home/chardson/chardson/parallelsurf/lib/libparallelsurf.so: undefined symbol: __gcj_personality_v0
    at java.lang.ClassLoader$NativeLibrary.load(Native Method)
    at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1750)
    at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1675)
    at java.lang.Runtime.loadLibrary0(Runtime.java:840)
    at java.lang.System.loadLibrary(System.java:1047)
    at parallelsurf.ParallelSURF.<clinit>(ParallelSURF.java:17)
    at testpsurf.<init>(testpsurf.java:11)
    at testpsurf.main(testpsurf.java:23)

I'm not sure what to make of this undefined symbol, and I have no idea where else to turn. Perhaps there's just a mistake in my JNI code that could be fixed to get rid of this problem? My JNI C++ code is included below for completeness.

#include <jni.h>
#include <stdio.h>
#include <assert.h>

#pragma GCC java_exceptions

/*
 * Class:     parallelsurf_ParallelSURF
 * Method:    parallelsurf_get_keypoints
 * Signature: (II[FZ)Ljava/util/ArrayList;
 */
JNIEXPORT jobject JNICALL Java_parallelsurf_ParallelSURF_parallelsurf_1get_1keypoints
  (JNIEnv *jenv, jclass jcls, jint width, jint height, jfloatArray gray, jboolean rotInvariant)
{
    // init arraylist class
    jclass arrayListClass = jenv->FindClass("java/util/ArrayList");
    assert(arrayListClass != NULL);

    jmethodID alInitMethodId = jenv->GetMethodID(arrayListClass, "<init>", "()V");
    assert(alInitMethodId != NULL);

    jobject arrayList = jenv->NewObject(arrayListClass, alInitMethodId);

    jmethodID alAddMethodId = jenv->GetMethodID(arrayListClass, "add", "(Ljava/lang/Object;)Z");
    assert(alAddMethodId != NULL);

    // init keypoint class
    jclass keypointClass = jenv->FindClass("parallelsurf/Keypoint");
    assert(keypointClass != NULL);

    jmethodID kpInitMethodId = jenv->GetMethodID(keypointClass, "<init>", "(DDDDID[D)V");
    assert(kpInitMethodId != NULL);

    jdoubleArray descriptor = jenv->NewDoubleArray(10);
    assert(descriptor != NULL);

    jdouble vals[10];
    for (int i=0; i < 10; i++) {
        vals[i] = (jdouble) i;
    }

    jenv->SetDoubleArrayRegion(descriptor, 0, 10, vals);

    // create keypoint
    jobject kp = jenv->NewObject(keypointClass, kpInitMethodId,
                                    (jdouble) 1, (jdouble) 2, (jdouble) 3,
                                    (jdouble) 4, (jint) 5, (jdouble) 6,
                                    descriptor);

    // add to arraylist
    jenv->CallBooleanMethod(arrayList, alAddMethodId, kp);
    jenv->DeleteLocalRef(kp);

    return arrayList;
}

Thanks for looking. Your help is much appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

油饼 2024-10-26 09:47:30

gcc-help 邮件列表上的一些优秀绅士解决了这个问题:

  • 不要用 #pragma GCC java_exceptions 来处理 __gxx_personality_v0,而是在 -l gcc_s 中创建 ld 链接
  • 如果 __gcj_personality_v0 未定义,则将 ld 链接到 -l gcj
  • ,将 ld 链接到 -l stdc++
  • 确保你的机器上有 libstdc++、libgcjX-dev(X 是一个版本)和 libgcc

如果你用 g++ 链接(我没有),其中一些可能会自动发生(stdc++?)

另外,请确保你没有不要忘记(或丢失)JNI 标头的 #import 行 - 您将需要 extern C {} 位,否则您将收到 UnsatisfiedLinkError

Some fine gentleman on the gcc-help mailing list figured this one out:

  • Instead of #pragma GCC java_exceptions to deal with __gxx_personality_v0, make ld link in -l gcc_s
  • If __gcj_personality_v0 is undefined, make ld link in -l gcj
  • Have ld link -l stdc++
  • Ensure that you have libstdc++, libgcjX-dev (X is a version) and libgcc on your machine

If you're linking with g++ (I'm not), some of these may happen automatically (stdc++?)

Also, make sure you didn't forget (or lose) the #import line for the JNI header -- you'll need the extern C {} bits, or you'll get an UnsatisfiedLinkError

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文