2016-10-15 5 views
1

Ich bin ziemlich neu mit NDK + Gradle + CMake Integration und ich versuche zu verstehen, warum Verknüpfung nicht Symbole wie vorgesehen exportiert.Android NDK CMake Verknüpfung Probleme

Ich habe eine statische Bibliothek von einem CMakeLists.txt gebaut, die nicht die Haupt CMakeLists.txt ist.

Die Skripte tun so etwas wie:

# 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}) 

während CMakeLists.txt innerhalb ${libs}/foo ist die folgende:

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

Das Skript funktioniert gut, ist es in der Lage libnative.so zu verbinden, und ich bin in der Lage das finden generiert libfoo.a. Alles scheint in Ordnung zu sein.

Ich versuche dann eine native Methode in foo.cpp in foo Bibliothek enthalten sind, zu definieren: in foo Bibliothek definiert

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

Aber ich bin nicht in der Lage die native Methode aufzurufen. Ich bekomme eine UnsatisfiedLinkError zur Laufzeit. Wenn ich stattdessen (direkt durch Kopieren und Einfügen) die Methode in native.cpp verschiebe, dann ist alles in Ordnung.

Also im Grunde:

  • Java -> Methode in native.cpp
  • Java funktioniert -> Methode in native.cpp -> Methode in foo Bibliothek definiert arbeitet
  • Java -> methode in foo bibliothek funktioniert nicht (UnsatisfiedLinkError)

Ich habe versucht, die exportierten Funktionen mit nm zu inspizieren und es sieht so aus, dass foo.a korrekt die native Funktion exportiert, wie ich

00011060 T Java_com_mypackage_Controls_onTap 

Aber dieser Eintrag verschwindet aus libnative.so sehen kann. Wenn ich stattdessen die Methode direkt in native.cpp definiere, kann ich sie mit nm auch auf libnative.so richtig sehen.

Darüber hinaus Aufruf einer Methode in foo Bibliothek von native.cpp funktioniert wie vorgesehen, so dass die Bibliothek effektiv statisch verknüpft ist.

Ich bin nicht in der Lage, den Grund dafür zu verstehen, der Ansatz sollte in Ordnung sein, Sichtbarkeit sollte korrekt sein wie von JNIEXPORT Makro festgelegt, so dass ich wirklich im Dunkeln tappen (und Gradle bietet keine Ausgabe der Kompilation Phase, so kann ich nicht verstehen, was passiert, aber die build.ninja Datei scheint korrekt)

+0

Haben Sie versucht, 'set (CMAKE_VERBOSE_MAKEFILE auf)' hinzufügen? Aus Ihrer Erklärung ist es schwer zu sagen, was schiefgelaufen ist - entweder wird das Symbol von libnative.so entfernt, oder das Verknüpfen von libfoo.a wird insgesamt übersprungen. –

+0

@AlexCohn Verknüpfung von libfoo.a wird nicht übersprungen, wie ich eine Methode von libfoo von libnative aufrufen kann und es richtig verknüpft und funktioniert. Es scheint, als ob das Symbol von außen sichtbar entfernt oder nicht exportiert wird, aber ich habe versucht, -visibility = default ohne Erfolg zu erzwingen. Leider wird der verwendete Generator nicht gemacht, daher gibt es kein Makefile. Ich kann den Aufruf Befehl sehen und es scheint richtig. Das wird erzeugt, indem native.o und libfoo.a gemocht werden. Ich habe wirklich keine Hinweise .. – Jack

Antwort

2

Dieses Verhalten, auch wenn unangenehm, ist richtig. Der Linker löscht jedes Objekt "files" (in Ihrem Fall foo.o) aus gebrauchten statischen Bibliotheken, es sei denn, sie werden von einem der Objekte in der gemeinsam genutzten Bibliothek "angeheftet" (in Ihrem Fall native.o) .Es gibt drei Möglichkeiten, das Problem zu lösen:

  1. kompilieren foo.cpp als Teil libnative.so anstelle eines statischen lib.

  2. Referenz Java_com_mypackage_Controls_onTap oder andere externes Symbol von foo.cpp in native.cpp

  3. Verwendung SET(native -Wl,--whole-archive foo -Wl,--no-whole-archive) (siehe https://stackoverflow.com/a/17477559/192373)

+0

Danke, indem Sie mit den verwandten verwandten Themen (nicht mit Android NDK) halten, erreichte ich die gleiche Schlussfolgerung. Während die Verwendung von '--whole-archive' wie ein Allheilmittel erscheint, um dieses Problem zu lösen, frage ich mich, ob es eine Möglichkeit gibt, bestimmte Methoden als" immer exportieren "zu markieren, vielleicht durch ein" Attribut ", nur um die Dinge vernünftig zu halten Blindes Exportieren irgendeines Symbols einer Objektdatei (da am Ende vielleicht nur 10 von 1000 verwendet werden)? – Jack

+0

Nein, es gibt keine Linker-Option "behalte Symbole a, b und q, auch wenn niemand sie braucht". Aber (siehe * 2. * oben) ist es einfach, eine solche Option zu simulieren. Wenn Sie von impliziter JNI-Bindung zu expliziten ** RegisterNatives() ** wechseln, erhalten Sie dies automatisch. –