开篇
作为一名iOS程序员,探索OC底层原理永不止息,同时也是永远的痛,最开始只能靠猜测!后面慢慢找到了苹果官方开源的源码来辅助看一下,但是尽管这样,还是显得不太直观!如果objc源码能够像我们自己创建的项目一样直接编译调试,像我们自己的代码一样能够直接 LLDB 调试,流程跟踪,那简直不要太爽。废话不多说,开炮~ 哦,不是,是开干~!🚀
一、准备工作
苹果官方开源源码地址:
上面这两种方式,自行下载即可。我这里下载的是目前最新的objc4-818.2版本!
系统版本、开发工具、objc源码
- macOS Big Sur 11.1
- Xcode 12.5.1
- objc4-818.2
依赖文件
dyld-852.2 在 macOS 11.5 中
Libc-825.40.1 在 Mac OS X 10.8.5 中
Libc-1439.141.1 在 macOS 11.5 中
libclosure-79 在 macOS 11.3 ~ macOS 11.5 中
libplatform-254.80.2 在 macOS 11.2 ~ macOS 11.5 中
libplatform-220.100.1 在 macOS 10.15.4~macOS 10.15.6 中
libpthread-454.120.2 在 macOS 11.4~macOS 11.5 中
xnu-7195.141.2 在 macOS 11.5 中
以上是依赖源文件库的版本,可以到官方Open Source上去下载,如图:
也可以直接点击上面对应的文件名跳转到GitHub上,然后再下载,比如:dyld-852.2,GitHub结果如图:
注意:建议依赖的文件库最好去官方Open Source上去下载,这样可以帮助你了解官方网站的玩法,并且版本尽量下载最新版,在macOS新版本找不到对应的文件库就从之前的macOS版本去找
二、objc源码项目编译和遇到问题解决
下载好objc4-818.2的源码后,解压后打开objc.xcodeproj
然后选中objc这个target进行编译
注意:以下错误顺序不分先后,我只是按照我这边遇到错误的顺序依次解决,小伙伴们如果遇到问题对应不上的,可以往前或往后翻一翻,对照相应的错误进行解决
报错1:'unable to find sdk 'macosx.internal'
第一次编译会出现两个'unable to find sdk 'macosx.internal'的报错,objc 和 objc-trampolines 这两个target都有这个问题。
解决方式:
- 找到BuildSettings,分别设置 objc、objc-trampolines的Base SDK为macOS。
target -> objc -> BuildSettings -> Base SDK -> macOS target -> objc-trampolines -> BuildSettings -> Base SDK -> macOS
报错2:'sys/reason.h' file not found
再次运行,出现'sys/reason.h' file not found错误
这个reason.h文件在哪儿呢?这时候就需要用到我们前面下载的文件依赖库了。reason.h就在下载的文件库 xnu-7195.141.2/bsd/sys目录下。
解决方式:
- 在objc4-818.2工程的根目录下新建一个名为JQDependencies(文件名随便取)的文件夹,然后JQDependencies下创建子文件夹sys
- 将xnu-7195.141.2/bsd/sys目录下的reason.h文件copy到JQDependencies/sys/目录下
- 然后设置一下文件的搜索路径 Header Search Paths
报错3:'mach-o/dyld_priv.h' file not found
再次运行,会出现'mach-o/dyld_priv.h' file not found这个错误
这个报错和错误2是同样的道理,是缺少了dyld_priv.h这个文件,dyld_priv.h文件在在dyld-852.2/include/mach-o目录下
解决方式:
- 在JQDependencies目录下同样创建一个mach-o文件夹
- 将dyld_priv.h从dyld-852.2/include/mach-o目录下copy到JQDependencies/mach-o目录下
- 拷贝之后还需要在 dyld_priv.h 文件添加以下宏定义
#define DYLD_MACOSX_VERSION_10_11 0x000A0B00 #define DYLD_MACOSX_VERSION_10_12 0x000A0C00 #define DYLD_MACOSX_VERSION_10_13 0x000A0D00 #define DYLD_MACOSX_VERSION_10_14 0x000A0E00
然后在项目中点击# include 跳转到dyld_priv.h文件中,查看其中是否有 bridgeos(3.0) 的函数参数报错,如果有报错则删除bridgeos(3.0)参数。
报错4:'os/lock_private.h' file not found
再次编译运行,会出现'os/lock_private.h' file not found错误
同理,我们在依赖库中找到文件位置,创建对应文件路径并将目标文件copy到对应的路径下即可。lock_private.h文件在libplatform-254.80.2/private/os目录下
解决方式:
- 在JQDependencies目录下同样创建一个os文件夹
- 将lock_private.h从libplatform-254.80.2/private/os目录下copy到JQDependencies/os目录下
此处就不贴图了,按照报错2的方式去对应的路径下找文件即可。
报错5:'os/base_private.h' file not found
再次编译运行,会出现'os/base_private.h' file not found错误
同理,我们在依赖库中找到文件位置,创建对应文件路径并将目标文件copy到对应的路径下即可。base_private.h文件在libplatform-254.80.2/private/os目录下
解决方式:
- 将base_private.h从libplatform-254.80.2/private/os目录下copy到JQDependencies/os目录下
报错6:'pthread/tsd_private.h' file not found
再次编译运行,会出现 'pthread/tsd_private.h' file not found错误
同理,我们在依赖库中找到文件位置,创建对应文件路径并将目标文件copy到对应的路径下即可。tsd_private.h文件在libpthread-libpthread-454.120.2/private/pthread*目录下
解决方式:
- 在JQDependencies目录下同样创建一个pthread文件夹
- 将tsd_private.h从libpthread-libpthread-454.120.2/private/pthread目录下copy到JQDependencies/pthread目录下
报错7:'pthread/spinlock_private.h' file not found
同理,我们在依赖库中找到文件位置,创建对应文件路径并将目标文件copy到对应的路径下即可。spinlock_private.h文件也在libpthread-libpthread-454.120.2/private/pthread*目录下
解决方式:
- 将spinlock_private.h从libpthread-libpthread-454.120.2/private/pthread目录下copy到JQDependencies/pthread目录下
报错8:'System/machine/cpu_capabilities.h' file not found
同样是找到文件位置,cpu_capabilities.h文件在xnu-7195.141.2/osfmk/machine目录下
解决方式:
- 在JQDependencies目录下同样创建一个System/machine文件夹。
- 将cpu_capabilities.h从xnu-7195.141.2/osfmk/machine目录下copy到JQDependencies/System/machine/目录下
这里要注意的是:上面的文件丢失都是创建的单层文件夹,这里是System和machine两层文件夹,主要是看报错提示的路径,比
如:'System/machine/cpu_capabilities.h'需要的System/machine/两层