OC底层 - objc4/818.2源码编译运行
一、开发环境
mac OS 10.15.7
Xcode Version 12.4 (12D4e)
源码下载地址
二、需要下载的库 点击进入查找下载

三、配置下载库文件
1.在objc4-818.2项目的根目录创建一个Common文件夹

2.Common文件夹里的结构如下:

3.Common文件内容相对下载的库文件
-
_simple.h = libplatform-254.60.1/private/_simple.h
-
Block_private.h = libclosure-78/Block_private.h
-
CrashReporterClient.h = Libc-825.24/include/CrashReporterClient.h
-
kern/restartable.h = xnu-7195.60.75/osfmk/kern/restartable.h
-
mach-o/dyld_priv.h = dyld-832.7.1/include/mach-o/dyld_priv.h
-
objc-shared-cache.h = dyld-832.7.1/include/objc-shared-cache.h
-
os/base_private = xnu-7195.60.75/libkern/os/base_private.h
-
os/lock_private = libplatform-254.60.1/private/os/lock_private.h
-
os/tsd = xnu-7195.60.75/libsyscall/os/tsd.h
-
pthread/spinlock_private.h = libpthread-454.60.1/private/pthread/spinlock_private.h
-
pthread/tsd_private = libpthread-454.60.1/private/pthread/tsd_private.h
-
sys/reason.h = xnu-7195.60.75/bsd/sys/reason.h
-
System/machine/cpu_capabilities.h = xnu-7195.60.75/osfmk/machine/cpu_capabilities.h
-
System/pthread_machdep.h = Libc-583/pthreads/pthread_machdep.h
四、编译前配置
-
将baseSDK 选择为 macOS


-
将 objc 下的脚本内 macosx.internal 改成 macosx

-
在Header Search Paths 添加 Common 的文件路径 (这里只添加Debug就可以了)

五、开始编译,解决报错
-
我们会遇到 bridgeos(3.0)和 bridgeos(4.0) 找不到的问题。
解决:因为Bridge OS是Apple独立的T2安全芯片使用的嵌入式操作系统, 而在这里我们用不到这个系统所以删掉,bridgeos(3.0)和,bridgeos(4.0)即可。 -
CrashReporterClient.h报错。
解决:在Build Settings -> Preprocessor Macros 中加入:LIBC_NO_LIBCRASHREPORTERCLIENT -
因为找不到头文件/宏/方法的地方,需要注释的代码如下:
(1) objc-runtime.mm#include <os/feature_private.h> if (!os_feature_enabled_simple(objc4, preoptimizedCaches, true)) { DisablePreoptCaches = true; } if (!dyld_program_sdk_at_least(dyld_fall_2020_os_versions)) DisableAutoreleaseCoalescingLRU = true;(2)objc-runtime-new.mm
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."); } } dyld_program_sdk_at_least(dyld_fall_2018_os_versions) STATIC_ASSERT((~ISA_MASK & MACH_VM_MAX_ADDRESS) == 0 || ISA_MASK + sizeof(void*) == MACH_VM_MAX_ADDRESS);(3)objc-oc.mm
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.)"); } }(4)objc-class.mm
#include <os/linker_set.h> LINKER_SET_FOREACH(_dupi, const objc_duplicate_class **, "__objc_dupclass") { const objc_duplicate_class *dupi = *_dupi; if (strcmp(dupi->name, name) == 0) { return; } }(5)objc-cache.mm
#include <Cambria/Traps.h> #include <Cambria/Cambria.h>(6)NSObject.mm
#include <os/feature_private.h> #include <os/reason_private.h> #include <os/variant_private.h> 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); }(7)pthread_machdep.h
inline static void * _pthread_getspecific_direct(unsigned long slot) { void *ret; #if defined(__i386__) || defined(__x86_64__) #if defined(__OPTIMIZE__) asm volatile("mov %%gs:%P1, %0" : "=r" (ret) : "i" (slot * sizeof(void *) + _PTHREAD_TSD_OFFSET)); #else asm("mov %%gs:%P2(,%1,%P3), %0" : "=r" (ret) : "r" (slot), "i" (_PTHREAD_TSD_OFFSET), "i" (sizeof (void *))); #endif #elif defined(__ppc__) void **__pthread_tsd; asm volatile("mfspr %0, 259" : "=r" (__pthread_tsd)); ret = __pthread_tsd[slot + (_PTHREAD_TSD_OFFSET / sizeof(void *))]; #elif defined(__ppc64__) register void **__pthread_tsd asm ("r13"); ret = __pthread_tsd[slot + (_PTHREAD_TSD_OFFSET / sizeof(void *))]; #elif defined(__arm__) && defined(_ARM_ARCH_6) void **__pthread_tsd; __asm__ ("mrc p15, 0, %0, c13, c0, 3" : "=r"(__pthread_tsd)); ret = __pthread_tsd[slot + (_PTHREAD_TSD_OFFSET / sizeof(void *))]; #elif defined(__arm__) && !defined(_ARM_ARCH_6) register void **__pthread_tsd asm ("r9"); ret = __pthread_tsd[slot + (_PTHREAD_TSD_OFFSET / sizeof(void *))]; #else #error no pthread_getspecific_direct implementation for this arch #endif return ret; }
六、libobjc.order 路径问题 (这个文件其实就是苹果用来对底层源码进行的二进制重排)
这里也可以直接把根目录的libobjc.order 拖进来

七、Other Linker Flags 中删除 -lCrashReporterClient 和 -loah
以上全部操作完毕,command+B 编译成功!
开始调试
新建一个 Target:MyTest
绑定二进制依赖关系

最后可能遇到的问题

上图所示,我加一个MyTextObjc的类,发现MyTextObjc内断点可以走到,但是main.m断点不走。
此时查看 Build Settings -> Enable Hardended Runtime 也设置的为NO。
最后发现必须在Complie Sources 中设置main.m为第一个加载的文件。就解决了,具体原因,我们在以后的编译原理中继续探索。