2010-08-23 15 views
7

Tengo una biblioteca estática, Foo, que es utilizada por una biblioteca compartida, Bar. Bar es la biblioteca compartida nativa cargada por mi aplicación de Android. Foo contiene funciones JNI que solo son llamadas por código Java y no por ningún código C++ en Bar. Debido a esto, esas funciones JNI se eliminan de la biblioteca estática (Foo) cuando se genera la biblioteca compartida (Bar). Actualmente estoy usando un método ligeramente hacky para evitar que eso suceda.¿Evita que se eliminen las funciones de una biblioteca estática cuando se vinculan a una biblioteca compartida?

Entonces, en este caso, ¿hay alguna manera de decirle al compilador que no quite las funciones JNI (o ninguna) al vincularlas?

Respuesta

7

No están siendo despojados, están siendo ignorados. Cuando la biblioteca compartida está vinculada, el vinculador solo está extrayendo los archivos del objeto con funciones que realmente se usan. (Así es como se definen las bibliotecas estáticas para que funcionen).

Creo que al pasar el indicador "--whole-archive" al enlazador hará que extraiga todos los archivos de objeto de una biblioteca estática. Puede proporcionarlo en la línea de enlace gcc con "-Wl, -whole-archive". Debe seguirlo con "-Wl, -no-whole-archive" después de especificar su biblioteca, o ld continuará el comportamiento para cualquier otra biblioteca estática que encuentre, que probablemente no sea el comportamiento que desea. Consulte también la página man de ld (1) en un sistema Linux.

Otra forma de lograr lo mismo es generar un único archivo .o masivo en lugar de un archivo .a.

EDIT: ejemplo simple de línea de comandos, utilizando libz en el escritorio:

% echo "int main() { return 0; }" > foo.c 
% gcc -o foo /usr/lib/libz.a foo.c 
% ls -s foo 
12 foo* 
% gcc -o foo -Wl,-whole-archive /usr/lib/libz.a -Wl,-no-whole-archive foo.c 
% ls -s foo 
104 foo* 

(Usted tiene que usar "/usr/lib/libz.a" en lugar de "-lz" aquí porque este último encuentra la biblioteca compartida /usr/lib/libz.so.)

No he usado mucho el NDK, pero parece que agregar las banderas a LOCAL_LDFLAGS podría hacer el truco.

+0

fadden - para el denso entre nosotros - ¿puedes publicar un ejemplo rápido de cómo necesitarías configurar el archivo Android.mk (al menos las dos líneas relacionadas con la vinculación)? – EboMike

6

Comencemos con el two-libs sample from NDK básico. Aquí está su archivo original de Android.mk:

1 # Copyright (C) 2009 The Android Open Source Project 
2 # 
3 # Licensed under the Apache License, Version 2.0 (the "License"); 
4 # you may not use this file except in compliance with the License. 
5 # You may obtain a copy of the License at 
6 # 
7 #  http://www.apache.org/licenses/LICENSE-2.0 
8 # 
9 # Unless required by applicable law or agreed to in writing, software 
10 # distributed under the License is distributed on an "AS IS" BASIS, 
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
12 # See the License for the specific language governing permissions and 
13 # limitations under the License. 
14 # 
15 
16 # the purpose of this sample is to demonstrate how one can 
17 # generate two distinct shared libraries and have them both 
18 # uploaded in 
19 # 
20 
21 LOCAL_PATH:= $(call my-dir) 
22 
23 # first lib, which will be built statically 
24 # 
25 include $(CLEAR_VARS) 
26 
27 LOCAL_MODULE := libtwolib-first 
28 LOCAL_SRC_FILES := first.c 
29 
30 include $(BUILD_STATIC_LIBRARY) 
31 
32 # second lib, which will depend on and include the first one 
33 # 
34 include $(CLEAR_VARS) 
35 
36 LOCAL_MODULE := libtwolib-second 
37 LOCAL_SRC_FILES := second.c 
38 
39 LOCAL_STATIC_LIBRARIES := libtwolib-first 
40 
41 include $(BUILD_SHARED_LIBRARY) 

Tenga en cuenta que la función JNI se encuentra en second.c que no forma parte de la biblioteca estática libtwolib-first.

Primero, permitanos reproducir su problema. El cambio es simple:

... 
27 LOCAL_MODULE := libtwolib-first 
28 LOCAL_SRC_FILES := first.c second.c 
... 
36 LOCAL_MODULE := libtwolib-second 
37 LOCAL_SRC_FILES := 

Si ejecuta el proyecto modificado, recibirá el siguiente error:

E/AndroidRuntime(4213): FATAL EXCEPTION: main 
E/AndroidRuntime(4213): java.lang.UnsatisfiedLinkError: add 
E/AndroidRuntime(4213):  at com.example.twolibs.TwoLibs.add(Native Method) 
E/AndroidRuntime(4213):  at com.example.twolibs.TwoLibs.onCreate(TwoLibs.java:39) 
E/AndroidRuntime(4213):  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047) 
E/AndroidRuntime(4213):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2627) 
E/AndroidRuntime(4213):  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2679) 
E/AndroidRuntime(4213):  at android.app.ActivityThread.access$2300(ActivityThread.java:125) 
E/AndroidRuntime(4213):  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2033) 
E/AndroidRuntime(4213):  at android.os.Handler.dispatchMessage(Handler.java:99) 
E/AndroidRuntime(4213):  at android.os.Looper.loop(Looper.java:123) 
E/AndroidRuntime(4213):  at android.app.ActivityThread.main(ActivityThread.java:4627) 
E/AndroidRuntime(4213):  at java.lang.reflect.Method.invokeNative(Native Method) 
E/AndroidRuntime(4213):  at java.lang.reflect.Method.invoke(Method.java:521) 
E/AndroidRuntime(4213):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:871) 
E/AndroidRuntime(4213):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:629) 
E/AndroidRuntime(4213):  at dalvik.system.NativeStart.main(Native Method) 

Explicaste este problema precisamente: el enlazador "despojado", el "sin usar" Java_com_example_twolibs_TwoLibs_add() entrada.

Ahora vamos a arreglar esto:

            
 
  
             39 LOCAL_STATIC_LIBRARIES := libtwolib-first
            
  
39 LOCAL_WHOLE_STATIC_LIBRARIES := libtwolib-first

Y de nuevo las obras de la muestra!

+1

¡Gracias! Eso era exactamente lo que necesitaba. –

Cuestiones relacionadas