4

状況は次のとおりです。

クライアントの Java プロジェクトを Eclipse で開いています。Xcode Objective C プロジェクトによって作成された JNI ライブラリを使用します。Java コードを実行するときに、Eclipse から C コードをデバッグする良い方法はありますか? 明らかに、Eclipse のデフォルトのデバッガーは jni ライブラリー・ファイルにステップインできず、スレッドが失われます (スレッドは、ここでは調査スレッドを意味し、プログラミング・スレッドではありません)。

コードベースが十分に大きいため、クライアントのコードをたどると他のオプションよりも大幅に高速になるため、アドバイスや入力を歓迎します。

ありがとう。

編集:

jni ライブラリが Objective-C で記述されているのは、Mac OSX と統合されているためです。Cocoa フレームワークを使用して、Apple の音声 API と統合しています。

4

4 に答える 4

5

私はあなたのセットアップを完全に理解しているかどうか、またこれを Eclipse から行う必要があるかどうかはわかりません。とにかく、obj-c/c コードのデバッグを試すためだけに、JNI と Cocoa ライブラリを使用して、何もしない小さなテスト プログラムを作成することに興味がありました。

このセットアップとコードのデバッグに成功しました。Java には IntelliJ を使用し、objc/c 部分には Xcode を使用しますが、Eclipse で Java 部分を実行するのは非常に簡単です。

したがって、プロジェクト構造を正確にセットアップして、デバッグを開始できるはずです。そこから、この知識を独自のより複雑なコードに適用できるはずです。

これが私が始めた方法です:

  • Cocoa Library を選択して、Xcode で新しいプロジェクトを作成します。

ココア図書館

  • プロジェクトに名前libnativeを付け、Type Dynamic にします。

オプションを選択

  • 新しいプロジェクトの場所を選択します。私はその部分を使用~/Development/してスキップしCreate local git...ます。

  • lib native.xcodeprojこれにより、選択したフォルダーに呼び出される新しいプロジェクトが作成されます。との 2 つのファイルが自動的に作成されましlibnative.hlibnative.m

  • まず、プロジェクト設定を変更する必要があります。

    • Executable Extensionセクションの を からに変更するPackaging必要があります。dynlibjnilib
    • Framework Search PathsSearch Pathsセクションの を更新して、JNI フレームワークを指すようにする必要があります。/System/Library/Frameworks/JavaVM.framework/Frameworks/JavaNativeFoundation.framework/

ここに画像の説明を入力

  • コードを追加します。このセットアップでは、 を使用する必要があることに注意してください<JavaVM/jni.h>libnative.mを次のコードのように更新します。

//
//  libnative.m
//  libnative
//
//  Created by maba on 2012-10-09.
//  Copyright (c) 2012 maba. All rights reserved.
//

#import "libnative.h"
#include <JavaVM/jni.h>

@implementation libnative

@end

#ifdef __cplusplus
extern "C" {
#endif

#ifndef VEC_LEN
#define VEC_LEN(v) (sizeof(v)/sizeof(v[0]))
#endif/*VEC_LEN*/

static JavaVM *javaVM;

static void print();

static JNINativeMethod Main_methods[] =
{
    { "print", "()V", (void*)print },
};

static struct {
    const char      *class_name;
    JNINativeMethod *methods;
    int             num_methods;
} native_methods[] = {
    { "com/stackoverflow/Main", Main_methods, VEC_LEN(Main_methods) },
};

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
    JNIEnv *env = 0;
    jclass cls  = 0;
    jint   rs   = 0;

    if ((*jvm)->GetEnv(jvm, (void**)&env, JNI_VERSION_1_4)) {
        return JNI_ERR;
    }

    javaVM = jvm;

    for (unsigned int i = 0; i < VEC_LEN(native_methods); i++) {
        cls = (*env)->FindClass(env, native_methods[i].class_name);
        if (cls == NULL) {
            return JNI_ERR;
        }
        rs = (*env)->RegisterNatives(env, cls, native_methods[i].methods, native_methods[i].num_methods);
        assert(rs == JNI_OK);
    }

    return JNI_VERSION_1_4;
}

static void print(JNIEnv *env, jclass cls) {
    printf("Hello from C");
}

#ifdef __cplusplus
}
#endif
  • を押してコードをビルドします⌘</kbd>+B.

  • それでは、Java コードを作成します。main という名前のクラスを package に作成しただけです com.stackoverflow

com.stackoverflow.Main.java

package com.stackoverflow;

/**
 * @author maba, 2012-10-09
 */
public class Main {

    static native void print();

    static {
        System.out.println(System.getProperty("java.library.path"));
        System.loadLibrary("native");
    }

    public static void main(String[] args) {
        System.out.println("Loading native");
        Main.print();
    }
}
  • の前の行にブレークポイントを設定しますMain.print();。次の JVM オプションを使用してデバッガーを開始します。

-Djava.library.path="/Users/maba/Library/Developer/Xcode/DerivedData/libnative-cquleqohzyhghnercyqdwpnznjdf/Build/Products/Debug/"

この行は少し長く、ユーザー固有でもあります。libnative-cquleqohzyhghnercyqdwpnznjdfディレクトリ名が何であるかを自分で探す必要がありますが、生成されたパスを除いて、それらは私のものとほぼ同じです。

  • プログラムが実行され、ブレークポイントで待機している必要があります。実行中のアプリケーションに Xcode デバッガーをアタッチする時間です。

  • メニューProduct->を選択し、ドロップダウンの一部で実行中のプロセスAttach to Process >をポイントします。複数のプロセスがある場合、PID が最も高いプロセスである可能性が最も高くなりますが、常にそうとは限りません。あなたは試してみる必要があります。javaSystemjava

  • 行の c コードにブレークポイントを作成しますprintf("Hello from C");

  • Java IDE に戻り、停止していたところから実行を続けます。

  • Xcode に戻り、ブレークポイントで待機していることを確認します。

ブレークポイントで


前に述べたように、これは obj-c/JNI に対する非常に単純なアプローチであり、プロジェクトはおそらく非常に大きいですが、この小さなテスト プロジェクトを使用すると、少なくともそれがどのように機能するかを確認してから、独自のプロジェクトのセットアップに進むことができます。

于 2012-10-09T21:34:13.003 に答える
1

ターミナルからgdb(または)でアタッチできる場合があります。lldbネイティブ コードを使用したプロセスの起動が a の結果であるfork()/exec()場合 (つまり、入力できない場合)gdb /some/command/lineは、--waitforオプション (man ページを参照) を使用して、inferior の起動を待つことができます。

シンボルをロードするのは難しいでしょう。


これは、cocoa フレームワークを使用した Mac OS X プロジェクトです。それはこれに影響しますか?

すべきではありません。どちらかといえば、うまくいけば、シンボルファイルが使用可能な形式であるという点で簡単になります。鍵となるのは通常、Java とネイティブ コードの間の境界でブレークする適切な場所を見つけることです。

JVM に読み込まれる dylib 内のネイティブ コードですか、それとも JVM を内部で起動するカスタム実行可能ファイルがありますか?

いずれにしても、そのネイティブ コードを実行しているプロセスにネイティブ デバッガーをアタッチする必要があります。おそらく、Java ベースのデバッグ セッションを適切に設定した後です。

于 2012-10-04T19:41:31.797 に答える
1

過去に JNI を行っていたとき、アプリケーションのネイティブ部分と JNI コードの開発を容易にするテスト ハーネスを作成しました。これは失敗しやすいことで有名で、両側から同時にデバッグする必要がありません。

これは、Java アプリケーションから開始してから JVM にアタッチしようとするのではなく、プログラムで JVM を呼び出すネイティブ アプリケーションとして作成されました。

もちろん、これを開始して Xcode でデバッグすることもできます。これは、CDT を使用した Eclipse よりもはるかに好ましいエクスペリエンスです。

この配置の Java 側は、通常は非常に単純で、不自然ではありません。基本的には、アプリのネイティブ部分から呼び出されるメソッドであり、JNI を介してネイティブ部分に 1 つまたは複数の呼び出しを戻します。

于 2012-10-08T14:24:21.823 に答える
0

WindowsでJNI(C / C ++)をデバッグするために私が従う手順は次のとおりです。ObjectiveCにも同じことが必要だと思います。Linuxの場合、これは非常に似ています(;を:、%XXX%を$ {XXX} ...に置き換えます)。

  1. MyDebug.gdbinitという名前のファイルを作成します
  2. 次の4行を追加します。

    setargs-classpath。;xxxx.jar;yyy.jar path.to.your.Main

    引数を表示

    走る

    bt

  3. gdbとJavaを起動します:gdb "%JAVA_HOME%\ bin \ java"

  4. JavaレイヤーのGUIを使用してエラーを再現します
  5. JNIコードを段階的に実行する場合、gdbではいくつかのブレークポイントを設定できます
于 2012-10-13T21:34:01.107 に答える