jnigen: JNI with less pain

I think jnigen is quite neat and I finally got around to writing some better documentation:

libgdx uses it to wrap Box2D, libjpeg, vorbis, mpeg123, and many other things, but jnigen isn’t specific to libgdx. It can be used to build any native libraries for use with Java. Eg, Jglfw uses it to wrap GLFW. Next time you need to interface with native code, maybe you keep it in mind! :slight_smile:

Hi

It’s not that bad :stuck_out_tongue: You can directly write the C/C++ source code in the Java source code, it supports iOS too and it seems documented but GlueGen already does a very good job on OpenGL, OpenAL and OpenCL. If a developer wants to keep C/C++ and Java source code into separate files, GlueGen should be used, otherwise jnigen is a better choice.

I’m not familiar with GlueGen. Gave it a very quick look. It looks limited to C, so if you need C++ that might be an issue. I can’t comment much further on it without digging deeper, though I can say mapping C to Java looks quite complex.

It seems the biggest difference between jnigen and tools that generate Java code from native code (GlueGen, SWIG, etc) is that jnigen allows you to write and control the Java code. Typically this will mean a nicer Java API, since it is handwritten and customized for the intended usage. I do concede that it can reduce development time to generate Java code from native code.

jnigen also feels to me like a simpler approach to the problem. You end up with exactly what you’d have if you were hand writing JNI: Java native methods and corresponding native code (in a separate file). jnigen reduces the pain of JNI by generating and populating the native code and handling the build for all platforms. If you rename a Java native method, add new native methods, new classes, change method signatures, etc you don’t have to do anything.

jnigen should work great for projects that want to keep source in separate files. If I were doing that, I would still use native code inline with the Java code, but only for the Java to native interface. The rest of the code I would put in a separate file. jnigen has a special “/*JNI” comment for includes, statics, functions, etc. The contents just get inserted in your native code.


public class Example {
	/*JNI
	#include <otherStuff.h>
	#include <moreStuff.h>
	*/

	static public native void doStuff (); /*
		// use included stuff
	*/
}

[quote]run:
C/C++ for ‘src/pl/mac70/jdirect/Window.java’ up to date
Wrote target ‘Windows’ build script ‘jni\build-windows32.xml’
Wrote master build script ‘jni\build.xml’
Executing ‘ant.bat -f D:\jDirect\jDirect\jni\build-windows32.xml -v -Dhas-compiler=true clean postcompile’
Executing ‘ant.bat -f D:\jDirect\jDirect\jni\build.xml -v pack-natives’
java.io.IOException: Cannot run program “ant.bat”: CreateProcess error=2, Nie mo¿na odnaleŸæ okreœlonego pl
at java.lang.ProcessBuilder.start(ProcessBuilder.java:1041)
at com.badlogic.gdx.jnigen.BuildExecutor.startProcess(BuildExecutor.java:51)
at com.badlogic.gdx.jnigen.BuildExecutor.executeAnt(BuildExecutor.java:38)
at pl.mac70.test.JNIBuild.main(JNIBuild.java:17)
Caused by: java.io.IOException: CreateProcess error=2, Nie mo¿na odnaleŸæ okreœlonego pl
at java.lang.ProcessImpl.create(Native Method)
at java.lang.ProcessImpl.(ProcessImpl.java:385)
at java.lang.ProcessImpl.start(ProcessImpl.java:136)
at java.lang.ProcessBuilder.start(ProcessBuilder.java:1022)
… 3 more
java.io.IOException: Cannot run program “ant.bat”: CreateProcess error=2, Nie mo¿na odnaleŸæ okreœlonego pl
at java.lang.ProcessBuilder.start(ProcessBuilder.java:1041)
at com.badlogic.gdx.jnigen.BuildExecutor.startProcess(BuildExecutor.java:51)
at com.badlogic.gdx.jnigen.BuildExecutor.executeAnt(BuildExecutor.java:38)
at pl.mac70.test.JNIBuild.main(JNIBuild.java:19)
Caused by: java.io.IOException: CreateProcess error=2, Nie mo¿na odnaleŸæ okreœlonego pl
at java.lang.ProcessImpl.create(Native Method)
at java.lang.ProcessImpl.(ProcessImpl.java:385)
at java.lang.ProcessImpl.start(ProcessImpl.java:136)
at java.lang.ProcessBuilder.start(ProcessBuilder.java:1022)
… 3 more
BUILD SUCCESSFUL (total time: 0 seconds)
[/quote]
Any ideas? ::slight_smile: Error(s) caused by this code:

package pl.mac70.test;

import com.badlogic.gdx.jnigen.*;
import com.badlogic.gdx.jnigen.BuildTarget.TargetOs;

public class JNIBuild {

    static public void main (String[] args) throws Exception {
        NativeCodeGenerator jnigen = new NativeCodeGenerator();
        jnigen.generate("src", "build/classes", "jni", new String[] {"**/*"}, null);

        BuildTarget win32 = BuildTarget.newDefaultTarget(TargetOs.Windows, false);
        win32.compilerPrefix = "mingw32-";
        //BuildTarget win64 = BuildTarget.newDefaultTarget(TargetOs.Windows, true);

        new AntScriptGenerator().generate(new BuildConfig("jDirectDll"), win32);
        BuildExecutor.executeAnt("jni/build-windows32.xml", "-v -Dhas-compiler=true clean postcompile");
        //BuildExecutor.executeAnt("jni/build-windows64.xml", "-v -Dhas-compiler=true clean postcompile");
        BuildExecutor.executeAnt("jni/build.xml", "-v pack-natives");
    }
    
}

Ant (and MinGW) needs to be on your path.

Both of them are added, still the same error. Path is working correctly via cmd for both mingw32-C++ (and everything else with “mingw32-” in name) and ant.bat

Restart Eclipse, probably it doesn’t see your path changes.