Предотвращение удаления функций из статической библиотеки при подключении к общей библиотеке? - PullRequest
7 голосов
/ 23 августа 2010

У меня есть статическая библиотека Foo, которая используется общей библиотекой Bar. Bar - это встроенная общая библиотека, загружаемая моим приложением для Android. Foo содержит функции JNI, которые вызываются только кодом Java, а не кодом C ++ в Bar. Из-за этого эти функции JNI удаляются из статической библиотеки (Foo) при создании разделяемой библиотеки (Bar). В настоящее время я использую немного хакерский метод, чтобы предотвратить это.

Так, в этом случае, есть ли способ сказать компилятору не удалять функции JNI (или какие-либо другие) при компоновке?

Ответы [ 2 ]

7 голосов
/ 24 августа 2010

Их не раздевают, их игнорируют.Когда совместно используемая библиотека связана, компоновщик извлекает только объектные файлы с функциями, которые фактически используются.(Это то, как статические библиотеки определены для работы.)

Я считаю, что передача флага «--whole-archive» компоновщику заставит его извлекать все объектные файлы из статической библиотеки.Вы можете указать его в строке ссылки gcc с помощью "-Wl, -whole-archive".После указания вашей библиотеки вам нужно следовать с «-Wl, -no-whole-archive», иначе ld продолжит поведение любых других статических библиотек, с которыми сталкивается, что, скорее всего, не то поведение, которое вам нужно.См. Также справочную страницу ld (1) в системе Linux.

Другой способ сделать то же самое - вывести один массивный файл .o вместо файла .a.

РЕДАКТИРОВАТЬ: Простой пример командной строки с использованием libz на рабочем столе:

% 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*

(Вы должны использовать "/usr/lib/libz.a" вместо "-lz" здесьпотому что последний находит общую библиотеку /usr/lib/libz.so.)

Я не использовал NDK много, но похоже, что добавление флагов в LOCAL_LDFLAGS может помочь.

6 голосов
/ 09 сентября 2012

Давайте начнем с базового образца two-libs из NDK .Вот его оригинальный файл 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)

Обратите внимание, что функция JNI находится в second.c, который не является частью статической библиотеки libtwolib-first.

Сначала давайтенам воспроизвести вашу проблему.Изменение простое:

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

Если вы запустите измененный проект, вы получите следующую ошибку:

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)

Вы точно объяснили эту проблему: компоновщик "удалил"«unused» запись Java_com_example_twolibs_TwoLibs_add ().

Теперь давайте исправим это:

<strike>39 LOCAL_STATIC_LIBRARIES := libtwolib-first</strike>
39 LOCAL_WHOLE_STATIC_LIBRARIES := libtwolib-first

И снова образец работает!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...