- 关于objc4源码的编译、以后还会出新版、如果自己想最先常鲜、需要自己玩一遍、以后自己就学到手咯。
- “内容不重要 分析思维探索的角度”很重要!!!圈住了!
1、关于objc4源码问题
可在Cooci处下载编译完成的源码、
2、手动体验源码编译过程
苹果原版源码下载地址、
macOS 11.3系统下的objc4-824未下载下来、获取11.2系统下的 objc4-818.2版本
3、源码需要的部分系统文件
源码获取下来后将面临一系列各个系统库获取的头文件缺失的报错问题、根据750、781等版本编译问题可一并总结下来缺失的那些文件可为公共部分、具体差异可自行对比。主要从以下几个源文件获取、可尝试从0到1找寻:玩过几次就不想这么折腾了。
libpthread
xnu
Libc
dyld
libdispatch
libplatform
libclosure
- 最方便的就是直接获取开篇github上找好的对应版本的头文件、哈哈哈、每个版本略微有差异、需要找到最新的为好
4、获取818.2源码之后、如图添加头文件到项目并且配置搜索路径
- TARGETS - objc - Build Settings - Search Path 添加 ${SRCROOT}/include 路径
5、接下来开始解决报错之旅
1.常见的系统报错:unable to find sdk 'macosx.internal'
解决方法:
- 选择当前系统就可
- 此时此刻当选择TARGETS - objc时、顺手把二进制重排的libobjc.order的Order File路径给改为项目路径。否则后边有报错。因为Other为虚文件夹、所以libobjc.order在项目根目录下
- 最隐藏的地方在执行脚本的地方、当我们搜索不到一个执行符号时、要考虑脚本是否包含。由于开了上帝视角、所以晓得脚本这块也会有报错。
- 将macosx.internal 改为 macosx
2.‘os/feature_private.h’ file not found
- 注释掉这个头文件
- 同时 obj-runtime.mm文件中的 os_feature_enabled_simple调用注释掉
// if (!os_feature_enabled_simple(objc4, preoptimizedCaches, true)) {
// DisablePreoptCaches = true;
// }
- 找不着的头文件引用就都注释掉、private一般为私有文件。
- Use of undeclared identifier ‘dyld_fall_2020_os_versions’
//if (!dyld_program_sdk_at_least(dyld_fall_2020_os_versions))
// DisableAutoreleaseCoalescingLRU = true;
4.‘objc-bp-assist.h’ file not found
注释掉
5.Use of undeclared identifier ‘dyld_platform_version_macOS_10_13’
// if (!dyld_program_sdk_at_least(dyld_platform_version_macOS_10_13)) {
// DisableInitializeForkSafety = true;
// if (PrintInitializing) {
// _objc_inform("INITIALIZE: disabling +initialize fork "
// "safety enforcement because the app is "
// "too old.)");
// }
// }
6.Use of undeclared identifier ‘dyld_platform_version_macOS_10_11’
// if (!dyld_program_sdk_at_least(dyld_platform_version_macOS_10_11)) {
// DisableNonpointerIsa = true;
// if (PrintRawIsa) {
// _objc_inform("RAW ISA: disabling non-pointer isa because "
// "the app is too old.");
// }
// }
7.Use of undeclared identifier ‘dyld_fall_2018_os_versions’
- 删掉 && dyld_program_sdk_at_least(dyld_fall_2018_os_versions) 判断
8.常见又熟悉的错误Use of undeclared identifier ‘CRGetCrashLogMessage’
看出处在CrashReporterClient.h文件中。
- 那么根据该宏定义的前一步、如果定义了 LIBC_NO_LIBCRASHREPORTERCLIENT 才会走下边的宏定义符号
来到 Preprocessor Macros预编译处 定义这个变量
9.‘os/linker_set.h’ file not found
注释掉该头文件引用
//#if !TARGET_OS_WIN32
//#include <os/linker_set.h>
//#endif
注释掉调用代码
// LINKER_SET_FOREACH(_dupi, const objc_duplicate_class **, "__objc_dupclass") {
// const objc_duplicate_class *dupi = *_dupi;
//
// if (strcmp(dupi->name, name) == 0) {
// return;
// }
// }
10、‘Cambria/Traps.h’ file not found
#if TARGET_OS_OSX
//#include <Cambria/Traps.h>
//#include <Cambria/Cambria.h>
#endif
相对应的注释掉其中的调用代码、oah_is_current_process_translated、保留调用的线程执行处
// Find out where thread is executing
//#if TARGET_OS_OSX
// if (oah_is_current_process_translated()) {
// kern_return_t ret = objc_thread_get_rip(threads[count], (uint64_t*)&pc);
// if (ret != KERN_SUCCESS) {
// pc = PC_SENTINEL;
// }
// } else {
// pc = _get_pc_for_thread (threads[count]);
// }
//#else
pc = _get_pc_for_thread (threads[count]);
//#endif
11.LINKER_SET_FOREACH
12.Use of undeclared identifier ‘dyld_platform_version_bridgeOS_2_0’
老SDK的兼容代码
- 注释掉
// if (DebugPoolAllocation || sdkIsAtLeast(10_12, 10_0, 10_0, 3_0, 2_0)) {
// // OBJC_DEBUG_POOL_ALLOCATION or new SDK. Bad pop is fatal.
// _objc_fatal
// ("Invalid or prematurely-freed autorelease pool %p.", token);
// }
13.最后熟悉的 library not found 未找到符号、什么符号呢?
- -lCrashReporterClient
- 来到我们的Build Settings – Other Linker Flags、干掉它
14.library not found for -loah 同理、你懂我意思吧?看上一步:删除 -loah即可。
6、解决完上述的这么些问题、就Build Success !!! 熟悉么?
-
其实我想说的是、我们想要的是 objc 动态链接库、
-
看到Build Phases中依赖的另一个库为 objc-trampolines、所以其他无关的运行不了的、可以干掉。
-
objc-simulator也可以保留、因为依赖 objc。
-
删掉之后、别忘了删掉 Edit Scheme中的文件
-
Edit Scheme – Manage Schemes
-
这个时候想想看、是不是项目压缩存放起来小了点点。。。
7、这个时候创建个调试的Target
- 选中这个Target – 在Build Phases 中添加objc的依赖就OK了。
8.调试运行
- 创建个HSPerson类、在main.m中调用、调用处打上断点。
- Step into and you will find a new world~~~
- 跑进源码的小断点。
9、隐藏文件
- 我编译成功了、藏一下文件、你晓得么?
10、第四种探索手段LLDB调试要不要玩一下?
- 对alloc相关的函数下正则表达式断点、
- 方式一、不指定库文件、下完之后自行调试
`(lldb) breakpoint set --func-regex (.*)[a|A]llo[c|C](.*)
Breakpoint 2: 82902 locations.`
- 方式二、指定库文件、开启上帝视角、晓得objc对应的库文件为 libobjc.A.dylib
- 先清理掉之前下的断点、br list一看一堆、当然 br delete咯
(lldb) breakpoint set --func-regex (.*)[a|A]llo[c|C](.*) -s libobjc.A.dylib
Breakpoint 3: 515 locations.
libobjc.A.dylib was compiled with optimization - stepping may behave oddly; variables may not be available.
具体再精简下断点处、可根据具体所走方法总结正则表达式、有兴趣自行去玩、你学到了么?