基于clang插件的一种iOS包大小瘦身方案

本文介绍了一种使用Clang插件来分析iOS应用中未被最终调用的代码,以达到减少包体积的目的。通过插件分析,开发者可以识别并移除冗余代码,有效地降低APP的大小。

引子

\

包瘦身,包瘦身,包瘦身,重要的事情说三遍。 \

最近公司一款iOS APP(本文只讨论使用Objective C开发的iOS安装包)一直在瘦身,我们团队的APP也愈发庞大了。而要解决这个问题,思路主要集中在两个方向,资源和代码。资源主要在于图片,方法包括移除未被引用的图片,只使用一套图片(2x或3x),图片伸缩等;代码层面主要思路包括重构消除冗余,linkmap中selector引用分析等。除此之外,有没有别的路径呢? \

众所周知,代码之间存在调用关系。假设iOS APP的主入口为-[UIApplication main],则所有开发者的源代码(包括第三方库)可分为两类:存在一条调用路径,使得代码可以被主入口最终调用(称此类代码为被最终调用);不存在一条调用路径,使得代码最终不能被主入口调用(称此类代码为未被最终调用)。 \

假设有一个源代码级别的分析工具(或编译器),可以辅助分析代码间的调用关系,这样就使得分析最终被调用代码成为可能,剩下的就是未被最终调用的代码。 \

这种工具目前有成熟可用的吗?答案是肯定的,就是clang插件。除可用于分析未被最终调用代码外,clang还可辅助发现重复代码。 \

LLVM与clang插件

\

LLVM工程包含了一组模块化,可复用的编辑器和工具链。同其名字原意(Low Level Virtual Machine)不同的是,LLVM不是一个首字母缩写,而是工程的名字。目前LLVM包含的主要子项目包括: \

  1. LLVM Core:包含一个现在的源代码/目标设备无关的优化器,一集一个针对很多主流(甚至于一些非主流)的CPU的汇编代码生成支持。 \
  2. Clang:一个C/C++/Objective-C编译器,致力于提供令人惊讶的快速编译,极其有用的错误和警告信息,提供一个可用于构建很棒的源代码级别的工具. \
  3. dragonegg: gcc插件,可将GCC的优化和代码生成器替换为LLVM的相应工具。 \
  4. LLDB:基于LLVM提供的库和Clang构建的优秀的本地调试器。 \
  5. libc++、libc++ ABI: 符合标准的,高性能的C++标准库实现,以及对C++11的完整支持。 \
  6. compiler-rt:针对__fixunsdfdi和其他目标机器上没有一个核心IR(intermediate representation)对应的短原生指令序列时,提供高度调优过的底层代码生成支持。 \
  7. OpenMP: Clang中对多平台并行编程的runtime支持。 \
  8. vmkit:基于LLVM的Java和.NET虚拟机实 \
  9. polly: 支持高级别的循环和数据本地化优化支持的LLVM框架。 \
  10. libclc: OpenCL标准库的实现 \
  11. klee: 基于LLVM编译基础设施的符号化虚拟机 \
  12. SAFECode:内存安全的C/C++编译器 \
  13. lld: clang/llvm内置的链接器

作为LLVM提供的编译器前端,clang可将用户的源代码(C/C++/Objective-C)编译成语言/目标设备无关的IR(Intermediate Representation)实现。其可提供良好的插件支持,容许用户在编译时,运行额外的自定义动作。 \

我们的目标是使用clang插件减少包大小。其原理是,针对目标工程,基于clang的插件特性,开发者可以编写插件以分析所有源代码。编译过程中,将插件作为clang的参数载入并生成各种中间文件。编译完成后,还需编写一个工具去分析所有包含源码的方法(包括用户编写,以及引入的第三方库源代码),检查这些方法中哪些最终可被程序主入口调用,剩余即是疑似无用代码。简单的一个复查,移除那些确定无用的代码,重新编译,便可以有效去除无用的代码从而减少包大小。 \

本文相关内容如下: \

  1. 如何编写一个clang插件并集成到Xcode \
  2. 如何实现代码级别的包瘦身 \
  3. 局限与个性化定制 \
  4. 其他

如何编写一个clang插件并集成到Xcode

\

Clone clang源码并编译安装

cd /opt\sudo mkdir llvm\sudo chown `whoami` llvm\cd llvm\export LLVM_HOME=`pwd`\\git clone -b release_39 git@github.com:llvm-mirror/llvm.git llvm\git clone -b release_39 git@github.com:llvm-mirror/clang.git llvm/tools/clang\git clone -b release_39 git@github.com:llvm-mirror/clang-tools-extra.git llvm/tools/clang/tools/extra\git clone -b release_39 git@github.com:llvm-mirror/compiler-rt.git llvm/projects/compiler-rt\\mkdir llvm_build\cd llvm_build\cmake ../llvm -DCMAKE_BUILD_TYPE:STRING=Release\make -j`sysctl -n hw.logicalcpu`
\

编写clang插件

\

要实现自定义的clang插件(以C++ API为例),应按照以下步骤: \

  1. 自定义继承自 \

    clang::PluginASTAction(基于consumer的抽象语法树(Abstract Syntax Tree/AST)前端Action抽象基类) \

    clang::ASTConsumer(用于客户读取抽象语法树的抽象基类), \

    clang::RecursiveASTVisitor(前序或后续地深度优先搜索整个抽象语法树,并访问每一个节点的基类)等基类。

    \
  2. 根据自身需要重载 \

    PluginASTAction::CreateASTConsumer \

    PluginASTAction::ParseArgs \

    ASTConsumer::HandleTranslationUnit \

    RecursiveASTVisitor::VisitDecl \

    RecursiveASTVisitor::VisitStmt \

    等方法,实现自定义的分析逻辑。

    \
  3. 注册插件 \

    static FrontendPluginRegistry::Add\u0026lt;MyPlugin\u0026gt; X(\"my-plugin- name\

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值