当链接到共享库时,防止从静态库中删除函数?

时间:2010-08-23 16:10:02

标签: android java-native-interface

我有一个静态库Foo,由共享库Bar使用。 Bar是我的Android应用加载的本机共享库。 Foo包含仅由Java代码调用的JNI函数,而不是Bar中的任何C ++代码。因此,在构建共享库(Bar)时,这些JNI函数会从静态库(Foo)中删除。我目前正在使用一种稍微粗暴的方法来防止这种情况发生。

那么,在这种情况下,有没有办法告诉编译器在链接时不要删除JNI(或任何)函数?

2 个答案:

答案 0 :(得分:7)

他们没有被剥夺,他们被忽略了。链接共享库时,链接器仅使用实际使用的函数提取目标文件。 (这是静态库的定义方式。)

我相信将“--whole-archive”标志传递给链接器会导致它从静态库中提取所有目标文件。您可以在gcc链接行中使用“-Wl,-whole-archive”提供它。在指定库之后,您需要使用“-Wl,-no-whole-archive”跟随它,或者ld将继续执行它遇到的任何其他静态库的行为,这可能不是您想要的行为。另请参见Linux系统上的ld(1)手册页。

另一种完成相同操作的方法是输出单个大量.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添加标志可能会有所帮助。

答案 1 :(得分:6)

让我们从基本two-libs sample from 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)

您准确地解释了这个问题:链接器“剥离”了“未使用的”Java_com_example_twolibs_TwoLibs_add()条目。

现在让我们解决这个问题:

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

样本再次运作!