LOCAL_WHOLE_STATIC_LIBRARIES与LOCAL_STATIC_LIBRARIES的区别

在分析Jelly Bean Audio Subsystem的时候,发现HAL层的库audio_policy.xxx.so与其依赖的静态库libaudiopolicy_legacy.a都有audio_policy_hal.cpp这个源文件而且两者都定义了一个HMI。当调用者引用HMI的时候,调用的究竟是哪个呢?

首先看audio_policy.xxx.so的Android.mk文件,在定义编译audio_policy.xxx.so的段落里面有这么一句:

LOCAL_STATIC_LIBRARIES := \
     libaudiohw_legacy \
     libmedia_helper \
     libaudiopolicy_legacy

说明libaudiopolicy_legacy是以静态库的形式为audio_policy.xxx.so所用,而在通用的audio_policy库(也可以说是谷歌提供给厂商参考用的policy库)audio_policy.default.so的库里面是这么用的:

LOCAL_WHOLE_STATIC_LIBRARIES := \
    libaudiopolicy_legacy

而audio_policy.default.so的源码里面就没有audio_policy_hal.cpp这个源文件,所以玄机应该就在LOCAL_WHOLE_STATIC_LIBRARIES和LOCAL_STATIC_LIBRARIES这两个宏的差异上面。先看下谷歌在build/core/build-system.html里面是怎么说的:

LOCAL_STATIC_LIBRARIES

These are the static libraries that you want to include in your module. Mostly, we use shared libraries, but there are a couple of places, like executables in sbin and host executables where we use static libraries instead.

LOCAL_WHOLE_STATIC_LIBRARIES

These are the static libraries that you want to include in your module without allowing the linker to remove dead code from them. This is mostly useful if you want to add a static library to a shared library and have the static library‘s content exposed from the shared library.

总的来说LOCAL_WHOLE_STATIC_LIBRARIES在连接静态连接库的时候不会移除"daed code",何谓dead code呢,就是调用者模块永远都不会用到的代码段和变量,下面用几个小源码来说明。

Android.mk如下

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

LOCAL_SRC_FILES :=     libstone_1.cpp

LOCAL_MODULE := libstone_1
LOCAL_MODULE_TAGS := optional

include $(BUILD_STATIC_LIBRARY)

# =========================================
include $(CLEAR_VARS)

LOCAL_SRC_FILES :=     libstone_2.cpp

LOCAL_STATIC_LIBRARIES := libstone_1
#<span style="color:#ff0000;"> LOCAL_WHOLE_STATIC_LIBRARIES := libstone_1</span>
LOCAL_MODULE := libstone_2
LOCAL_MODULE_TAGS := optional

include $(BUILD_SHARED_LIBRARY)

静态库源文件(libstone_1.cpp):

char hello[] = "this is a string in libstone_1";
char str_2[] = "non static string 1";
char str_3[] = "non static string 2";
void func_1(){hello[0]+=1;}

调用者源文件(libstone_2.cpp):

char hello[] = "this is a string in libstone_2";

case 1,按照上述的代码make之后,libstone_1的所有东西都没有被连接到动态库libstone_2里面:

readelf -Ws system/lib/libstone_2.so 
Symbol table ‘.dynsym‘ contains 11 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 00002000    31 OBJECT  GLOBAL DEFAULT   13 hello2
     2: 000002e8    12 FUNC    GLOBAL DEFAULT    7 __on_dlclose
     3: 00000000     0 FUNC    GLOBAL DEFAULT  UND __cxa_finalize
     4: 00000000     0 FUNC    GLOBAL DEFAULT  UND __aeabi_unwind_cpp_pr0
     5: 00002020     0 NOTYPE  GLOBAL DEFAULT   14 __dso_handle
     6: 00001ee4     0 NOTYPE  GLOBAL DEFAULT    9 __INIT_ARRAY__
     7: 00001eec     0 NOTYPE  GLOBAL DEFAULT   10 __FINI_ARRAY__
     8: 0000201f     0 NOTYPE  GLOBAL DEFAULT  ABS _edata
     9: 0000201f     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start
    10: 00002030     0 NOTYPE  GLOBAL DEFAULT  ABS _end

case 2,修改Android.mk使用LOCAL_WHOLE_STATIC_LIBRARIES 宏,这个时候libstone_2.cpp中的hello要改成hello2,因为libstone_1里面的东西全部链接进来了:

readelf -Ws system/lib/libstone_2.so 
Symbol table ‘.dynsym‘ contains 16 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 0000037d    20 FUNC    GLOBAL DEFAULT    7 _Z6func_3v
     2: 0000201f    31 OBJECT  GLOBAL DEFAULT   13 hello
     3: 00000000     0 FUNC    GLOBAL DEFAULT  UND __aeabi_unwind_cpp_pr0
     4: 00002000    31 OBJECT  GLOBAL DEFAULT   13 hello2
     5: 00000390    12 FUNC    GLOBAL DEFAULT    7 __on_dlclose
     6: 00000000     0 FUNC    GLOBAL DEFAULT  UND __cxa_finalize
     7: 00002070     0 NOTYPE  GLOBAL DEFAULT   14 __dso_handle
     8: 00001ee0     0 NOTYPE  GLOBAL DEFAULT    9 __INIT_ARRAY__
     9: 00001ee8     0 NOTYPE  GLOBAL DEFAULT   10 __FINI_ARRAY__
    10: 000003a1    16 FUNC    GLOBAL DEFAULT    7 _Z6func_1v
    11: 00002052    20 OBJECT  GLOBAL DEFAULT   13 str_3
    12: 0000203e    20 OBJECT  GLOBAL DEFAULT   13 str_2
    13: 00002066     0 NOTYPE  GLOBAL DEFAULT  ABS _edata
    14: 00002066     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start
    15: 00002080     0 NOTYPE  GLOBAL DEFAULT  ABS _end

case 2,仍使用LOCAL_STATIC_LIBRARIES宏,libstone_2.cpp的代码修改为:

char hello2[] = "this is a string in libstone_2";

extern char str_2[];

void func_3(){str_2[0]+=1;}

这个时候readelf的结果是:

readelf -Ws system/lib/libstone_2.so 
Symbol table ‘.dynsym‘ contains 16 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 0000037d    20 FUNC    GLOBAL DEFAULT    7 _Z6func_3v
     2: 0000201f    31 OBJECT  GLOBAL DEFAULT   13 hello
     3: 00000000     0 FUNC    GLOBAL DEFAULT  UND __aeabi_unwind_cpp_pr0
     4: 00002000    31 OBJECT  GLOBAL DEFAULT   13 hello2
     5: 00000390    12 FUNC    GLOBAL DEFAULT    7 __on_dlclose
     6: 00000000     0 FUNC    GLOBAL DEFAULT  UND __cxa_finalize
     7: 00002070     0 NOTYPE  GLOBAL DEFAULT   14 __dso_handle
     8: 00001ee0     0 NOTYPE  GLOBAL DEFAULT    9 __INIT_ARRAY__
     9: 00001ee8     0 NOTYPE  GLOBAL DEFAULT   10 __FINI_ARRAY__
    10: 000003a1    16 FUNC    GLOBAL DEFAULT    7 _Z6func_1v
    11: 00002052    20 OBJECT  GLOBAL DEFAULT   13 str_3
    12: 0000203e    20 OBJECT  GLOBAL DEFAULT   13 str_2
    13: 00002066     0 NOTYPE  GLOBAL DEFAULT  ABS _edata
    14: 00002066     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start
    15: 00002080     0 NOTYPE  GLOBAL DEFAULT  ABS _end
可以看到,不仅仅是被引用到的str_2,所有在libstone_1中的global变量都被链接到libstone_2中。

所以可以得到如下的结论:

是否链接到调用者模块 使用了静态库的global变量 不使用
LOCAL_STATIC_LIBRARIES  Y N
LOCAL_WHOLE_STATIC_LIBRARIES  Y Y

至于android的编译系统是怎么处理这两个宏的,在./build目录发现其实使用了gcc的参数来区分(in core/definitions.mk ):

1161         -Wl,--whole-archive \
1162         $(call normalize-host-libraries,$(PRIVATE_ALL_WHOLE_STATIC_LIBRARIES)) \
1163         -Wl,--no-whole-archive \
1164         $(if $(PRIVATE_GROUP_STATIC_LIBRARIES),-Wl$(comma)--start-group) \

综上所述,audio_policy.xxx.so这个policy库使用的是自己的audio_policy_hal.cpp源文件。

原文地址:http://blog.csdn.net/darkengine/article/details/9720131#

LOCAL_WHOLE_STATIC_LIBRARIES与LOCAL_STATIC_LIBRARIES的区别

时间: 2024-08-29 23:35:27

LOCAL_WHOLE_STATIC_LIBRARIES与LOCAL_STATIC_LIBRARIES的区别的相关文章

Android NDK编程浅入深出之--Android.mk

    Android.mk Android.mk是一个向Android NDK构建系统描述NDK项目的GUN Makefile片段.它是每一个NDK项目的必备组件.构建系统希望它出现在jni子目录中.下面是hello-jni项目中Android.mk文件的内容. # Copyright (C) 2009 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License

自己编写库模块,Win&Android联调总结二

libGameNet模块Win&Android联调总结二 作者:Jack(JCracker) 邮箱:[email protected] 作者很赖还是不想上传图片 需要图片和配置实例的来这里下载:下载 Application.mk 废弃不用 因为这里是打包成库 Android.mk: #LOCAL_PATH := $(call my-dir) LOCAL_PATH := E:\ylss\project\NewStartDemo\NetworkDemo\NetworkDemo include $(C

Nginx 反代参数:$X-Real-Ip和$X-Forwarded-For的区别

## \$X-Real-Ip和$X-Forwarded-For的区别 标签(空格分隔): nignx 负载均衡 client-ip --- ####1.如果只有一层代理,这两个头的值就是一样的####2.多层代理> * X-Forwarded-For:  header包含这样一行        `*X-Forwarded-For: 1.1.1.1, 2.2.2.2, 3.3.3.3*`> * X-Real-Ip:没有相关标准,上面的例子,如果配置了X-Read-IP,可能会有两种情况`// 最

C#中Convert和parse的区别

Convert.ToInt32()与int.Parse()的区别(1)这两个方法的最大不同是它们对null值的处理方法: Convert.ToInt32(null)会返回0而不会产生任何异常,但int.Parse(null)则会产生异常. 没搞清楚Convert.ToInt32和int.Parse()的细细微区别时千万别乱用,否则可能会产生无法预料的结果,举例来说:假如从url中取一个参数page的值,我们知道这个值是一个int,所以即可以用Convert.ToInt32(Request.Que

python判断字符串,str函数isdigit、isdecimal、isnumeric的区别

s为字符串s.isalnum() 所有字符都是数字或者字母s.isalpha() 所有字符都是字母s.isdigit() 所有字符都是数字s.islower() 所有字符都是小写s.isupper() 所有字符都是大写s.istitle() 所有单词都是首字母大写,像标题s.isspace() 所有字符都是空白字符.\t.\n.\r 判断是整数还是浮点数a=123b=123.123 >>>isinstance(a,int)True>>>isinstance(b,floa

java web 过滤器跟拦截器的区别和使用

1.首先要明确什么是拦截器.什么是过滤器 1.1 什么是拦截器: 拦截器,在AOP(Aspect-Oriented Programming)中用于在某个方法或字段被访问之前,进行拦截然后在之前或之后加入某些操作.拦截是AOP的一种实现策略. 在Webwork的中文文档的解释为--拦截器是动态拦截Action调用的对象.它提供了一种机制可以使开发者可以定义在一个action执行的前后执行的代码,也可以在一个action执行前阻止其执行.同时也是提供了一种可以提取action中可重用的部分的方式.

mysql中int、bigint、smallint和tinyint的区别与长度

对比发现 int bigint smallint 和 tinyint 类型,如果创建新表时没有指定 int(M) 中的M时,默认分别是 : int             -------     int(11) bigint       -------     bigint(20) smallint   -------     smallint(6) tinyint     -------     tinyint(4) 下面是这几种类型的取值范围 参考:http://www.2cto.com/d

call和apply和bind的区别

在 javascript 中,call 和 apply 都是为了改变某个函数运行时的上下文(context)而存在的,换句话说,就是为了改变函数体内部 this 的指向. JavaScript 的一大特点是,函数存在「定义时上下文」和「运行时上下文」以及「上下文是可以改变的」. apply(): 将函数作为指定对象的方法来调用,传递给它的是指定的参数数组function.apply(thisobj, args) 或者 function.apply(thisobj, args) 1.thisobj

mybatis中&quot;#&quot;和&quot;$&quot;的区别

mybatis中"#"和"$"的区别 动态 sql 是 mybatis 的主要特性之一,在 mapper 中定义的参数传到 xml 中之后,在查询之前 mybatis 会对其进行动态解析.mybatis 为我们提供了两种支持动态 sql 的语法:#{} 以及 ${}. 在下面的语句中,如果 username 的值为 zhangsan,则两种方式无任何区别: select * from user where name = #{name}; select * from