【问题标题】:How to load and use native c code in a lein project?如何在 lein 项目中加载和使用本机 c 代码?
【发布时间】:2014-06-23 11:58:32
【问题描述】:

问题
我无法将已编译的 c 类中的方法加载和调用到 leiningen 项目中。我的基本方法是加载一个Java类JavaWrapper.java,它使用JNI调用本机代码wrapper.o中的一些本机方法,然后通过这个java包装类调用这些方法。
我想加载一个从 clojure 项目加载本机代码的 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 文件
我已经尝试用四种方法对其进行了轻微修改,所有方法都包含在下面的代码中,以及 cmets 中的相应错误。

(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 的本机方法的 Java 代码

public class JavaWrapper{
    public native void setup();
    public static void load(String lib){ System.load(lib);}
}

在尝试让它与 clojure 和 lein 一起工作之前,我确实通过 JavaWrapper 和 JNI 成功加载并使用了 wrapper.o 中的本机方法。

可能相关:
我也无法通过

在 JavaWrapper.java 中加载 wrapper.o
System.loadLibrary("wrapper.o");

我必须使用

System.load("/absolute/path/to/wrapper.o");

工具版本
clojure 版本:1.5.1
lein 版本:2.3.4
JDK:1.7
操作系统:debian7

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

【问题讨论】:

    标签: clojure native leiningen


    【解决方案1】:

    问题是由于我在 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
    此加载方法不适用于本机代码,它需要一个 java 类或 clj 文件

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

    • 首先,该库应编译为动态共享库,即 gcc 编译器使用 -shared 标志(我确实这样做了,但没有使用正常的 .so 扩展名命名输出文件)
    • java 和因此 clojure 期望本地库以非常具体的方式命名: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
    “动态链接器根据其名称解析条目。本机方法名称由以下组件连接:”
    • 前缀 Java_
    • 错位的完全限定类名
    • 下划线 (_) 分隔符
    • 错误的方法名称
    • 对于重载的本机方法,两个下划线 (__) 后跟错误的参数签名

    在这种情况下,完整的 c 源方法签名将是

    void Java_com_test_setup(JNIEnv *env, jobject obj)
    


    4) (assembly-load "/abs/path/to/wrapper.o") ;;无法解析符号:assembly-load
    此方法也不意味着加载本机代码

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-25
      • 1970-01-01
      相关资源
      最近更新 更多