如何在使用 bazel 创建的 C++ 二进制文件中的 JNI 中包含 clojure 的 jar 文件

问题描述 投票:0回答:1

您好,我正在研究这个项目:https://github.com/svazqz/plClojure

但目前我在构建 c++ 二进制文件后遇到一个问题,当我在构建步骤后运行文件创建时,我得到:

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x0000000105d3894c, pid=12933, tid=259
#
# JRE version: OpenJDK Runtime Environment Homebrew (21.0.2) (build 21.0.2)
# Java VM: OpenJDK 64-Bit Server VM Homebrew (21.0.2, mixed mode, sharing, tiered, compressed oops, compressed class ptrs, g1 gc, bsd-aarch64)
# Problematic frame:
# V  [libjvm.dylib+0x42894c]  jni_CallStaticObjectMethodV+0x9c
#
# No core dump will be written. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
#
# An error report file with more information is saved as:
# /Users/$USER/Projects/plClojure/hs_err_pid12933.log
#
# If you would like to submit a bug report, please visit:
#   https://github.com/Homebrew/homebrew-core/issues
#
zsh: abort      ./bazel-bin/src/pl_clojure

概括而言,与以下内容相关:

Internal exceptions (2 events):
Event: 0.124 Thread 0x000000014880a800 Exception <a 'java/lang/NoClassDefFoundError'{0x0000000787f120c0}: clojure/java/api/Clojure> (0x0000000787f120c0) 
thrown [src/hotspot/share/classfile/systemDictionary.cpp, line 301]
Event: 0.124 Thread 0x000000014880a800 Exception <a 'java/lang/NoSuchMethodError'{0x0000000787f123c8}: var> (0x0000000787f123c8) 
thrown [src/hotspot/share/prims/jni.cpp, line 1072]

我尝试了不同的方法在项目中添加 clojure jar 文件作为依赖项,但是下载 deps 时

bazel sync
失败,或者在成功下载依赖项并构建二进制文件后二进制文件仍然抛出先前的异常。

如何使用 bazel 添加所需的 jar 文件,然后在 C++ 代码中使用它们?

我尝试过使用这个规则:

http_archive(
    name = "rules_clojure",
    sha256 = "c841fbf94af331f0f8f02de788ca9981d7c73a10cec798d3be0dd4f79d1d627d",
    strip_prefix = "rules_clojure-c044cb8608a2c3180cbfee89e66bbeb604afb146",
    urls = ["https://github.com/simuons/rules_clojure/archive/c044cb8608a2c3180cbfee89e66bbeb604afb146.tar.gz"],
)

load("@rules_clojure//:repositories.bzl", "rules_clojure_dependencies", "rules_clojure_toolchains")

rules_clojure_dependencies()

rules_clojure_toolchains()

我希望能够在 C++ 代码中使用 clojure,如下所示:

options[0].optionString = "-Djava.class.path=/Library/external/spec_alpha/spec.alpha-0.1.143.jar:/Library/external/clojure/clojure-1.9.0.jar";

为了能够运行 clojure 代码,抛出 C++ 接口。

c++ clojure java-native-interface bazel
1个回答
0
投票

2 件事:

  1. 您的 jar 选项基于相对路径,它无法解析为正确的路径。
  2. 您可以手动将 jar 及其类添加到类路径并将类加载到 JVM 中。您可以在 main.cpp 文件中创建 Java 虚拟机后立即通过添加此函数并调用它来执行此操作:

    void add_path(JNIEnv* env, const std::string& path)
    {
        const std::string urlPath = "file:/"+path;
        jclass classLoaderCls = env->FindClass("java/lang/ClassLoader");
        jmethodID getSystemClassLoaderMethod = env- >GetStaticMethodID(classLoaderCls, "getSystemClassLoader", "()Ljava/lang/ClassLoader;");
        jobject classLoaderInstance = env- >CallStaticObjectMethod(classLoaderCls, getSystemClassLoaderMethod);
        jclass urlClassLoaderCls = env->FindClass("java/net/URLClassLoader");
        jmethodID addUrlMethod = env->GetMethodID(urlClassLoaderCls, "addURL", "(Ljava/net/URL;)V");
        jclass urlCls = env->FindClass("java/net/URL");
        jmethodID urlConstructor = env->GetMethodID(urlCls, "<init>", " (Ljava/lang/String;)V");
        jobject urlInstance = env->NewObject(urlCls, urlConstructor, env- >NewStringUTF(urlPath.c_str()));
        env->CallVoidMethod(classLoaderInstance, addUrlMethod, urlInstance);
        std::cout << "Added " << urlPath << " to the classpath." << std::endl;
    }

您的 main.cpp 文件将如下所示:

#include <jni.h>       /* where everything is defined */
#include <cstring>

void add_path(JNIEnv* env, const std::string& path)
{
    const std::string urlPath = "file:/"+path;
    jclass classLoaderCls = env->FindClass("java/lang/ClassLoader");
    jmethodID getSystemClassLoaderMethod = env->GetStaticMethodID(classLoaderCls, "getSystemClassLoader", "()Ljava/lang/ClassLoader;");
    jobject classLoaderInstance = env- >CallStaticObjectMethod(classLoaderCls, getSystemClassLoaderMethod);
    jclass urlClassLoaderCls = env->FindClass("java/net/URLClassLoader");
    jmethodID addUrlMethod = env->GetMethodID(urlClassLoaderCls, "addURL", "(Ljava/net/URL;)V");
    jclass urlCls = env->FindClass("java/net/URL");
    jmethodID urlConstructor = env->GetMethodID(urlCls, "<init>", " (Ljava/lang/String;)V");
    jobject urlInstance = env->NewObject(urlCls, urlConstructor, env- >NewStringUTF(urlPath.c_str()));
    env->CallVoidMethod(classLoaderInstance, addUrlMethod, urlInstance);
    std::cout << "Added " << urlPath << " to the classpath." << std::endl;
}

int main() {
    JavaVM *jvm;       /* denotes a Java VM */
    JNIEnv *env;       /* pointer to native method interface */
    JavaVMInitArgs vm_args; /* JDK/JRE 6 VM initialization arguments */
    JavaVMOption* options = new JavaVMOption[1];
    options[0].optionString = "-Djava.class.path=/Library/external/spec_alpha/spec.alpha-0.1.143.jar:/Library/external/clojure/clojure-1.9.0.jar";
    vm_args.version = JNI_VERSION_1_6;
    vm_args.nOptions = 1;
    vm_args.options = options;
    vm_args.ignoreUnrecognized = false;
    /* load and initialize a Java VM, return a JNI interface
     * pointer in env */
    JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
    delete options;

    add_path(env, "path to jar")

    jclass Clojure = env->FindClass("clojure/java/api/Clojure");
    jmethodID var = env->GetStaticMethodID(Clojure, "var", "(Ljava/lang/Object;Ljava/lang/Object;)Lclojure/lang/IFn;");
    jobject load_string = env->CallStaticObjectMethod(Clojure, var, env->NewStringUTF("clojure.core"), env->NewStringUTF("load-string"));
    jmethodID load_string_invoke = env->GetMethodID(env->GetObjectClass(load_string), "invoke", "(Ljava/lang/Object;)Ljava/lang/Object;");
    env->CallObjectMethod(load_string, load_string_invoke, env->NewStringUTF("(prn (+ 1 2 3 4 5))"));

    jvm->DestroyJavaVM();
}

© www.soinside.com 2019 - 2024. All rights reserved.