Reputation: 173
I've managed to build my JNI library (the jar, the jni shared cc_library, the wrapped cc_library) but I don't see how to build a Java app that uses it. My BUILD is simple:
java_binary(
name = "OCFTestServer",
srcs = glob(["src/main/java/**/*.java"]),
deps = ["//:OpenOCF-JNI"])
Here OpenOCF-JNI
looks like this:
java_library(
name = "OpenOCF-JNI",
srcs = glob(["src/main/**/*.java"]),
deps = ["libopenocf"],
visibility = ["//visibility:public"])
And libopenocf
is:
cc_library(
name = "libopenocf",
srcs = glob(["src/c/*.c"]) + glob(["src/c/*.h"])
+ ["@local_jdk//:jni_header",
"@local_jdk//:jni_md_header-darwin"],
... etc ...
These all build successfully. However, building does not cause dependencies to be built, which is what I would expect (i.e. building OCFTestServer should cause OpenOCF-JNI to be built, which should cause libopenocf-jni to be built). Shouldn't that happen?
If I build them all using separate steps and then try to run the application (using the OCFTestServer wrapper in bazel-bin), I get UnsatisfiedLinkError: no libopenocf-jni in java.library.path
. But from reading the docs I get the impression that this should all be set up automatically (i.e. the needed jni lib should be put in the java.library.path).
What am I doing wrong? Does anybody have an example of building and using a JNI lib?
Upvotes: 2
Views: 2891
Reputation: 24
Actually, you don't need to add bazel local_jdk jni and jni_md headers to your package cc_library target. But, you can copy them to your project package.
I have already submit PR to https://github.com/mhlopko/bazel-jni-example project to fix the jni relative path problem. maybe this could help you.
Upvotes: 0
Reputation: 3268
I created a simple repo: https://github.com/mhlopko/bazel-jni-example to help you get started.
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;
}
Now by running bazel run :Main
you should see 42
printed out, that is coming from Main.cc
. The example clearly needs more polish so it works on other-than-linux platforms, and so it works with the launcher script. You might end up needing multiple System.loadLibrary
calls, like bazel does in its windows loader.
Upvotes: 5
Reputation: 623
I stumbled across your question, while trying to figure out how to link to malmo, which I just got working. It's linking against a static library, so it may or may not help you.
third_party/BUILD:
java_import(
name = "malmo",
jars = ["MalmoJavaJar.jar"],
deps = [":libMalmo"],
)
cc_library(
name = "libMalmo",
srcs = ["libMalmoJava.so"],
)
And then in my actual target:
"//third_party:malmo",
Upvotes: 0