Skip to content

Instantly share code, notes, and snippets.

@JNNGL
Last active May 13, 2023 18:29

Revisions

  1. JNNGL revised this gist May 13, 2023. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion RuntimeJNI.java
    Original file line number Diff line number Diff line change
    @@ -46,7 +46,7 @@ JNIEXPORT void JNICALL Java_Test_hello(JNIEnv* env, jclass class) {
    processBuilder.redirectErrorStream(true);
    processBuilder.redirectOutput(ProcessBuilder.Redirect.INHERIT);
    processBuilder.directory(directory.toFile());
    processBuilder.start().waitFor(); // TODO: Write native library directly in native form
    processBuilder.start().waitFor(); // TODO: Write native library directly in binary form

    try (URLClassLoader classLoader = new URLClassLoader(new URL[]{directory.toUri().toURL()})) {
    Class<?> nativeBinding = classLoader.loadClass("Test");
  2. JNNGL revised this gist May 13, 2023. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion RuntimeJNI.java
    Original file line number Diff line number Diff line change
    @@ -34,7 +34,7 @@ public static void main(String[] args) throws Throwable {
    String bindingCode = """
    #include <jni.h>
    extern void hello();
    JNIEXPORT void JNICALL Java_Test_hello(JNIEnv*, jclass class) {
    JNIEXPORT void JNICALL Java_Test_hello(JNIEnv* env, jclass class) {
    hello();
    }""";

  3. JNNGL revised this gist May 13, 2023. 1 changed file with 0 additions and 1 deletion.
    1 change: 0 additions & 1 deletion RuntimeJNI.java
    Original file line number Diff line number Diff line change
    @@ -56,7 +56,6 @@ JNIEXPORT void JNICALL Java_Test_hello(JNIEnv*, jclass class) {
    nativeBinding.getMethod("hello").invoke(null);
    }


    try (Stream<Path> stream = Files.walk(directory)) {
    stream.sorted(Comparator.reverseOrder())
    .map(Path::toFile)
  4. JNNGL created this gist May 13, 2023.
    66 changes: 66 additions & 0 deletions RuntimeJNI.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,66 @@
    import org.objectweb.asm.*;
    import java.io.File;
    import java.net.URL;
    import java.net.URLClassLoader;
    import java.nio.file.Files;
    import java.nio.file.Path;
    import java.util.Comparator;
    import java.util.stream.Stream;

    import static org.objectweb.asm.Opcodes.*;

    public class Main {

    public static void main(String[] args) throws Throwable {
    ClassWriter cw = new ClassWriter(0);
    cw.visit(49, ACC_PUBLIC + ACC_SUPER, "Test", null, "java/lang/Object", null);

    // public static native void hello();
    cw.visitMethod(ACC_PUBLIC + ACC_STATIC + ACC_NATIVE, "hello", "()V", null, null).visitEnd();

    // public static void loadLibrary(String lib) { System.load(lib); }
    MethodVisitor mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "loadLibrary", "(Ljava/lang/String;)V", null, null);
    mv.visitVarInsn(ALOAD, 0);
    mv.visitMethodInsn(INVOKESTATIC, "java/lang/System", "load", "(Ljava/lang/String;)V", false);
    mv.visitInsn(RETURN);
    mv.visitMaxs(1, 1);
    mv.visitEnd();

    cw.visitEnd();

    Path directory = Files.createTempDirectory("test");
    Files.write(directory.resolve("Test.class"), cw.toByteArray());

    String bindingCode = """
    #include <jni.h>
    extern void hello();
    JNIEXPORT void JNICALL Java_Test_hello(JNIEnv*, jclass class) {
    hello();
    }""";

    String targetLib = new File("hello.so").getAbsolutePath();

    Files.writeString(directory.resolve("glue.c"), bindingCode);
    ProcessBuilder processBuilder = new ProcessBuilder("bash", "-c", "gcc -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux -Os -fPIC -shared glue.c -o binding.so " + targetLib);
    processBuilder.environment().put("JAVA_HOME", System.getProperty("java.home"));
    processBuilder.redirectErrorStream(true);
    processBuilder.redirectOutput(ProcessBuilder.Redirect.INHERIT);
    processBuilder.directory(directory.toFile());
    processBuilder.start().waitFor(); // TODO: Write native library directly in native form

    try (URLClassLoader classLoader = new URLClassLoader(new URL[]{directory.toUri().toURL()})) {
    Class<?> nativeBinding = classLoader.loadClass("Test");
    nativeBinding.getMethod("loadLibrary", String.class)
    .invoke(null, directory.resolve("binding.so").toFile().getAbsolutePath());

    nativeBinding.getMethod("hello").invoke(null);
    }


    try (Stream<Path> stream = Files.walk(directory)) {
    stream.sorted(Comparator.reverseOrder())
    .map(Path::toFile)
    .forEach(File::deleteOnExit);
    }
    }
    }
    5 changes: 5 additions & 0 deletions hello.c
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,5 @@
    #include <stdio.h>

    void hello() {
    puts("Hello, world!");
    }