I made a gradle plugin as the title says. We are currently applying for the gradle repository. Click here for source code
jnr-ffi Plugin
This plugin makes it easier to use the features under development (to be implemented in Java 13) in Project Panama.
In particular, it aims to make JEP 191: Foreign Function Interface more convenient.
JNR related articles are summarized in this Qiita, so please do not hesitate to contact us.
Version 13 or higher for both the system JDK and project JDK?
The operation-guaranteed JDK is Project Panama Early-Access Builds only.
If the JDK version is 12 or less, a warning message will be issued, and if jextract does not exist in the system JDK, an error message will be issued.
jextract
jextract is a tool that generates the corresponding Java interface from .h files such as C language.
It is attached to early-access version JDK and is attached to Service Loader. It can also be called programmatically by using api / java / util / ServiceLoader.html).
This plugin defines a task called jextract.
The jextract task uses jextract to generate a jar file (corresponding interface) from the .h files in the specified folder.
(It also searches for nested files and associates the directory with the package to generate a jar)
Options for the jextract task can be specified in build.gradle as follows:
build.gradle
jextract{
// .h The path of the directory containing the file
//The initial value is"src/main/resources/"
sourceRoot = "head/"
//The path of the directory to put the generated jar
//The initial value is"libs/"
outPath = "jar"
//The root name of the package to which the generated interface belongs
// <packageRoot>.<Directory name>.<Directory name>Is named like
//The initial value is""
packageRoot = "pkg"
//Whether the package name includes the sourceRoot directory
//If set to false, it is directly under SourceRoot..The h file package becomes packageRoot
//Initial value is false
includeRoot = false
}
Call jextract using ServiceLoader. By the way, if you try to call com.sun.tools.jextract.Main $ JextractToolProvider directly, you will get a compile error. (Is it because of resources / Message.properties?)
Now, let's write the Java code.
Test.java
public class Test{
public static void main(String[] args){
//Get the implementation list of ToolProvider with ServiceLoader.
//Those in the JDK bin, such as jshell and jextract, will be returned.
//The tool name of jextract is"jextract"So use the one that matches.
ServiceLoader<ToolProvider> providers = load(ToolProvider.class);
ToolProvider provider = null;
for (ToolProvider tool : providers) {
if (tool.name().equals("jextract")) provider = tool;
}
if(provider == null) System.out.println("error:jextract does not exist.");
//Pass the command line arguments when calling jextract to the last argument array.
//Separate elements instead of separating them with spaces.
provider.run(System.out, System.err, String[]{"src/main/resources/test.h"});
}
}
test.h
int hoge(void);
If you create test.h in src / main / resources / and execute Test.main, a file called test.h.jar will be created directly under the project.
In addition, the options used this time are excerpted.
option | argument | Description |
---|---|---|
-t | package name | The generated interface will belong to the package |
-o | file name(Including the path) | file name(path)The generated jar file is placed in |
file name(Including the path) | I want to convert.file name of h file(path) Multiple selections are possible, but they are always generated as the same package |
For example
jextract -t pkg -o out.jar test.h
When you execute the command, or
Test.java
public class Test{
public static void main(String[] args){
ServiceLoader<ToolProvider> providers = load(ToolProvider.class);
ToolProvider provider = null;
for (ToolProvider tool : providers) {
if (tool.name().equals("jextract")) provider = tool;
}
provider.run(System.out, System.err, String[]{"-o", "out.jar", "-t", "pkg", "test.h"});
}
}
When I ran the program
test.h
int hoge(void);
If there is a file called out.jar, a file called out.jar will be generated.
out.jar
|-META-INF
| \jextract.properties
\pkg
\test.class
The internal structure of out.jar is as follows, and you can see that a package directory called pkg is generated.
If you decompile Test.class using jad, you will see that it looks like this:
Test.jad
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3)
package pkg;
public interface test
{
public abstract int hoge();
}
The .h file is firmly transpiled to the interface.
Also, when I made it a plugin, ServiceLoader didn't find jextract, so after changing the system JDK to 13, I changed the call a bit.
public class Test{
public static void main(String[] args){
//Use the system class loader
ServiceLoader<ToolProvider> providers = load(ToolProvider.class, ClassLoader.getSystemClassLoader());
ToolProvider provider = null;
for (ToolProvider tool : providers) {
if (tool.name().equals("jextract")) provider = tool;
}
provider.run(System.out, System.err, String[]{"-o", "out.jar", "-t", "pkg", "test.h"});
}
}
I referred to this article.
Recommended Posts