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

mob*_*ink 2 java java-native-interface bazel

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

java_binary(
    name = "OCFTestServer",
    srcs = glob(["src/main/java/**/*.java"]),
    deps = ["//:OpenOCF-JNI"])
Run Code Online (Sandbox Code Playgroud)

这里OpenOCF-JNI看起来像这样:

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

并且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 ...
Run Code Online (Sandbox Code Playgroud)

这些都构建成功。但是,构建不会导致构建依赖项,这正是我所期望的(即构建 OCFTestServer 应该导致构建 OpenOCF-JNI,这应该导致构建 libopenocf-jni)。难道不应该发生这种事吗?

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

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

hlo*_*pko 5

我创建了一个简单的存储库:https://github.com/mhlopko/bazel-jni-example来帮助您入门。

BUILD:

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=." ],
)
Run Code Online (Sandbox Code Playgroud)

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());
  }
}
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

Main.cc:

#include <jni.h>
#include <stdio.h>
#include "Main.h"

JNIEXPORT jint JNICALL Java_Main_foo(JNIEnv *, jobject) {
   return 42;
}
Run Code Online (Sandbox Code Playgroud)

现在,通过运行,bazel run :Main您应该看到42打印出来的内容,它来自Main.cc. 该示例显然需要更多改进,以便它可以在 Linux 以外的平台上运行,并且可以与启动器脚本一起运行。您最终可能需要多次System.loadLibrary调用,就像 bazel 在其 windows loader中所做的那样。