I made a plugin to execute jextract with Gradle task

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.

Operating environment

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

What is 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).

jextract task

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
}

Production process

Call jextract

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"});
    }
}

Make a plugin

I referred to this article.

Be careful

Recommended Posts

I made a plugin to execute jextract with Gradle task
I made a GUI with Swing
I made a command line interface with WinMerge Plugin using JD-Core
I made a risky die with Ruby
I made a plugin for IntelliJ IDEA
I made a rock-paper-scissors app with kotlin
I made a rock-paper-scissors app with android
I made an app to scribble with PencilKit on a PDF file
04. I made a front end with SpringBoot + Thymeleaf
I made a mosaic art with Pokemon images
I made a gender selection column with enum
I made a Docker container to run Maven
I wanted to gradle spring boot with multi-project
I made a LINE bot with Rails + heroku
I tried to break a block with java (1)
I made a portfolio with Ruby On Rails
[Java 11] I tried to execute Java without compiling with javac
I made a method to ask for Premium Friday
[Ruby] I made a crawler with anemone and nokogiri.
I want to monitor a specific file with WatchService
I made a function to register images with API in Spring Framework. Part 1 (API edition)
I tried to create a java8 development environment with Chocolatey
I made a development environment with rails6 + docker + postgreSQL + Materialize.
I tried to modernize a Java EE application with OpenShift.
[Rails] I tried to create a mini app with FullCalendar
I want to push an app made with Rails 6 to GitHub
[Beginner] I made a program to sell cakes in Java
I want to make a list with kotlin and java!
I made a chat app.
I want to make a function with kotlin and java!
I made a mod that instantly calls a vehicle with Minecraft
[Rails] I tried to implement batch processing with Rake task
Even in Java, I want to output true with a == 1 && a == 2 && a == 3
I made a function to register images with API in Spring Framework. Part 2 (Client Edition)
I tried to create a padrino development environment with Docker
[Personal development] I made a site to recruit test users!
I made a Dockerfile to start Glassfish 5 using Oracle Java
A story that made it convenient with Kotlin that it is troublesome to execute animation continuously on Android
A story that I struggled to challenge a competition professional with Java
[Rails] I made a simple calendar mini app with customized specifications.
I want to make a button with a line break with link_to [Note]
Set Spring profile when executing bootRun task with Spring Boot Gradle Plugin
I want to add a browsing function with ruby on rails
[Unity] I tried to make a native plug-in UniNWPathMonitor using NWPathMonitor
I made a gem to post the text of org-mode to qiita
I made a simple search form with Spring Boot + GitHub Search API.
I made a method to ask for Premium Friday (Java 8 version)
[Introduction to JSP + Servlet] I played with it for a while ♬
I made a tool to output the difference of CSV file
I want to extract between character strings with a regular expression
I tried to make a group function (bulletin board) with Rails
Ruby: I made a FizzBuzz program!
I can't install lombok with Gradle.
I tried to interact with Java
I made a simple recommendation function.
How to make a Jenkins plugin
I made a matching app (Android app)
I made a package.xml generation tool.
[Android] I made a pedometer app.
I was in trouble at work, so I made a plugin for IntelliJ
I want to select multiple items with a custom layout in Dialog