我有一个静态库Foo,由共享库Bar使用。 Bar是我的Android应用加载的本机共享库。 Foo包含仅由Java代码调用的JNI函数,而不是Bar中的任何C ++代码。因此,在构建共享库(Bar)时,这些JNI函数会从静态库(Foo)中删除。我目前正在使用一种稍微粗暴的方法来防止这种情况发生。
那么,在这种情况下,有没有办法告诉编译器在链接时不要删除JNI(或任何)函数?
答案 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-first39 LOCAL_WHOLE_STATIC_LIBRARIES := libtwolib-first
样本再次运作!