Bazel:具有JNI依赖性的Java应用程序

Bazel:具有JNI依赖性的Java应用程序,java,java-native-interface,bazel,Java,Java Native Interface,Bazel,我已经设法构建了我的JNI库(jar、JNI共享cc_库、包装的cc_库),但我不知道如何构建使用它的Java应用程序。我的构建很简单: java_binary( name = "OCFTestServer", srcs = glob(["src/main/java/**/*.java"]), deps = ["//:OpenOCF-JNI"]) 这里的OpenOCF JNI如下所示: java_library( name = "OpenOCF-JNI",

我已经设法构建了我的JNI库(jar、JNI共享cc_库、包装的cc_库),但我不知道如何构建使用它的Java应用程序。我的构建很简单:

java_binary(
    name = "OCFTestServer",
    srcs = glob(["src/main/java/**/*.java"]),
    deps = ["//:OpenOCF-JNI"])
这里的
OpenOCF JNI
如下所示:

java_library(
    name = "OpenOCF-JNI",
    srcs = glob(["src/main/**/*.java"]),
    deps = ["libopenocf"],
    visibility = ["//visibility:public"])
libopenocf
是:

cc_library(
    name = "libopenocf",
    srcs = glob(["src/c/*.c"]) + glob(["src/c/*.h"])
    + ["@local_jdk//:jni_header",
       "@local_jdk//:jni_md_header-darwin"],
    ... etc ...
这些都是成功构建的。但是,构建不会导致构建依赖项,这是我所期望的(即构建OCFTestServer应该导致构建OpenOCF JNI,这应该导致构建libopenocf JNI)。那不应该发生吗

如果我使用单独的步骤构建它们,然后尝试运行应用程序(使用bazel bin中的OCFTestServer包装器),我会得到
未满足的linkerror:no libopenocf jni in java.library.path
。但是从阅读文档中,我得到的印象是,这些都应该自动设置(即,所需的jni库应该放在java.library.path中)


我做错了什么?有人有构建和使用JNI库的例子吗?

我在试图找出如何链接到JNI库时,偶然发现了你的问题,我刚刚开始工作。它是针对静态库的链接,因此它可能会帮助您,也可能不会帮助您

第三方/构建:

java_import(
    name = "malmo",
    jars = ["MalmoJavaJar.jar"],
    deps = [":libMalmo"],
)

cc_library(
    name = "libMalmo",
    srcs = ["libMalmoJava.so"],
)
然后在我的实际目标中:

    "//third_party:malmo",
我创建了一个简单的回购:帮助你开始

构建

cc_library(
    name = "main-jni-lib",
    srcs = [
        "@local_jdk//:jni_header",
        "@local_jdk//:jni_md_header-linux",
        "Main.cc"
        ],
    hdrs = [ "Main.h" ],
    includes = [ "external/local_jdk/include", "external/local_jdk/include/linux" ],
)

cc_binary(
    name = "libmain-jni.so",
    deps = [ ":main-jni-lib" ],
    linkshared = 1,
)

java_binary(
    name = "Main",
    srcs = [ "Main.java" ],
    main_class = "Main",
    data = [ ":libmain-jni.so" ],
    jvm_flags = [ "-Djava.library.path=." ],
)
Main.java

public class Main {
  static {
    System.loadLibrary("main-jni");
  }

  private native int foo();

  public static void main(String[] args) {
    System.out.println(new Main().foo());
  }
}
Main.h

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class Main */

#ifndef _Included_Main
#define _Included_Main
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     Main
 * Method:    foo
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_Main_foo(JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

现在通过运行
bazel run:Main
您应该会看到打印出来的
42
,它来自
Main.cc
。这个例子显然需要更多的润色,因此它可以在linux平台以外的平台上工作,也可以与launcher脚本一起工作。您可能最终需要多个
System.loadLibrary
调用,就像bazel在中所做的那样。

实际上,您不需要将bazel local_jdk jni和jni_md头添加到包cc_库目标中。但是,您可以将它们复制到项目包中


我已经向project提交了PR来修复jni相对路径问题。也许这可以帮助您。

我认为您的cc_库应该将其SRC与HDR分开。不确定这是否相关。@kd8azz:afaik
hdrs
用于公共(即api)头。否则,所有标题都被视为源文件。我想这里的答案是:@mhlopko:该项目用于构建LIB,但不是如何在应用程序中使用它们。啊,对不起,我没有注意到是你:)谢谢。问:为什么
:libmain jni.so
数据中,而不是
deps
?或者“runtime\u deps”。在这里使用数据或deps只是风格问题。效果是一样的,因为数据实际上是一个cc二进制文件,它被允许作为java_库的依赖项。
#include <jni.h>
#include <stdio.h>
#include "Main.h"

JNIEXPORT jint JNICALL Java_Main_foo(JNIEnv *, jobject) {
   return 42;
}