原文连接html
Runtime,也就是所谓的运行时,是Objective-C语言一个很是重要的特性。了解Runtime,对理解Objective-C这门语言有很大的帮助。苹果官方提供的有Runtime源码,不幸的是官方提供的源码是不能编译运行的。若是有一个能够编译运行的Runtime源码,咱们就能够打断点调试,这对于理解Runtime机制,理解Runtime源码是大有裨益的。所以,这篇文章介绍下如何编译官方提供的Runtime源码。git
因为编译Runtime源码步骤比较多,我在github上放了能够直接编译运行、调试的Runtime源码,你们能够从这里下载。不过建议仍是亲自动手编译一遍。github
Runtime源码能够从苹果开源代码网站下载。在该页面搜索objc,找到最新的objc4下载便可。macos
下载好Runtime源码以后,就能够开始编译Runtime源码了。编译过程当中会遇到不少错误信息,这篇文章主要是我在编译过程当中遇到的错误信息以及解决方案,若是你们没有遇到对应的错误信息,直接跳过便可。api
下载后的Runtime源码目录结构以下图:xcode
双击打开objc.xcodeproj,编译运行便可。bash
Xcode打开以后以下图:架构
咱们的目的就是编译出Products目录下的libobjc.A.dylib。app
编译Runtime源码,遇到的第一个错误信息是i386架构被废弃。ide
错误信息以下:
The i386 architecture is deprecated. You should update your ARCHS build setting to remove the i386 architecture. (in target 'objc')
复制代码
The i386 architecture is deprecated. You should update your ARCHS build setting to remove the i386 architecture. (in target 'objc-trampolines')
复制代码
target分别是objc和objc-trampolines,意思是i386架构已经被废弃了,须要移出i386架构。
解决方案就是移出对应的i386架构。
进入"TARGETS->objc-trampolines->Architecture",将Debug中的 (ARCHS_STANDARD),以下图:
同理,对应的TARGETS objc也是作一样的操做,只不过是在TARGETS下面选择objc,所修改的内容是同样的。
在编译过程当中,会提示缺乏不少头文件,咱们要作的就是加入这些头文件。我把须要用到的头文件作了个整理,能够从这里下载。
错误信息以下:
sys/reason.h file not found
复制代码
sys是文件夹,reason.h是文件名。
解决方案就是按照Xcode给的错误提示信息,新建对应的文件夹和头文件。
由于缺乏的头文件比较多,为了方便,咱们在工程目录下首先新建一个文件夹CommonHeaders,所缺乏的文件能够所有放倒该目录下。新建好CommonHeaders以后以下图:
为了让Xcode能找到咱们添加的头文件,须要将CommonHeaders添加到Header Search Paths中,步骤:"TARGETS->objc->Build Settings",搜索header search,加入$(SRCROOT)/CommonHeaders,DEBUG和RELEASE都要添加。以下图:
在CommonHeaders下新建sys文件夹,而且从刚才下载的头文件中找到reason.h,放到sys文件夹下。编译,对应的错误信息应该就没有了。
除了reason.h,还会提示缺乏一些其余的头文件,解决方案是同样的,只是在CommonHeaders下新建不一样的文件夹和拷贝不一样的文件。提示的错误信息有:
'mach-o/dyld_priv.h' file not found
'os/lock_private.h' file not found
'os/base_private.h' file not found
'pthread/tsd_private.h' file not found
'System/machine/cpu_capabilities.h' file not found
'os/tsd.h' file not found
'pthread/spinlock_private.h' file not found
'System/pthread_machdep.h' file not found
'Block_private.h' file not found
'objc-shared-cache.h' file not found
'_simple.h' file not found
复制代码
pthread_machdep.h是咱们后续加入的,里面有一些定义和原Runtime源码定义重复了,须要将pthread_machdep.h中的重复定义注释。
错误信息以下:
Static declaration of '_pthread_has_direct_tsd' follows non-static declaration
复制代码
Static declaration of '_pthread_getspecific_direct' follows non-static declaration
复制代码
Static declaration of '_pthread_setspecific_direct' follows non-static declaration
复制代码
分别将pthread_machdep.h文件中的_pthread_has_direct_tsd、_pthread_setspecific_direct、_pthread_getspecific_direct注释便可。
因为该文件的处理方式较为特别,因此单独说一下。
'CrashReporterClient.h' file not found
复制代码
首先将CrashReporterClient.h文件放到CommonHeaders目录下。
"TARGETS->objc->Build Settings",搜索"preprocessor",在Preprocessor Macros中添加 LIBC_NO_LIBCRASHREPORTERCLIENT,DEBUG和RELEASE都添加。
在我电脑上作完上述操做后,编译,仍是提示缺乏CrashReporterClient.h文件。这时能够重启下Xcode,应该就没有这个错误信息了。
错误信息以下:
Use of undeclared identifier 'DYLD_MACOSX_VERSION_10_11'
复制代码
使用了未定义的宏。
在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
复制代码
dyld_priv.h是咱们添加的,在CommonHeaders文件夹下找就能够。
错误信息以下:
'isa.h' file not found
复制代码
之因此将isa.h单独拿出来,是由于isa.h文件的位于最开始咱们下载的Runtime源码中,在runtime文件夹下。咱们须要把runtime文件夹下的isa.h文件拷贝到CommonHeaders文件夹下。isa.h文件的位置以下图:
Xcode提示
linker command failed with exit code 1(use -v to see invocation)
复制代码
点击以后能看到详细的错误信息:
can't open order file: /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/AppleInternal/OrderFiles/libobjc.order 复制代码
"TARGETS->objc->Build Settings->Linking->Order File"修改成$(SRCROOT)/libobjc.order
Xcode提示
linker command failed with exit code 1(use -v to see invocation)
复制代码
点击后会看到错误信息:
library not found for -lCrashReporterClient
复制代码
"TARGETS->objc->Build Settings->Linking->Other Linker Flags"中删除lCrashReporterClient,DEBUG和RELEASE都删除,以下图:
错误信息以下:
SDK "macosx.internal" cannot be located 和 unable to find utility "clang++", not a developer tool or in PATH
复制代码
"TARGETS->objc->Build Phases->Run Script",将脚本里面的macosx.internal改成macosx。以下图:
错误信息以下:
no such public header file: '/tmp/objc.dst/usr/include/objc/ObjectiveC.apinotes'
复制代码
作完上述操做后,再次编译,应该就能够编译经过了,编译经过后的项目以下图:
注意看Products目录下的libobjc.A.dylib和libobjc-trampolines.dylib如今都不是红色了,说明这两个动态库都已经编译成功了。
最终CommonHeaders下面的目录以下图:
编译Runtime的目的是为了调试Runtime,为了调试Runtime,须要在Runtime工程下增长一个新的Target。
Xcode->File->New->Target,选择macOS->Command Line Tool,以下图:
好比命名为runtimeTest。
添加新的Target后的项目截图以下:
为runtimeTest添加依赖,使用咱们本身编译的动态库。
Targets->runtimeTest->Build Phase->Target Dependencies,选择objc。选择完以后以下图
如今就能够在runtimeTest目录下的main.m文件中添加代码,并在Runtime源码中加断点了,运行main.m,会走到Runtime源码的断点中。运行runtimeTest以前,须要将Xcode顶部的Target改成runtimeTest,以下图