Skip to content

Instantly share code, notes, and snippets.

@jiqiujia
Forked from caiorss/Running.txt
Created November 20, 2018 06:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jiqiujia/b5126b2790f8a723f902fea8751392d8 to your computer and use it in GitHub Desktop.
Save jiqiujia/b5126b2790f8a723f902fea8751392d8 to your computer and use it in GitHub Desktop.
C++ Scala JNI - Java Native Interface - Example - Calling C++ from Scala / Java
// 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()
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
// 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