一、背景
作为一名iOS开发,日常我们基本天天跟iOS对象打交道,但是创建、释放、引用底层是如何实现的呢?估计很多初级开发工程甚至一些高级开发工程师都是云里雾里,这篇文档主要是介绍如何编译objc底层源码,然后如何调试这些源码,大家后续就可以一步步根据断点分析iOS源码流程。
二、objc818.2源码调试,请准备如下内容:
- macOS Big Sur 11.6
- Xcode 13.0
- Objc4-818.2 源代码 下载地址Objc4-818.2: opensource.apple.com/tarballs/ob…
三、编译objc,常见问题如下
解决:找不到 “'sys/reason.h' file not found”
第一步:在 opensource.apple.com/tarballs/xn… 下载 xnu-4903.241.1.tar.gz 在 xnu/bsd/sys 找到 reason.h 然后把找到的文件按照如下操作加入到工程里面:
- 在项目根目录创建了一个 GGZCommon 文件夹
- 在 GGZCommon文件夹内创建 sys 文件夹
- 把 reason.h 文件加入进去
第二步:设置检索路径
- 选择 target -> objc -> Build Settings
- 在 Header Serach Paths 中加入路径 $(SRCROOT)/GGZCommon (Debug和Release都要设置)
解决: “'mach-o/dyld_priv.h' file not found“
在Apple Source中找到“dyld-832.7.1 -> include -> mach-o -> dyld_priv.h”文件并下载,将mach-o/dyld_priv.h 加入 GGZCommon文件
解决: “dyld_priv.h:160:148: Expected ','”解决办法:将“bridgeos(3.0)”去掉。如下:
//将含有bridgeos(3.0)的代码注释
//extern dyld_platform_t dyld_get_base_platform(dyld_platform_t platform) __API_AVAILABLE(macos(10.14), iOS(12.0), watchos(5.0), tvos(12.0), bridgeos(3.0));
//修改后的代码
extern dyld_platform_t dyld_get_base_platform(dyld_platform_t platform) __API_AVAILABLE(macos(10.14), iOS(12.0), watchos(5.0), tvos(12.0));
解决: #include <pthread/tsd_private.h> 找不到
下载 libpthread-416.100.3将 pthread/tsd_private.h 拷贝到 GGZCommon/pthread 目录下
解决: #include<System/machine/cpu_capabilities.h>找不到
下载 libpthread-454.120.2 将 osfmk/machine/cpu_capabilities.h 拷贝到 GGZCommon/System/machine/ 目录下
解决: <pthread/spinlock_private.h> 找不到
下载 Libc-498 将 pthreads/spinlock_private 放入 GGZCommon/pthread 目录下
解决:include <CrashReporterClient.h>
还是一样 下载'CrashReporterClient.h文件, 这个在也在Libc中, 这里也是留意下Libc不能下最新的, 也是没有这个 CrashReporterClient.h文件, 在 Libc-825.26中
解决:#include <objc-shared-cache.h> 找不到
下载 dyld-832.7.1 2 将 pthreads/spinlock_private 放入 GGZCommon/pthread 目录下
解决:常见又熟悉的错误Use of undeclared identifier ‘CRGetCrashLogMessage’
- 那么根据该宏定义的前一步、如果定义了 LIBC_NO_LIBCRASHREPORTERCLIENT 才会走下边的宏定义符号
- 来到 Preprocessor Macros预编译处 定义这个变量
解决: os/linker_set.h 头文件找不到
解决方案:直接注释掉 objc-class.mm 文件的 #include <os/linker_set.h> 这一行即可
解决:Block_private.h 找不到
下载 libclosure-78 将 Block_private.h 放入 GGZCommon/ 目录下
解决:Cambria/Traps.h 和 Cambria/Cambria.h 头文件找不到
解决方案:直接注释掉 objc-cache.mm 文件的 #include <Cambria/Traps.h> 和 #include <Cambria/Cambria.h> 这两行即可
解决: #include <kern/restartable.h> 头文件找不到
下载 xnu-7195.50.7.100.1 将 osfmk/kern/restartable.h 放入 GGZCommon/kern 目录下
解决: LINKER_SET_FOREACH 报错
解决方案:直接注释掉 objc-class.mm 的 896 - 902 行
解决:"objc-cache.mm:1122:33: Use of undeclared identifier 'objc_thread_get_rip'”
直接注释即可
解决:os/reason_private.h 和 os/variant_private.h 头文件找不到
解决方案:直接注释掉 NSObject.mm 文件的 #include <os/reason_private.h> 和 #include<os/variant_private.h> 这两行即可。
解决:ld: can't open order file: /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk/AppleInternal/OrderFiles/libobjc.order clang: error: linker command failed with exit code 1 (use -v to see invocation)
解决方法: Build Settings->Linking->Order File -> Debug 改成$(SRCROOT)/libobjc.order
解决: ld: library not found for -lCrashReporterClient clang: error: linker command failed with exit code 1 (use -v to see invocation)
解决方法: 虽然我们添加了 CrashReporterClient 但还是在报错,所以直接删除引用。 在 TARGETS -> objc -> Build Settings -> Linking -> Other Linker Flags里删掉 Debug -> Any macOS SDK 和 Release -> Any macOS SDK 中的"-lCrashReporterClient"
删除之后如下
解决:SDK "macosx.internal" cannot be located.
解决 : 'os/feature_private.h' file not found
解决方案 : 直接注释掉 #include <os/feature_private.h> 这一行, 涉及以下两处代码文件;
解决:
Unknown type name 'uint32_t'、 Use of undeclared identifier 'INT64_C'
解决方案:在失败的文件添加如下代码
#include <stdint.h>
解决
Assertion failed: (sel_registerName(sel_getName(meth.name())) == meth.name()), function methodizeClass, file objc-runtime-new.mm, line 1536.
warning: could not find Objective-C class data in the process. This may reduce the quality of type information available.
(lldb)
解决方案: 原因系统升级到13.0及之上导致,需要用最新的objc源码才可以
四、objc源码调试步骤
- 新建Target MyTest
- 添加依赖
- 如果想断点调试 818.2 源码 需要做如下步骤
- 选择 Target MyTest + 运行,会正常出现断点到runtime源码里啦