链接到共享库时防止将函数从静态库中剥离?

我有一个静态库Foo,由共享库Bar使用。 Bar是我的Android应用程序加载的本地共享库。 Foo包含仅由Java代码调用的JNI函数,而不是Bar中的任何C ++代码。 正因为如此,当共享库(Bar)被构build时,这些JNI函数会从静态库(Foo)中剥离出来。 我目前正在使用一个稍微黑客的方法来防止发生。

那么,在这种情况下,是否有办法告诉编译器在链接时不去掉JNI(或任何)函数?

Solutions Collecting From Web of "链接到共享库时防止将函数从静态库中剥离?"

他们没有被剥夺,他们被忽略。 当共享库被链接时,链接器只用实际使用的函数来提取目标文件。 (这是如何定义静态库的工作。)

我相信将“–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”,因为后者find共享库/usr/lib/libz.so。)

我还没有使用过NDK,但是看起来像在LOCAL_LDFLAGS中添加标志可能会起到一些作用。

我们从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 

样品再次运作!