揭祕NSRuntime源碼編譯


C語言,函數的調用在編譯的時候會決定調用哪個函數。編譯完成之後直接順序執行,無任何二義性。而OC的函數調用成為消息發送。屬於動態調用過程。在編譯的時候並不能決定真正調用哪個函數(事實證明,在編 譯階段,OC可以調用任何函數,即使這個函數並未實現,只要申明過就不會報錯。而C語言在編譯階段就會報錯)。只有在真正運行的時候才會根據函數的名稱找到對應的函數來調用。


我們如何找到RunTime源碼?


Runtime源碼下載鏈接:https://opensource.apple.com/release/macos-10141.html


打開鏈接,搜索objc 找到objc4最新版本下載即可。


本文編譯環境


1、 Xcode版本:11.2.1

2、 MacOS版本:10.14.6

3、 Runtime版本:objc4-750.1

對於不同的Runtime版本及Xcode版本可能出現的錯誤也不一樣,這篇文章主要是我在編譯過程中遇到的錯誤信息以及解決方案,如果大家沒有遇到對應的錯誤信息,直接跳過即可。


編譯過程


打開objc.xcodeproj,編譯運行,

1、編譯報錯:

揭秘NSRuntime源碼編譯


解決方案:按圖中步驟將Architectures選擇Stand Architectures,點擊objc target,也如下圖修改。


揭秘NSRuntime源碼編譯


2、編譯報錯,會缺少很多的文件

第一步:打開鏈接https://opensource.apple.com/release/macos-10141.html 下載:Libc、dyld、libauto、libclosure、libdispatch、xnu、libpthread、launchd、libplatform,全部下載下來解壓到統一個目錄下。

第二步:新建文件夾Common,之後我們會把所有的報錯文件都放到該文件夾下。

第三步:Header search path,debug及release下添加$(SRCROOT)/Common,如下圖。


揭秘NSRuntime源碼編譯


第四步:逐步編譯添加缺少的文件。


報錯1:'reason.h' file not found

解決方案:打開終端,cd到第一步中統一的目錄下,執行命令:find . -name 'reason.h' ,

終端打印./xnu-4570.71.2/bsd/sys/reason.h

在Common目錄下新建sys文件夾,到文件夾下該文件夾下找到reason.h 添加到項目sys文件夾下,繼續編譯。


報錯2:'dyld_priv.h' file not found,所在路徑:./dyld-655.1.1/include/mach-o/dyld_priv.h,

添加後會在dyld_priv.h文件中報錯Expected ',' 註釋掉即可

*通上述步驟可找到文件添加到工程,為節省大家時間,相同的操作會列出缺少文件及對應找的目錄

報錯3:'lock_private.h' file not found

路徑:./libplatform177.200.16/private/os/lock_private.h


報錯4:'base_private.h' file not found

路徑:./libplatform177.200.16/private/os/base_private.h


報錯5:'tsd_private.h' file not found

路徑:./libpthread-330.250.2/private/tsd_private.h


報錯6:'cpu_capabilities.h' file not found

如果執行find . -name 'cpu_capabilities.h'會有三個文件,我們用./xnu-4570.71.2/osfmk/machine/cpu_capabilities.h 目錄下文件

報錯7:'tsd.h' file not found

會有兩個文件,我們用:./xnu-4570.71.2/libsyscall/os/tsd.h


報錯8:'spinlock_private.h' file not found

路徑./libpthread-330.250.2/private/spinlock_private.h

報錯9:'pthread_machdep.h' file not found

採用上述方案找不到該文件,我們需要採取新的方案,即在google搜索pthread_machdep打開第一條,自己在Common/System下新建文件,將內容拷貝進去。

拷貝後會報錯:Typedef redefinition with different types ('int' vs 'volatile OSSpinLock' (aka 'volatile int')) 解決方案 將該文件中報錯的地方註釋掉


*注意如果註釋不全這會報錯-如果沒有下圖報錯跳過次步驟


揭秘NSRuntime源碼編譯

解決方案:一定將pthread_machdep.h文件中inline static int 這行代碼註釋掉


錯誤10:'CrashReporterClient.h' file not found

同報錯9一樣的方式解決,


錯誤11:'Block_private.h' file not found

路徑./libclosure-73/Block_private.h對應目錄./libdispatch-1008.250.7/src/BlocksRuntime/Block_private.h


錯誤12:'objc-shared-cache.h' file not found

路徑:./dyld-655.1.1/include/objc-shared-cache.h


錯誤13:'_simple.h' file not found

路徑./libplatform-177.200.16/private/_simple.h


錯誤14:'dyld_priv.h' file not found

路徑./dyld-655.1.1/include/mach-o/dyld_priv.h


錯誤15:'isa.h' file not found

路徑./objc4-750.1/runtime/isa.h


3、編譯報錯:

Use of undeclared identifier ‘CRGetCrashLogMessage’

解決方法:target -> Build Settings -> Preprocessor Macros 添加LIBC_NO_LIBCRASHREPORTERCLIENT,如下圖。


揭秘NSRuntime源碼編譯


4、編譯報錯:

Use of undeclared identifier 'DYLD_MACOSX_VERSION_10_13'

解決方案:在dyld_priv.h中添加下邊代碼:

<code>#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/<code>


如下圖:


揭秘NSRuntime源碼編譯


5、繼續編譯報錯:

<code>can't open order file: /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk/AppleInternal/OrderFiles/libobjc.order/<code>

解決方法:如下圖target -> objc -> Build Settings -> Order File

加入:$(SRCROOT)/libobjc.order,如下圖:


揭秘NSRuntime源碼編譯


6、繼續編譯報錯:

library not found for -lCrashReporterClient

解決方法:刪除lCrashReporterClient,如下圖:


揭秘NSRuntime源碼編譯


7、繼續編譯報錯:

Undefined symbol: _objc_opt_class:

解決方法:


揭秘NSRuntime源碼編譯


8、繼續編譯報錯:


揭秘NSRuntime源碼編譯


•解決方法:選擇 target -> objc -> Build Phases -> Run Script(markgc)

•把腳本文本 macosx.internal 改成 macosx


9、繼續編譯報錯:

<code>error: no such public header file: '/tmp/objc.dst/usr/include/objc/ObjectiveC.apinotes'/<code>


解決方法:選擇 target -> objc -> Build Settings

•Text-Based InstallAPI Verification Model 中添加搜索路徑 Errors Only

將Supports Text-Based Install API 設為NO


揭秘NSRuntime源碼編譯


編譯通過

新建Target:runtimeTest 運行runtimeTest,runtimeTest下main.m文件裡可以斷點查看runtime源碼。


分享到:


相關文章: