Встраиваем интерпретатор Python в java-приложение с помощью проекта Panama

Пару дней назад увидел твит Брайана Гетца, но только сегодня дошли руки поиграться с примерами.

image

Про это и хочу кратко рассказать.

О проекте Panama на Хабре уже писали, поэтому просто покажу пару простых примеров того, как можно применить native binder.
Прежде всего вам понадобится компилятор C. Если вы используете Linux или MacOS, то он у вас уже есть. Если Windows, то придётся сначала установить Build Tools for Visual Studio 2017. И, конечно же, вам потребуется OpenJDK с поддержкой «Панамы». Получить его можно либо сборкой ветки «foreign» соответствующего репозитория, либо загрузкой Early-Access билда.

Начнём с минимального примера — простой функции складывающей два числа:

adder.h

#ifndef _ADDER_H
#define _ADDER_H

__declspec(dllexport) int add(int, int);

#endif


adder.c

#include "adder.h"

__declspec(dllexport)
int add(int a, int b) {
    return a + b;
}


Example.java

// импорт jextract'нутых "заголовочных" классов
import static com.example.adder_h.*;

public class Example {
    public static void main(String[] args) {
        System.out.println(add(3, 5));
    }
}


Компилируем в DLL

cl /LD adder.c


Используем утилиту jextract для генерации java-интерфейса на основе заголовочного файла:

jextract -L . -l adder -o adder.jar -t "com.example" adder.h


И используем полученный jar-файл для сборки и запуска java-кода:

javac -cp adder.jar Example.java
java -cp .;adder.jar Example


Пока не особенно впечатляет, но позволяет понять принцип. Теперь попробуем использовать python37.dll.

PythonMain.java

import java.foreign.Libraries;
import java.foreign.Scope;
import java.foreign.memory.Pointer;

import static org.python.Python_h.*;
import static org.python.pylifecycle_h.*;
import static org.python.pythonrun_h.*;

public class PythonMain {
    public static void main(String[] args) {
        Py_Initialize();
        try (Scope s = Scope.newNativeScope()) {
            PyRun_SimpleStringFlags(s.allocateCString(
                "print(sum([33, 55, 66]))\n"),
                Pointer.nullPointer());
        }
        Py_Finalize();
    }
}


Генерируем интерфейсы:

jextract -L "C:\Python37" -l python37 -o python.jar -t "org.python" --record-library-path C:\Python37\include\Python.h


Компилируем и запускаем:

javac -cp python.jar PythonMain.java
java -cp .;python.jar PythonMain


Поздравляю, ваше java-приложение только что загрузило в себя интерпретатор Python и выполнило в нём скрипт!

image


Больше примеров можно посмотреть в инструкции для первопроходцев.

© Habrahabr.ru