查找iOS上每个外部库提供的大小

时间:2015-08-14 06:02:03

标签: ios xcode linker uikit

我试图减少我的应用商店二进制文件大小,我们有很多外部库可能会影响最终ipa的大小。有没有办法找出每个外部静态库在最终二进制文件中占用多少(除了去除每个外部静态库?)?

4 个答案:

答案 0 :(得分:19)

所有这些信息都包含在链接地图中,如果您有耐心筛选它(对于大型应用程序,它可能非常大)。链接映射包含所有库,其目标文件以及打包到应用程序中的所有符号的列表,所有这些都是人类可读的文本。通常情况下,项目没有配置为默认生成它们,因此您必须快速更改项目文件。

从Xcode内部:

  1. 在'构建设置'为您的目标,搜索" map"
  2. 在下面的结果中,在' Linking'部分,设置'写链接地图文件'到"是"
  3. 请务必记下“链接地图文件路径”下列出的完整路径和文件名。
  4. 下次构建应用时,您将获得转储到该文件路径的链接映射。请注意,路径相对于应用在DerivedData文件夹中的位置(通常为~/Library/Developer/Xcode/DerivedData/<your-app-name>-<random-string-of-letters-and-numbers>/Build/Intermediates/...,但为YMMV)。由于它只是一个文本文件,您可以使用任何文本编辑器阅读它。

    链接地图的内容分为3个部分,其中2个部分与您正在寻找的内容相关:

    1. 目标文件:此部分包含最终应用程序中包含的所有目标文件的列表,包括您自己的代码以及您包含的任何第三方库的代码。重要的是,每个目标文件还列出了它来自的库;
    2. 章节:此部分与您的问题无关,包含处理器细分及其各个部分的列表;
    3. 符号:此部分包含您感兴趣的原始数据:所有符号/方法的列表及其绝对位置(即处理器内存映射中的地址),大小和最重要的所有,对其包含对象模块的交叉引用(在&#39;文件&#39;列下)。
    4. 从这些原始数据中,您可以获得进行所需大小计算所需的一切。从#1开始,您会看到,对于每个库,都有N个可能的组成对象模块;从#2开始,你会看到,对于每个目标模块,都有M个可能的符号,每个符号占用大小S.对于任何给定的库,那么,粗略的大小顺序将类似于O(N * M * S)。这仅仅是为了向您提供实际计算中的组件的指示,它不是任何有用的公式。为了自己进行计算,我很遗憾地说我不知道​​任何现有的工具会为你做必要的处理,但鉴于链接映射只是一个文本文件,有一点点脚本魔法和独创性你可以构建一个脚本来完成繁重的工作。

      例如,我有一个示例项目链接到以下库:https://github.com/ColinEberhardt/LinqToObjectiveC(示例项目本身来自ReactiveCocoa的一个很好的教程,这里:http://www.raywenderlich.com/62699/reactivecocoa-tutorial-pt1),我想要知道它占据了多少空间。我已经生成了一个链接映射,TwitterInstant-LinkMap-normal-x86_64.txt(它在模拟器中运行)。为了找到库中包含的所有对象模块,我这样做:

      $ grep -i "libLinqToObjectiveC.a" TwitterInstant-LinkMap-normal-x86_64.txt
      

      给了我这个:

      [  8] /Users/Smyrl/Library/Developer/Xcode/DerivedData/TwitterInstant-ecppmzhbawtxkwctokwryodvgkur/Build/Products/Debug-iphonesimulator/libLinqToObjectiveC.a(LinqToObjectiveC-dummy.o)
      [  9] /Users/Smyrl/Library/Developer/Xcode/DerivedData/TwitterInstant-ecppmzhbawtxkwctokwryodvgkur/Build/Products/Debug-iphonesimulator/libLinqToObjectiveC.a(NSArray+LinqExtensions.o)
      [ 10] /Users/Smyrl/Library/Developer/Xcode/DerivedData/TwitterInstant-ecppmzhbawtxkwctokwryodvgkur/Build/Products/Debug-iphonesimulator/libLinqToObjectiveC.a(NSDictionary+LinqExtensions.o)
      

      第一列包含我需要的符号表的交叉引用,因此我可以搜索这些:

      $ cat TwitterInstant-LinkMap-normal-x86_64.txt | grep -e "\[  8\]"
      

      给了我:

      0x100087161 0x0000001B  [  8] literal string: PodsDummy_LinqToObjectiveC
      0x1000920B8 0x00000008  [  8] anon
      0x100093658 0x00000048  [  8] l_OBJC_METACLASS_RO_$_PodsDummy_LinqToObjectiveC
      0x1000936A0 0x00000048  [  8] l_OBJC_CLASS_RO_$_PodsDummy_LinqToObjectiveC
      0x10009F0A8 0x00000028  [  8] _OBJC_METACLASS_$_PodsDummy_LinqToObjectiveC
      0x10009F0D0 0x00000028  [  8] _OBJC_CLASS_$_PodsDummy_LinqToObjectiveC
      

      第二列包含所讨论符号的大小(十六进制),所以如果我将它们全部添加,我会得到0x103或259字节。

      更好的是,我可以做一些流黑客攻击,将其简化为必要元素并为我做补充:

      $ cat TwitterInstant-LinkMap-normal-x86_64.txt | grep -e "\[  8\]" | grep -e "0x" | awk '{print $2}' | xargs printf "%d\n" | paste -sd+ - | bc
      

      直接给我这个号码:

      259
      

      "\[ 9\]"(13016字节)和"\[ 10\]"(5503字节)执行相同操作,并将它们添加到之前的259字节,这给了我18778字节。

      你当然可以改进我在这里做的流黑客攻击,使其更加强大(在这个实现中,你必须确保你得到正确的空格数并引用括号),但是你至少得到了这个主意。

答案 1 :(得分:4)

制作应用的.ipa文件并将其保存在系统中。

然后打开终端并执行以下命令:

  

unzip -lv /path/to/your/app.ipa

它将返回有关.ipa文件的数据表。 size列具有.ipa文件中每个文件的压缩大小。

答案 2 :(得分:0)

我认为你应该能够从中提取所需的信息:

symbols -w -noSources YourFileHere

参考:https://devforums.apple.com/message/926442#926442

IIRC,它不会给你关于每个lib的明确的摘要信息,但是你应该发现每个库中的函数应该聚集在一起,所以通过一些努力,你可以计算每个lib的近似贡献:

答案 3 :(得分:0)

还要确保在构建设置中将“生成调试符号”设置为“否”。这可以将静态库的大小减少大约30%。

如果它是您关心的一部分,静态库只是存档在一起的相关.o文件加上一些簿记。因此,1.7mb静态库 - 即使其中的代码是整个1.7mb - 通常会为您的产品增加170mb。关于死代码剥离的通常规则将适用。

除此之外,您还可以减少代码的内置大小。以下可能不是一份全面的清单。

在目标的构建设置中查找“优化级别”&#39;。通过将其切换为最快,最小的-Os&#39;你允许编译器牺牲一些大小的速度。

确保您正在构建拇指,即更紧凑的ARM代码。假设您正在使用LLVM,这意味着确保您在项目设置中的任何位置都没有-mno-thumb。

还要考虑要构建哪些体系结构。 Apple不允许提交支持ARMv6和iPhone 5屏幕的应用程序,并完全放弃了最新Xcode的ARMv6支持。所以现在可能没有任何意义,包括此。