2016-10-15 17 views
1

NDK + Gradle + CMakeの統合が新しくなりました。リンクが意図したとおりにシンボルをエクスポートしない理由を理解しようとしています。Android NDK CMakeのリンクの問題

CMakeLists.txtで構築されたスタティックライブラリは、CMakeLists.txtではありません。

# main CMakeLists.txt 
add_subdirectory(${LIBS}/foo libs} 

add_library(native SHARED native.cpp) 
# omitting standard android libraries 
target_link_libraries(native foo ${android-lib} ${log-lib}) 

${libs}/foo内部CMakeLists.txtながら、以下の通りである:

スクリプト

は何かのように行います

# misc configuration of ${SRC} 
add_library(foo STATIC ${SRC}) 

スクリプトが正常に動作し、それがlibnative.soをリンクすることができますし、私は見つけることができますよ生成されたlibfoo.a。すべてがうまく見えます。

私はその後、FOOライブラリに含まれるfoo.cppでネイティブメソッドを定義しよう:

extern "C" JNIEXPORT void JNICALL Java_com_mypackage_Controls_onTap(JNIEnv*, jobject, int x, int y) { 
    // log something 
} 

しかし、私はFOOライブラリで定義されたネイティブメソッドを呼び出すことができませんよ。実行時にUnsatisfiedLinkErrorが表示されます。代わりに、メソッドをnative.cppに(直接コピーして貼り付けて)移動すれば、すべてうまく行きます。

だから、基本的には:> native.cppでの方法 - -

  • Javaの作品 FOOライブラリで定義されている>方法

    • のJava -
    • Javaの作品 native.cppで>方法fooライブラリの - >メソッドが機能しません(UnsatisfiedLinkError

    私はnmでエクスポート機能を検査しようとしたと私は

    00011060 T Java_com_mypackage_Controls_onTap 
    

    を見ることができるように、そのfoo.aが正しくネイティブ関数をエクスポートします。しかし、このエントリはlibnative.soから消えるように見えます。代わりにnative.cppに直接メソッドを定義すると、libnative.soのnmでも正しく表示できます。

    さらに、fooライブラリの任意のメソッドをnative.cppから呼び出すと、ライブラリが効果的に静的にリンクされます。

    私はこれの背後にある理由を理解することができませんが、アプローチはうまくいくはずです。可視性はJNIEXPORTマクロで指定されているように正確でなければなりません。だから私は暗闇の中で本当に頑張っています(そしてGradleはコンパイルフェーズでは何が起こっているのか理解できませんが、build.ninjaファイルは正しいようです)

  • +0

    は、あなたが ''セット(上CMAKE_VERBOSE_MAKEFILE)を追加しようとしたことがありますか?あなたの説明から、何がうまくいかないかを知るのは難しいです。シンボルがlibnative.soから削除されているか、libfoo.aのリンクが完全にスキップされています。 –

    +0

    libfoo.aの@AlexCohnリンクは、libnativeからlibfooのメソッドを呼び出すことができ、正しくリンクして動作するため、スキップされません。それはシンボルが剥奪されているか、外から目に見えないようにエクスポートされているようですが、私は強制的に-fvisibility = defaultを成功させようとしました。残念ながら、使用されたジェネレータはメイクファイルではありません。私は呼び出しコマンドを見ることができ、それは正しいようです。 soはnative.oとlibfoo.aを好きにして生成されます。私は実際に手がかりを得ていませんでした。 – Jack

    答えて

    2

    この動作は、不快であっても正しいです。リンカーは、共有ライブラリ内のいずれかのオブジェクト(「native.o」)に「固定」されていない限り、使用されている静的ライブラリからオブジェクト「ファイル」(場合によってはfoo.o) 。この問題を解決する3つの方法があります。

    1. 代わり 静的libにの libnative.soの一環としてfoo.cppをコンパイルします。 native.cpp

    2. foo.cppから参照Java_com_mypackage_Controls_onTapまたはその他の 外部シンボル

    3. 使用SET(native -Wl,--whole-archive foo -Wl,--no-whole-archive)https://stackoverflow.com/a/17477559/192373を参照)

    +0

    関連の発行(Android NDKは関係しません)への検索を続けていただき、私は同じ結論に達しました。 '--whole-archive'を使うと、この問題を解決する万能薬のように思えますが、特定のメソッドを「常にエクスポートする」、おそらく単に__attribute__を使ってマークする方法があるのだろうかと思っていました。盲目的にオブジェクトファイルの任意のシンボルをエクスポートします(最終的には1000のうちの10が使用されます)。 – Jack

    +0

    いいえ、リンカーオプション「シンボルを保持する必要がない場合でもシンボルa、b、qを保持する」はありません。しかし、(上記の* 2. *を参照)、そのようなオプションをシミュレートするのは簡単です。暗黙的なJNIバインディングから明示的な** RegisterNatives()**に切り替えると、これは自動的に取得されます。 –