gpt4 book ai didi

clojure - 如何在 lein 项目中加载和使用原生 c 代码?

转载 作者:行者123 更新时间:2023-12-04 15:34:00 25 4
gpt4 key购买 nike

问题我无法将已编译的 c 类中的方法加载和调用到 leiningen 项目中。我的基本方法是加载一个Java类JavaWrapper.java,它使用JNI调用本地代码wrapper.o中的一些本地方法,然后通过这个java包装类调用这些方法。
我想在加载从 clojure 项目加载 native 代码的 java 类时存在 classLoader 问题,但鉴于我似乎无法直接获取 clojure 代码以在库路径上找到 wrapper.o,我不确定如何处理这个。

lein 项目文件

(defproject lein-native-test "0.1.0-SNAPSHOT"
...
:java-source-paths ["java-path"]
:jvm-opts ["-Djava.library.path=.:./native:/absolute/path/to/native"] ;;not sure what format it wants
)

带有 main 方法的 clojure 文件
我已经尝试使用四种方法对其进行了轻微修改,所有方法都包含在下面的代码中以及注释中的相应错误。
(ns lein-native-test.core
(:import (com.test JavaWrapper)))
(def -main []
;;four things I've tried and their errors
(clojure.lang.RT.load "/abs/path/to/wrapper.o") ;;could not find file /abs/path/wrapper.o_init.class or wrapper.o.clj
(clojure.lang.RT.loadLibrary "wrapper.o") ;;UnsatisfiedLinkError no wrapper.o in java library path
(JavaWrapper/load "/abs/path/to/wrapper.o") ;;UnsatisfiedLinkError com.test.JavaWrapper.setup()
(assembly-load "/abs/path/to/wrapper.o") ;;unable to resolvesymbol: assembly-load
)

带有使用 JNI、JavaWrapper.java 的 native 方法的 Java 代码
public class JavaWrapper{
public native void setup();
public static void load(String lib){ System.load(lib);}
}

在尝试使用 clojure 和 lein 之前,我确实通过 JavaWrapper 和 JNI 成功加载并使用了 wrapper.o 中的 native 方法。

可能相关:我也无法通过 JavaWrapper.java 加载 wrapper.o
System.loadLibrary("wrapper.o");

我必须使用
System.load("/absolute/path/to/wrapper.o");

工具版本
Clojure 版本:1.5.1
莱因版本:2.3.4
jdk:1.7
操作系统:debian7


更好地理解 ClassLoaders 或者特别是一个简单的示例将非常有用,谢谢。

最佳答案

问题是由于我的方法在 C 头文件和源文件中的命名错误引起的 jni standard .将 jni 与 clojure 一起使用的正确方法是像我所做的那样创建一个 Java 包装器类并使用该方法加载动态库clojure.lang.RT.loadLibrary由于我很难为此找到好的示例,因此我在 github 上做了一个演示。
错误
1) (clojure.lang.RT.load "/abs/path/to/wrapper.o") ;;找不到文件/abs/path/wrapper.o_init.class 或 wrapper.o.clj
此加载方法不适用于 native 代码,它需要一个 java 类或 clj 文件

2) (clojure.lang.RT.loadLibrary "wrapper.o") ;;UnsatisfiedLinkError java库路径中没有wrapper.o
Clojure 在链接时无法找到库,因此 UnsatisfiedLinkError --- 这是由于命名错误


  • 首先,库应该被编译为动态共享库,即对于 gcc 编译器使用 -shared 标志(我实际上做了但没有使用正常的 .so 扩展名命名输出文件)

  • java 和 clojure 期望以非常具体的方式命名 native 库:libwrapper.so(或 .jnilib 为 mac 或 .dll 为 Windows,但总是带有“lib”前缀)
  • 3) (JavaWrapper/load "/abs/path/to/wrapper.o") ;;UnsatisfiedLinkError com.test.JavaWrapper.setup()
    这次错误是在文件或库中的 JavaWrapper 中的一个方法上,因此您知道至少它找到了该文件。在 Java 类中指定特定方法的 UnsatisfiedLinkError,像这个,应该总是由于在 Java 文件中声明为本地方法的内容与 c 源或头文件中实际存在的内容之间的命名错误。
    注意命名空间“com.test”
    在 c 中声明 jni 方法时,方法名称必须遵循特定格式,
    来自 http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/design.html
    “动态链接器根据名称解析条目。 native 方法名称由以下组件连接而成:”

  • 前缀 Java_
  • 一个完整的类名
  • 下划线 (_) 分隔符
  • 错误的方法名称
  • 对于重载的本地方法,两个下划线 (__) 后跟错误的参数签名

  • 在这种情况下,完整的 c 源方法签名将是
    void Java_com_test_setup(JNIEnv *env, jobject obj)

    4) (assembly-load "/abs/path/to/wrapper.o") ;;无法解析符号:程序集加载
    此方法也不是为了加载 native 代码

    关于clojure - 如何在 lein 项目中加载和使用原生 c 代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24365347/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com