2017-09-16 108 views
2

我已经设法构建了我的JNI库(jar,jni共享cc_library,包装的cc_library),但是我看不到如何构建使用它的Java应用程序。我的BUILD很简单:Bazel:具有JNI依赖性的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包装器),则获得UnsatisfiedLinkError: no libopenocf-jni in java.library.path。但是通过阅读文档,我得到的印象是应该全部自动设置(即所需的jni库应该放在java.library.path中)。

我在做什么错?有没有人有一个构建和使用JNI库的例子?

+0

我认为你的cc_library应该将srcs从它的hdrs中分离出来。不确定这是否相关。 – kd8azz

+0

@ kd8azz:afaik'hdrs'用于公共(即api)标题。否则所有标题都被视为源文件。 – mobileink

+0

我认为这是在这里回答:https://stackoverflow.com/questions/46160790/bazel-for-jni-jni-h-file-not-found – mhlopko

回答

0

我偶然发现你的问题,同时试图找出如何链接到malmo,我刚刚工作。它链接到一个静态库,所以它可能会或可能不会帮助你。

THIRD_PARTY/BUILD:

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

cc_library(
    name = "libMalmo", 
    srcs = ["libMalmoJava.so"], 
) 

然后在我的实际目标:

"//third_party:malmo", 
1

我创建了一个简单的回购: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=." ], 
) 

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 

Main.cc

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

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

现在通过运行bazel run :Main您应该看到42打印出来,即来自Main.cc。这个例子显然需要更多的光泽,所以它可以在非Linux平台上工作,所以它可以与启动脚本一起工作。您可能最终需要多个System.loadLibrary来电,例如its windows loader中的bazel。

+0

谢谢。问:为什么数据中的':libmain-jni.so'而不是'deps'? – mobileink

+0

或'runtime_deps'。 – mobileink

+0

使用数据或代码只是这里的风格问题。由于数据实际上是一个cc二进制文件,因此可以作为java_library的依赖项,所以效果相同。 –