Отладка кода JNI с помощью Xcode 4 / OS X 10.6

Я рвал на себе волосы, пытаясь выяснить что-то, что является бессмысленным в Windows / Visual Studio. У меня есть библиотека JNI под OS X 10.6, которую я хотел бы вызвать с помощью исполняемого файла Java и отладки под Xcode: пошаговое выполнение кода, проверка переменных в моей библиотеке JNI, установка точек останова и т. Д.

Вот рабочий пример JNI, который хорошо компилируется и запускается из командной строки. Если бы кто-то мог сказать мне, как настроить это в XCode, я был бы бесконечно благодарен. В идеале я хотел бы, чтобы пошаговые инструкции начинались с нуля в Xcode и вырезались и вставлялись из кода ниже, в зависимости от ситуации, что приводило бы к чему-то, что можно отлаживать в Xcode 4 и позволяло мне устанавливать точки останова в коде JNI, исследовать переменные посмотреть трассировку стека и т. д.

В знак благодарности я отправлю 20 долларов первому человеку, который даст мне такие инструкции, которые я смогу воспроизвести на моем конце, если вы дадите мне адрес Paypal.

Заранее спасибо!

HelloWorld.java

class HelloWorld {
    public native String displayHelloWorld();

    static {
        System.loadLibrary("HelloWorldImp");
    }

    public static void main(String[] args) {
        System.out.println("--> "+new HelloWorld().displayHelloWorld());
    }
}

HelloWorldImp.mm

#include <stdio.h>
#include <jni.h>

#include <string>

#import <Foundation/Foundation.h>

#ifdef __cplusplus
extern "C" {
#endif

JNIEXPORT jstring JNICALL
Java_HelloWorld_displayHelloWorld(JNIEnv *env, jobject obj)
{
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    NSString* name = @"Yo Cocoa";
    std::string s = [name UTF8String];    

    jstring ret = env->NewStringUTF(s.c_str());

    [pool drain];

    return ret;
}

#ifdef __cplusplus
}
#endif

buildjni.sh

gcc -bundle -I/System/Library/Frameworks/JavaVM.framework/Headers -lstdc++ -o libHelloWorldImp.jnilib -framework Foundation HelloWorldImp.mm

1 ответ

Решение

Ну вот.

Строим библиотеку
Вы, наверное, знаете, что jni libs на mac должен быть назван в форме libFoo.jnilib. Затем вы загружаете библиотеку из Java, вызывая System.loadLibrary ("Foo");
1. Создайте новый динамический библиотечный проект. Назовите это libSomething. Это половина битвы имен.
2. Найдите целевые параметры сборки для исполняемого расширения. По умолчанию это установлено в dylib. Измените это, чтобы быть jnilib. Это вторая половина битвы имен.
3. Добавьте фреймворк JavaVM в связанные фреймворки. Это содержит JNI.
4. Создайте свой собственный заголовочный файл как обычно.
5. Включите его в свой проект и создайте соответствующий файл.m.
6. Вы должны изменить путь включения для jni.h. На маке это <JavaVM/jni.h> или используйте инфраструктуру JavaNativeFoundation. Я рекомендую последнее.
7. (необязательно) JavaNativeFoundation предоставляет ряд макросов и методов, которые значительно упростят преобразование данных / методов в / из Java/Objective-C. Это не очень хорошо задокументировано, но это стоит исследовать. Если вы решили использовать JNF, используйте открытый треугольник в инфраструктуре JavaVM. Вы увидите, что JNF является подрамником. Перетащите его на верхний уровень, равный JavaVM. Тогда вы можете начать использовать его. Импортировать <JavaNativeFoundation/JavaNativeFoundation.h> Выполните поиск в Google на JNF_COCOA_ENTER, чтобы увидеть примеры использования JNF.

Теперь вы должны иметь возможность построить действительную библиотеку jni. Предполагая, что в вашем коде нет ошибок, все готово.;-)

отладка
Я перепробовал все, что нашел на разных веб-страницах, чтобы заставить работать JNI в Xcode. Это сработало, но зависало при переходе через вызовы какао. Тем не менее, отладка с помощью GDB работает. Это действительно не так уж плохо, если вы запускаете GDB в Emacs. Недостатком, конечно же, является то, что вам нужно набрать скорость на emacs и gdb, если вы еще этого не сделали. Вот суть:
1. Скомпилируйте вашу библиотеку с отладочными символами
2. Установите точку останова в вашем коде вызова Java после загрузки библиотеки, но перед вызовом кода, который вы хотите отладить. В качестве альтернативы, вы можете поместить туда showMessageDialog. Все, что заблокирует Java-программу в нужной точке.
3. Откройте Activity Monitor и запишите pid вашей Java-программы.
4. Запустите Emacs. Если вы находитесь на Lion, терминал emacs, который поставляется вместе, должен работать. На SL терминальный Emacs не обладает магией GDB. В обоих случаях, однако, я рекомендую вам скачать и использовать Mac Gui Emacs. Доступно более одного, я использую тот, который получил здесь. Если вы используете emacs в терминале, вам нужно перейти в Termina/Preferences/Settings/Keyboard и посмотреть вниз. Есть флажок "использовать опцию как мета-ключ". Вы хотите, чтобы это проверили.
5. При запущенном emacs нажмите Mx (опция x). Введите GDB и нажмите Enter. Вы увидите что-то вроде "gdb --annotate=2 xxxxxxxxxx". Нажимайте клавишу Backspace, пока не доберетесь до настройки аннотирования. Введите "pid xxx", где xxx - это pid вашего приложения для вызова Java. В итоге вы должны получить строку, похожую на "gdb --annotate=2 pid xxxx". Нажмите Ввод.
6. Вы должны увидеть, как gdb загружает символы для вашей jni lib.
7. Теперь нажмите Mx. Наберите gdb-many-windows. Нажмите Ввод.
8. Теперь вы должны увидеть несколько окон в Emacs. Окно команды GDB, локальные переменные, исходный код и другие.
9. Введите break someFunctionName в командном окне. Нажмите Ввод.
10. Введите продолжение в командном окне. (Это приводит к продолжению выполнения). Нажмите Ввод.
11. Теперь продолжайте в отладчике Java или нажмите Enter в диалоговом окне Java.
12. Вы должны увидеть, как gdb достиг точки останова в вашем коде jni.
13. Изучите Emacs и GDB. В частности, проверьте команду po в gdb.
14. А Боб твой дядя.

Наслаждайтесь!

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