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

djc*_*uch 7 java-native-interface android

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

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

fad*_*den 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*
Run Code Online (Sandbox Code Playgroud)

(你必须在这里使用"/usr/lib/libz.a"而不是"-lz",因为后者找到共享库/usr/lib/libz.so.)

我没有多少使用NDK,但看起来像向LOCAL_LDFLAGS添加标志可能会有所帮助.


Ale*_*ohn 6

让我们从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)
Run Code Online (Sandbox Code Playgroud)

请注意,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 :=
Run Code Online (Sandbox Code Playgroud)

如果您运行修改后的项目,您将收到以下错误:

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)
Run Code Online (Sandbox Code Playgroud)

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

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

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

样本再次起作用!