Внешний блок "Java" в GCC

Я нашел интересную особенность в документации GCC для C++:

java_interface

Этот атрибут типа сообщает C++, что класс является интерфейсом Java. Он может применяться только к классам, объявленным внутри внешнего блока "Java". Вызовы методов, объявленные в этом интерфейсе, будут отправляться с использованием механизма таблицы интерфейса GCJ вместо обычной отправки виртуальных таблиц.

Как я понимаю, это будет выглядеть примерно так:

extern "Java" {
    class NativeClass __attribute__((java_interface)) {
        //Implementation on native methods goes here.
    }
}

Кто-нибудь знает подробности об этом? Как вызвать методы NativeClass из Java? Может быть, кто-нибудь пробовал это в реальной жизни?

2 ответа

Решение

GCJ предоставляет два нативных интерфейса для Java: JNI с использованием C и CNI с использованием C++. Поскольку пример, который вы цитируете, использует класс, он должен ссылаться на последний. Документация CNI по интерфейсам только описывает, как получить доступ к интерфейсам, описанным в Java, из кода C++. Ваш пример работает наоборот: класс, написанный на C++, который доступен из Java и служит интерфейсом Java.

Но подробностей об этом доступно довольно мало, поэтому метод проб и ошибок будет одним из способов поэкспериментировать с этим, а другой взгляд - на источники GCC. Если вы хотите увидеть один пример обоих extern "Java" блок и java_interface атрибут, посмотрите на java/lang/Readable.h, Он содержит C++ представление интерфейса Java java.lang.Readable, Как указано в первой строке этого файла, он генерируется машиной. Так что, вероятно, причина, по которой так мало документации, заключается в том, что вы не должны писать этот материал самостоятельно. Это просто деталь того, как GCJ реализует CNI. И если присмотреться более внимательно к приведенному выше файлу, кажется, что они даже нарушают собственную документацию, поскольку Readable.h имеет атрибут вне extern блок, в отличие от фрагмента, который вы цитировали.

Когда я впервые встретил этот тип блока, он был не для "java", а для "C", так что я думаю, что это тот же интерес. Блок определяется:

extern "Java"
{
// some java definition
}

используется для указания GCC, что этот блок является интерфейсом Java. Используется для описания того, какой тип искажения используется для определения класса. Перенос имени используется gcc для генерации имени функции по параметрам и т. Д. Более подробная информация здесь: http://www.agner.org/optimize/calling_conventions.pdf Таким образом, вы используете extern "Java" когда вы импортируете java-код с его помощью, вы можете вызывать его juste, как и любую функцию в C/C++ без указания искаженного имени. Я использовал его только для DLL с определенными в нем функциями C, загруженными в код на C++, поэтому я использую extern "C", чтобы указать GCC, что определение этой функции не использует искажение имени. Хорошо, теперь, как вызвать нативный метод в java, потому что все в java это метод, все это объект, нет функции. Во-первых, вы должны описать свой класс в java, все ваши функции, которые вы хотите выполнять в нативном языке, должны быть определены как нативные: private native void print(); например. Во-вторых, вернувшись в свой заголовок собственного кода, вы должны определить метод, следуя номенклатуре:

extern "Java"
{
        JNIEXPORT YourReturnType JNICALL Java_ClassName_MethodName (JNIEnv* env, jobject obj);
}

По крайней мере, все методы должны выглядеть так, потому что JNI будет отправлять указатель JNIEnv и объект, который будет "this" в методе, если у вас есть другие аргументы, они должны быть заданы после 2 основ. Наконец, вам просто нужно реализовать все методы в файле с собственным кодом, всегда следуя норме, например:

 JNIEXPORT void JNICALL Jave_Printer_print(JNIEnv* env, jobject obj)
 {
      printf("Hello world");
 }

Теперь вы можете создать объект Printer в Java и вызвать метод print, определенный как native. Я надеюсь, что ответил на ваш вопрос.

Другие вопросы по тегам