最新版本的Runtime源碼已經出來了,是不急不可耐的想用用它呢?在這里我將一步步教大家如何編譯它,首先貼個自己的環境配置:
- mac OS 10.14
- Xcode 10.1
- objc4-750
首先給出我已編譯好的objc4-750地址,可以直接使用。
Runtime源碼地址
-
蘋果開源網站上可以下載到很多開源項目,可以看到當前最新mac OS系統為10.14.1,最新的Xcode版本為10,安裝Xcode 10.0提示mac OS系統需要10.13.6:
- 通常所說的Runtime源碼就是objc4文件,由于iOS中開源項目非常少,所以選擇最新mac OS系統10.14.1,
command+f
鍵在瀏覽器頁面右上角輸入objc4:
- 可以看到最新的objc4文件為
objc4-750.1
,點擊右邊的下載按鈕可以下載壓縮包:
-
也可以點擊objc4-750.1,可以看到包里的具體內容,用Xcode可以打開它:
- 此時顯示的網頁地址為
https://opensource.apple.com/source/objc4/objc4-750.1/
:
- 去掉最后的
objc4-750.1/
路徑,進入網頁地址https://opensource.apple.com/source/objc4/,可以看到以往objc4歷史版本:
- 其中source替換成tarballs,http://opensource.apple.com/tarballs/objc4/,就可以下載自己想要的objc4版本:
Runtime源碼編譯
下載好源碼之后用Xcode打開是這個樣子:
這里的
libobjc.A.dylib
就是我們要編譯的目標-Runtime庫
,編譯好之后自己可以再添加一個Target用于測試里面的Runtime源碼,但是現在編譯會報錯,大部分錯誤是缺少頭文件,這些頭文件都在蘋果開源的其它項目里。接下來依依解決這些問題:
- 準備工作
進入蘋果開源網站,下載依賴的開源項目:
Libc-825.40.1.tar.gz
dyld-551.3.tar.gz
libauto-187.tar.gz
libclosure-73.tar.gz
libdispatch-1008.220.2.tar.gz
xnu-4903.221.2.tar.gz
libpthread-330.220.2.tar.gz
launchd-842.92.1.tar.gz
-
libplatform-177.200.16.tar.gz
把他們下載好并解壓之后放入同一個文件夾中,方便查找。
- 提示
'sys/reason.h' file not found
在當前項目下創建一個文件夾Common
,里面用于存放所有缺失的頭問題件:
并且把它添加到項目的Header Search Paths
中,依次選擇objc->TARGETS->objc->Build Settings
,搜索框中輸入header search path
,然后加入$(SRCROOT)/Common
:
接下來需要去已下載好的開源項目中尋找reason.h頭文件了,方式有兩種:
- 使用命令行:
進入目錄cd /Users/gcf/Desktop/OpenSource
搜索文件名find . -name ‘reason.h’
image.png
可以看到搜索結果顯示在./xnu-4903.221.2/bsd/sys/reason.h
中,按照這個路徑找到reason.h
文件,根據編譯錯誤提示知道,這個reason.h
文件在路徑sys
下,那么在已創建的Common
文件下創建一個新的sys
文件夾,里面放入找到的reason.h
文件:
- 普通搜索
直接在Opensource中搜索reason.h
文件:
接下來處理和上述一樣。
- 再次編譯,提示
'mach-o/dyld_priv.h' file not found
選擇./dyld-551.3/include/mach-o/dyld_priv.h
,和上述同樣操作,不再重述。 - 提示
'os/lock_private.h' file not found
選擇./libplatform-177.200.16/private/os/lock_private.h
- 提示
'os/base_private.h' file not found
選擇./libplatform-177.200.16/private/os/base_private.h
- 提示
'pthread/tsd_private.h' file not found
選擇./libpthread-330.220.2/private/tsd_private.h
- 提示
'System/machine/cpu_capabilities.h' file not found
選擇./xnu-4903.221.2/osfmk/machine/cpu_capabilities.h
- 提示
'os/tsd.h' file not found
選擇./xnu-4903.221.2/libsyscall/os/tsd.h
- 提示
'pthread/spinlock_private.h' file not found
選擇./libpthread-330.220.2/private/spinlock_private.h
- 提示
'System/pthread_machdep.h' file not found
選擇./Libc-825.40.1 2/pthreads/pthread_machdep.h
- 提示
Typedef redefinition with different types ('int' vs 'volatile OSSpinLock' (aka 'volatile int’))
這種redefinition錯誤時,在include文件夾下使用grep命令:
// 如 重復定義 pthread_lock_t
grep -rne "typedef.*pthread_lock_t” .
// 輸出
./pthread/spinlock_private.h:59:typedef volatile OSSpinLock pthread_lock_t __deprecated_msg("Use <os/lock.h> instead”);
./System/pthread_machdep.h:214:typedef int pthread_lock_t;
可以看見有兩處定義了pthread_lock_t,注釋掉pthread_machdep.h
文件中的定義即可。
- 提示
Static declaration of '_pthread_getspecific_direct' follows non-static declaration
這里有三個函數定義重復了:
- _pthread_has_direct_tsd(void)
- _pthread_getspecific_direct(unsigned long slot)
- _pthread_setspecific_direct(unsigned long slot, void * val)
grep -re "_pthread_has_direct_tsd(void)” .
//輸出
./pthread/tsd_private.h:_pthread_has_direct_tsd(void)
./System/pthread_machdep.h:_pthread_has_direct_tsd(void)
grep -re "_pthread_getspecific_direct(unsigned long slot)” .
//輸出
./pthread/tsd_private.h:_pthread_getspecific_direct(unsigned long slot)
./System/pthread_machdep.h:_pthread_getspecific_direct(unsigned long slot)
grep -re "_pthread_setspecific_direct(unsigned long slot, void \* val)” .
//輸出
./pthread/tsd_private.h:_pthread_setspecific_direct(unsigned long slot, void * val)
./System/pthread_machdep.h:_pthread_setspecific_direct(unsigned long slot, void * val)
這里選擇把pthread_machdep.h
文件中的定義注釋掉。
- 提示
'CrashReporterClient.h' file not found
選擇./Libc-825.40.1 2/include/CrashReporterClient.h
,放入Common
文件夾下之后還是報錯,需要在Build Settings->Preprocessor Macros中加入:LIBC_NO_LIBCRASHREPORTERCLIENT
- 提示
'Block_private.h' file not found
選擇./libdispatch-1008.220.2/src/BlocksRuntime/Block_private.h
- 提示
'objc-shared-cache.h' file not found
選擇./dyld-551.3/include/objc-shared-cache.h
- 提示
Use of undeclared identifier ‘DYLD_MACOSX_VERSION_10_13
在 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
- 提示
'_simple.h' file not found
選擇./libplatform-177.200.16/private/_simple.h
- 提示
'isa.h' file not found
isa.h
文件在項目的runtime
文件夾中,新加入的一個頭文件:
我們把它引入Commone
文件夾中去:
- 提示
can't open order file: /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/AppleInternal/OrderFiles/libobjc.order
修改工程配置,將Build Settings->Linking->Order File改為工程根目錄下的libobjc.order,即:$(SRCROOT)/libobjc.order。 - 提示
library not found for -lCrashReporterClient
此時在 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
把Target-objc
的Build Phases
->Run Script(markgc)
里的內容macosx.internal
改為macosx
,這里我猜測macosx.internal
為蘋果內部的macosx,說的不對,大家指出來。
- 提示
no such public header file: '/tmp/objc.dst/usr/include/objc/ObjectiveC.apinotes’
這里需要把Target-objc
的Build Settings
->Other Text-Based InstallAPI Flags
里的內容設為空
!
并且一定記得要把Text-Based InstallAPI Verification Model
里的值改為Errors Only
相關警告
- 警告
Traditional headermap style is no longer supported; please migrate to using separate headermaps and set 'ALWAYS_SEARCH_USER_PATHS' to NO. (in target 'objc-trampolines')
和Traditional headermap style is no longer supported; please migrate to using separate headermaps and set 'ALWAYS_SEARCH_USER_PATHS' to NO. (in target 'objc’)
在項目Target->objc-trampolines
和objc
中的Build Settings
下設置ALWAYS_SEARCH_USER_PATHS
為No
。 - 警告
'_PTHREAD_TSD_SLOT_PTHREAD_SELF' macro redefined
在pthread_machdep.h
頭文件中共有四個宏定義重復了:
- _PTHREAD_TSD_SLOT_PTHREAD_SELF
- __PTK_LIBC_TTYNAME_KEY
- LOCK_INIT
- LOCK_INITIALIZER
這里選擇把pthread_machdep.h文件中的宏定義注釋掉。
- 警告
objc-exception.mm:584:5: Code will never be executed
把不會執行到的代碼__builtin_trap();
注釋掉 - 警告
objc-class.mm:558:33: Possible misuse of comma operator here
使用Xcode提示的Fix
修復 - 還有一些
Fixme...
之類的警告,是蘋果在自己代碼里定義的一些警告提示,就不處理了。
添加Debug Target
-
添加一個target 取名為 objc-test
-
為改target添加工程依賴
- 在objc-test中添加測試代碼
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import <objc/message.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
Class newClass = objc_allocateClassPair(objc_getClass("NSObject"), "newClass", 0);
objc_registerClassPair(newClass);
id newObject = [[newClass alloc]init];
NSLog(@"%@",newObject);
}
return 0;
}
參考文章:
- http://www.lxweimin.com/p/9e0fc8295c4b
- https://blog.csdn.net/WOTors/article/details/54426316
- https://blog.csdn.net/wotors/article/details/52489464
總結
-
所有頭文件
-
所有其它開源項目
- 推薦給技巧,從別人博客中看到的:
當缺少頭文件時,不知道在哪個開源項目中,比如缺少CrashReporterClient.h
,那么在谷歌中輸入CrashReporterClient.h site:opensource.apple.com
,搜索結果: