今日头条丨一点资讯丨腾讯丨搜狐丨网易丨凤凰丨阿里UC大鱼丨新浪微博丨新浪看点丨百度百家丨博客中国丨趣头条丨腾讯云·云+社区
zsource 命令是什么?
美团App在2015年就已经基于CocoaPods完成了组件化的工作。在组件化的改造过程中,为了能够加速整体工程的构建速度,我们对需要集成进美团App的组件进行了二进制化,同时提供一个叫做cocoapods-binary的CocoaPods插件来支持本地工程使用二进制。因此,美团App的开发者在集成开发时,除了自己正在开发的组件,其他的组件都以二进制的形式存在。
使用二进制,虽然会给工程带来构建速度的提升,但是会带来一个新的问题:在调试工程时,那些使用二进制的组件,无法像源码调试那样看到足够丰富的调试信息。例如,如果程序在二进制组件的代码中崩溃,我们只能看到该组件的堆栈信息和一些不明所以的汇编代码:
和业界大多的组件化方案类似,美团App的组件化方案也提供了将一个组件从二进制切换到源码的机制。美团工程的开发者能够使用一系列配置和命令来切换组件的源码和二进制状态,但每次切换都需要重新执行pod install
。这种方式在组件化初期没有什么问题,但随着美团App组件数量不断增长,即便是只切换一个组件的状态,单次pod install
的时间也增长到了分钟级。而且这种方式每切换一次就必须重新编译运行一次App,在追查一些偶现崩溃问题时,开发体验非常不友好,也不利于崩溃问题的快速定位分析。为了解决以上提到的这些问题,我们利用CocoaPods的插件机制,为CocoaPods的pod
命令增加了zsource
子命令,开发者可以在使用二进制构建工程的同时,非常快速地将一个组件调出源码进行调试,具体的使用效果可以看一下如下的屏幕录制:
zsource 命令的开发始末
在推出zsource功能后,很多同学都对zsource背后的技术原理十分感兴趣。其实zsource整个功能的开发流程也十分有趣,就像小说一样,分为几个不同的时期:
原理猜想
如果让我们猜想Xcode断点调试功能的实现原理,可能大部分人都会猜这样一种可能:Xcode在编译Debug版本的二进制过程中,在二进制中某个字段存储了该二进制所对应的源码的文件地址。当我们在Xcode中打断点进行调试的时候,Xcode会根据二进制中这个字段中存储的源码文件地址,打开对应的源码文件,并在UI上展示该源码文件。
道理好像没有什么问题,但是事实是这样吗?在某次团建回国的航班上,我们组两位同学在提出这种猜想后,拿出电脑,做了一个这样的小实验:
实验中,他们分别创建了两个Xcode工程A和B,工程A会产出一个二进制libA.a。工程B会直接将A的产出libA.a 拖到工程中,然后设置A中代码的符号断点,编译运行。结果发现,当断点断在A中的代码时,Xcode会直接跳转到A的源文件中,并且可以继续增加断点以及正常的单步调试。
通过这个实验,我们确定了猜想是正确的。那么接下来需要做的就是确定二进制中,这个源文件地址信息具体藏在哪一个字段中。
查阅资料
我们都知道苹果的Mach-O二进制文件是使用DWARF这种格式来存放调试相关的数据,但因为我们很难从这个问题中提炼几个精确的关键词在搜索引擎中检索,所以很难通过简单的几次检索就获取到我们想要的答案:二进制这个字段的名称,在初期甚至无法确定这个字段应该是从Mach-O的资料中检索还是从DWARF的资料中检索。
在没有太好的搜索结果的情况下,我们就想尝试从头去啃一啃文档。于是,找到了如下的一些二进制相关文档: