Created
July 23, 2018 08:08
-
-
Save caiorss/bcb10be8af3535956778129e2541923c to your computer and use it in GitHub Desktop.
C++ Scala JNI - Java Native Interface - Example - Calling C++ from Scala / Java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Author: Caio Rodrigues | |
// Description: Scala/Java Client Code | |
// | |
// On Unix* loads libTest.so in LD_LIBRARY_PATH | |
object NUtils{ | |
def getPathToApp(implicit cls: Class[_]): String = { | |
import java.io.File | |
val rawPath = cls | |
.getProtectionDomain() | |
.getCodeSource() | |
.getLocation().toExternalForm() | |
if(System.getProperty("os.name").toLowerCase().contains("windows")) | |
// Windows | |
new File(rawPath.stripPrefix("file:/")).getParent.replace("\\", "/") | |
else | |
// Unix - Linux, MacOSX, BSD variants and etc. | |
new File(rawPath.stripPrefix("file:")).getParent | |
} | |
def loadDLL(library: String)(implicit cls: Class[_]) = | |
System.load(NUtils.getPathToApp + "/" + library) | |
} | |
class TestJNI{ | |
init() | |
private def init(){ | |
//System.loadLibrary("TestJNI") | |
NUtils.loadDLL("libTestJNI.so")(getClass()) | |
} | |
@native def printDisplay(): Unit | |
@native def getVersion(): String | |
@native def vector3DLen(a: Double, b: Double, c: Double): Double | |
@native def average(xs: Array[Double]): Double | |
} | |
object Main{ | |
def main(args: Array[String]) = { | |
println("dir = " + System.getProperty("user.dir") + "/" + "libTestJNI.so") | |
val t = new TestJNI() | |
// val t = new TestJNI() | |
t.printDisplay() | |
println("Library version = " + t.getVersion()) | |
println("vector3DLen(3, 4, 5) = " + t.vector3DLen(3, 4, 5)) | |
println("Average of 1, 2 ... 8 = " + t.average(Array(1, 2, 3, 4, 5, 6, 7, 8))) | |
} | |
} | |
// val cls = new dummy.com.MyClass() | |
// cls.printDisplay() | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Compile the C++ code creating a shared library (or shared object in UNIX) | |
$ clang++ TestJNI.cpp -o libTestJNI.so -fPIC -shared -std=c++11 -I$HOME/opt/java/include -I$HOME/opt/java/include/linux | |
Run the application | |
$ scala -save load.scala | |
dir = /home/archbox/opengl/jni/libTestJNI.so | |
Hello world java | |
i = 0 | |
i = 1 | |
i = 2 | |
i = 3 | |
i = 4 | |
Library version = version 3.4 | |
vector3DLen(3, 4, 5) = 7.0710678118654755 | |
Average of 1, 2 ... 8 = 4.5 | |
$ scala -save load.jar | |
dir = /home/archbox/opengl/jni/libTestJNI.so | |
Hello world java | |
i = 0 | |
i = 1 | |
i = 2 | |
i = 3 | |
i = 4 | |
Library version = version 3.4 | |
vector3DLen(3, 4, 5) = 7.071 | |
Check compilation output | |
$ file libTestJNI.so | |
libTestJNI.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=6a21fdf13b652757f1773db2069095eaa050b759, not stripped | |
Check symbols | |
$ nm -D libTestJNI.so | grep " T " | |
0000000000000f08 T _fini | |
0000000000000a28 T _init | |
0000000000000d40 T Java_TestJNI_average | |
0000000000000cc0 T Java_TestJNI_getVersion | |
0000000000000c20 T Java_TestJNI_printDisplay | |
0000000000000cf0 T Java_TestJNI_vector3DLen | |
0000000000000e00 T main | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Author: Caio Rodrigues | |
// Description: Example showing how to call C++ code from Scala/Java | |
// | |
#include <iostream> | |
#include <vector> | |
#include <jni.h> | |
#include <cmath> | |
#define JEXPORT_VOID(name, method, ret) extern "C" JNIEXPORT ret JNICALL \ | |
Java_ ## name## _ ## method (JNIEnv* env, jobject obj) | |
// JNI NAME RULE: Java_[package-name]_[class_name]_[exported function] | |
// - JNIEnv* => Pointer to the VM | |
// - jobject => Pointer to current object (or this*) | |
#define JEXPORT(name, method, ret, ...) extern "C" JNIEXPORT ret JNICALL \ | |
Java_ ## name## _ ## method (JNIEnv* env, jobject obj, ##__VA_ARGS__) | |
/** Generates: | |
extern "C" JNIEXPORT ret JNICALL Java_TestJNI_printDisplay | |
*/ | |
JEXPORT_VOID(TestJNI, printDisplay, void){ | |
std::cout << "Hello world java" << std::endl; | |
for (int i = 0; i < 5; i++){ | |
std::cout << "i = " << i << std::endl; | |
} | |
} | |
JEXPORT(TestJNI, getVersion, jstring){ | |
return env->NewStringUTF("version 3.4"); | |
} | |
// extern "C" JNIEXPORT jdouble JNICALL Java_TestJNI_vector3DLen( | |
// JNIEnv*, jobject, jdouble a, jdouble b, jdouble c){ | |
// return sqrt(a * a + b * b + c * c); | |
// } | |
JEXPORT(TestJNI, vector3DLen, jdouble, jdouble a, jdouble b, jdouble c){ | |
return sqrt(a * a + b * b + c * c); | |
} | |
// extern "C" JNIEXPORT jdouble JNICALL Java_TestJNI_average( | |
JEXPORT(TestJNI, average, double, jdoubleArray xs){ | |
jdouble* ptr = env->GetDoubleArrayElements(xs, nullptr); | |
if(ptr == NULL) | |
return 0.0; | |
jsize n = env->GetArrayLength(xs); | |
jdouble sum = 0.0; | |
for(int i = 0; i < n; i++){ | |
sum += ptr[i]; | |
} | |
return sum / n; | |
} | |
extern "C" int main(){ | |
std::cout << "Hello world" << std::endl; | |
return 0; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment