Code 是怎么变成 .ipa 包的

作为一名 iOS 开发工程师,“把代码变成.ipa的可安装到手机上的应用发生了什么”应该是要了解的。提出这么几个问题,去探索一下背后的原理。
这个过程做了什么?
程序员可以在这个过程中做什么?

第一个问题:做了什么
    1. Archive
    1. 打包 .ipa
Archive
  • 1.进行编译
  • 2.生成一个 DSYM 文件(存储了16进制的函数地址映射)
    奔溃日志中的地址通过此文件由地址映射到具体的函数位置。

Xcode 的编译器是由 Clang + LLVM 组成

编译器是做什么的?
编译器是用来把源代码文件转换为更为低级的语言的(同时还有语句的静态分析),而 xcode 使用的clang 编译器的作用就是把源代码转换为更为低级的 LLVM IR(Intermedia Representation),这个 LLVM IR 是操作系统无关的,然后 LLVM 通过这个中间语言来进行下一步的二进制文件的产出

  • Clang 编译器
    作为编译器前端,作用是:语法分析语义分析生成中间代码.在这个过程中,会进行类型检查,如果发现错误或者警告会标注出来在哪一行。

通过$ clang -ccc-print-phases <file name>.m观察单个文件的编译过程

1.预处理
2.编译生成IR(中间代码)
语法分析,语义分析(这个过程就是 Compiling)
3.汇编器生成汇编代码
4.生成机器码
5.链接
6.生成Image,也就是最后的可执行文件

预处理
会处理源文件中的宏定义,将代码中的宏用其对应定义的具体内容进行替换,展开头文件:

#import <Foundation/Foundation.h>
#define MY_CONSTANT 4
#ifdef DEBUG
//...
#else
//...
#endif

每次 ⌘B 发生的事情(使用cocoa pods)

  • 编译信息写入辅助文件,创建文件架构 .app 文件
  • 处理文件打包信息
  • 执行 CocoaPod 编译前脚本,checkPods Manifest.lock
  • 编译.m文件,使用 CompileC 和 clang 命令
  • 链接需要的 Framework
  • 编译 xib
  • 拷贝 xib ,资源文件
  • 编译 ImageAssets
  • 处理 info.plist
  • 执行 CocoaPod 脚本
    Run custom shell script 'Embed Pods Frameworks'
    Run custom shell script 'Copy Pods Resources'
  • 拷贝标准库
  • 创建 .app 文件和签名
clang是实际的编译命令
-x      objective-c 指定了编译的语言
-arch   x86_64制定了编译的架构,类似还有arm7等
-fobjc-arc 一些列-f开头的,指定了采用arc等信息。这个也就是为什么你可以对单独的一个.m文件采用非ARC编程。
-Wno-missing-field-initializers 一系列以-W开头的,指的是编译的警告选项,通过这些你可以定制化编译选项
-DDEBUG=1 一些列-D开头的,指的是预编译宏,通过这些宏可以实现条件编译
-iPhoneSimulator10.1.sdk 制定了编译采用的iOS SDK版本
-I 把编译信息写入指定的辅助文件
-F 链接所需要的Framework
-c ClassName.c 编译文件
-o ClassName.o 编译产物

可以通过 XCode的Link Map File 窥探二进制文件中的布局

设置为 YES
  • 在此目录下可以找到文件
~/Library/Developer/Xcode/DerivedData/<TARGET-NAME>-对应ID/Build/Intermediates/<TARGET-NAME>.build/Debug-iphoneos/<TARGET-NAME>.build/

文件内容包含 Object files,Sections,Symbols

  • Object files

这个部分的内容都是 .m 文件编译后的 .o 和需要 link 的 .a 文件。前面是文件编号,后面是文件路径。

  • Sections

这里描述的是每个 Section 在可执行文件中的位置和大小。每个 Section 的 Segment 的类型分为 __TEXT 代码段和 __DATA 数据段两种。

  • Symbols

Symbols 是对 Sections 进行了再划分。这里会描述所有的 methods,ivar 和字符串,及它们对应的地址,大小,文件编号信息。

第二个问题:程序员可以做什么

以 attribute(xx) 的语法格式出现,是 Clang 提供的一些能够让开发者在编译过程中参与一些源码控制的方法。下面列一些会用到的用法:

attribute((format(NSString, F, A))) 格式化字符串

- (void)preMethod:( NSString *)string __attribute__((deprecated("preMethod已经被弃用,请使用newMethod")));
- (void)deprecatedMethod DEPRECATED_ATTRIBUTE; //也可以直接使用DEPRECATED_ATTRIBUTE这个系统定义的宏
 //如果没有使用返回值,编译的时候给出警告
#define __unused_result  __attribute__ ((warn_unused_result)) 

//指定不能有子类
attribute((objc_subclassing_restricted)) 

//子类继承必须调用 super
attribute((objc_requires_super)) 

//带描述信息的弃用
#define __deprecated_msg(_msg) __attribute__((deprecated(_msg)))

//遇到__unavailable的变量/方法,编译器直接抛出Error
#define __unavailable   __attribute__((unavailable))

//告诉编译器,即使这个变量/方法 没被使用,也不要抛出警告
#define __unused    __attribute__((unused))

//和__unused相反
#define __used      __attribute__((used))

//如果不使用方法的返回值,进行警告
#define __result_use_check __attribute__((__warn_unused_result__))

//OC方法在Swift中不可用
#define __swift_unavailable(_msg)   __attribute__((__availability__(swift, unavailable, message=_msg)))

clang 警告处理

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundeclared-selector"
///代码
#pragma clang diagnostic pop

这段代码的作用是

对当前编译环境进行压栈
忽略-Wundeclared-selector(未声明的)Selector警告
编译代码
对编译环境进行出栈

通过clang diagnostic push/pop,你可以灵活的控制代码块的编译选项。

在 Xcode 的 Project editor 中的 Build Setting,Build Phases 和 Build Rules 能够控制编译的过程

Build Setting

  • 配合多个Target(右键Target,选择Duplicate),单独一个Target负责测试服务器。这样我们就不用每次切换测试服务器都要修改代码了
  • warnings是编码中很重要的一个环节,编译器给出合理的warning能帮助开发者找到自己代码的问题,防止很多bug产生。
    默认用XCode创建一个工程,会自动开启一些重要的warnings,但是更多的时候,我们需要编译器更完整的提醒
    默认的Warning可以在Build Settings里找到

    在search里搜索Warnings,就可以看到如图,这是为所有语言开启的warnings

当然,也可以为不同语言开启warning,也在Build Settings里
详情看这里

Build Phases
在 Compile Source 中指定所有必须编译的文件,这些文件会根据 Build Setting 和 Build Rules 里的设置来处理
在 Link Binary With Libraries 里会列出所有的静态库和动态库,它们会和编译生成的目标文件进行链接
build phase 还会把静态资源拷贝到 bundle 里
通过右上角的新增,可以添加自己的运行脚本。


Build Rules
指定不同文件类型如何编译。每条 build rule 指定了该类型如何处理以及输出在哪。可以增加一条新规则对特定文件类型添加处理方法

build 过程控制的这些设置都会被保存在工程文件 .pbxproj 里

提高项目编译速度

通过$ defaults write com.apple.dt.Xcode ShowBuildOperationDuration YES可以看到 Xcode 编译时间(首先要关闭 Xcode)

forward declaration
选择@class CLASSNAME,而不是#import CLASSNAME.h

预处理器对 #import 处理是用 CLASSNAME.h 文件中的内容去替换这行代码
 @class 是告诉编译器 CLASSNAME 是一个类,并且在 .m 实现文件中可以通过 import CLASSNAME.h 的方式来使用它。

对常用的工具类进行打包(Framework/.a)
打包成Framework或者静态库,这样编译的时候这部分代码就不需要重新编译了。

常用头文件放到预编译文件里
XCode的pch文件是预编译文件,这里的内容在执行XCode build之前就已经被预编译,并且引入到每一个.m文件里了。

二. 生成 .ipa
  • Mach-O文件
    是Mac和iOS可以执行文件的格式。进程就是系统根据该格式将执行文件加载到内存后得到的结果。系统通过解析文件建立依赖(动态库),初始化运行时环境,才能真正开始执行该App(进程)

参考文章:
https://segmentfault.com/a/1190000003101087
https://blog.csdn.net/Hello_Hwc/article/details/53557308
https://blog.csdn.net/forwardto9/article/details/51656274
https://juejin.im/post/5a352bb0f265da433562d5e3
https://blog.csdn.net/bjtufang/article/details/50628310
https://blog.csdn.net/vincentiss/article/details/54617915
https://objccn.io/issue-6-3/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270