原文連接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,以下圖