最新版本的Runtime源碼已經(jīng)出來(lái)了毡惜,是不急不可耐的想用用它呢?在這里我將一步步教大家如何編譯它祈噪,首先貼個(gè)自己的環(huán)境配置:
- mac OS 10.14
- Xcode 10.1
- objc4-750
首先給出我已編譯好的objc4-750地址粥鞋,可以直接使用派殷。
Runtime源碼地址
-
蘋(píng)果開(kāi)源網(wǎng)站上可以下載到很多開(kāi)源項(xiàng)目瞻佛,可以看到當(dāng)前最新mac OS系統(tǒng)為10.14.1传黄,最新的Xcode版本為10俏站,安裝Xcode 10.0提示mac OS系統(tǒng)需要10.13.6:
- 通常所說(shuō)的Runtime源碼就是objc4文件枣氧,由于iOS中開(kāi)源項(xiàng)目非常少辜伟,所以選擇最新mac OS系統(tǒng)10.14.1铲觉,
command+f
鍵在瀏覽器頁(yè)面右上角輸入objc4:
- 可以看到最新的objc4文件為
objc4-750.1
窝稿,點(diǎn)擊右邊的下載按鈕可以下載壓縮包:
-
也可以點(diǎn)擊objc4-750.1野揪,可以看到包里的具體內(nèi)容访忿,用Xcode可以打開(kāi)它:
- 此時(shí)顯示的網(wǎng)頁(yè)地址為
https://opensource.apple.com/source/objc4/objc4-750.1/
:
- 去掉最后的
objc4-750.1/
路徑,進(jìn)入網(wǎng)頁(yè)地址https://opensource.apple.com/source/objc4/斯稳,可以看到以往objc4歷史版本:
- 其中source替換成tarballs海铆,http://opensource.apple.com/tarballs/objc4/,就可以下載自己想要的objc4版本:
Runtime源碼編譯
下載好源碼之后用Xcode打開(kāi)是這個(gè)樣子:
這里的
libobjc.A.dylib
就是我們要編譯的目標(biāo)-Runtime庫(kù)
挣惰,編譯好之后自己可以再添加一個(gè)Target用于測(cè)試?yán)锩娴腞untime源碼卧斟,但是現(xiàn)在編譯會(huì)報(bào)錯(cuò)殴边,大部分錯(cuò)誤是缺少頭文件,這些頭文件都在蘋(píng)果開(kāi)源的其它項(xiàng)目里珍语。接下來(lái)依依解決這些問(wèn)題:
- 準(zhǔn)備工作
進(jìn)入蘋(píng)果開(kāi)源網(wǎng)站锤岸,下載依賴(lài)的開(kāi)源項(xiàng)目:
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
把他們下載好并解壓之后放入同一個(gè)文件夾中,方便查找板乙。
- 提示
'sys/reason.h' file not found
在當(dāng)前項(xiàng)目下創(chuàng)建一個(gè)文件夾Common
是偷,里面用于存放所有缺失的頭問(wèn)題件:
并且把它添加到項(xiàng)目的Header Search Paths
中,依次選擇objc->TARGETS->objc->Build Settings
募逞,搜索框中輸入header search path
蛋铆,然后加入$(SRCROOT)/Common
:
接下來(lái)需要去已下載好的開(kāi)源項(xiàng)目中尋找reason.h頭文件了,方式有兩種:
- 使用命令行:
進(jìn)入目錄cd /Users/gcf/Desktop/OpenSource
搜索文件名find . -name ‘reason.h’
可以看到搜索結(jié)果顯示在./xnu-4903.221.2/bsd/sys/reason.h
中放接,按照這個(gè)路徑找到reason.h
文件刺啦,根據(jù)編譯錯(cuò)誤提示知道,這個(gè)reason.h
文件在路徑sys
下纠脾,那么在已創(chuàng)建的Common
文件下創(chuàng)建一個(gè)新的sys
文件夾玛瘸,里面放入找到的reason.h
文件:
- 普通搜索
直接在Opensource中搜索reason.h
文件:
接下來(lái)處理和上述一樣。
- 再次編譯苟蹈,提示
'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錯(cuò)誤時(shí)再来,在include文件夾下使用grep命令:
// 如 重復(fù)定義 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;
可以看見(jiàn)有兩處定義了pthread_lock_t,注釋掉pthread_machdep.h
文件中的定義即可磷瘤。
- 提示
Static declaration of '_pthread_getspecific_direct' follows non-static declaration
這里有三個(gè)函數(shù)定義重復(fù)了:
- _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
文件夾下之后還是報(bào)錯(cuò)采缚,需要在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
文件在項(xiàng)目的runtime
文件夾中针炉,新加入的一個(gè)頭文件:
我們把它引入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
此時(shí)在 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)
里的內(nèi)容macosx.internal
改為macosx
,這里我猜測(cè)macosx.internal
為蘋(píng)果內(nèi)部的macosx贸呢,說(shuō)的不對(duì)镰烧,大家指出來(lái)。
- 提示
no such public header file: '/tmp/objc.dst/usr/include/objc/ObjectiveC.apinotes’
這里需要把Target-objc
的Build Settings
->Other Text-Based InstallAPI Flags
里的內(nèi)容設(shè)為空
!
并且一定記得要把Text-Based InstallAPI Verification Model
里的值改為Errors Only
相關(guān)警告
- 警告
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’)
在項(xiàng)目Target->objc-trampolines
和objc
中的Build Settings
下設(shè)置ALWAYS_SEARCH_USER_PATHS
為No
楞陷。 - 警告
'_PTHREAD_TSD_SLOT_PTHREAD_SELF' macro redefined
在pthread_machdep.h
頭文件中共有四個(gè)宏定義重復(fù)了:
- _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
把不會(huì)執(zhí)行到的代碼__builtin_trap();
注釋掉 - 警告
objc-class.mm:558:33: Possible misuse of comma operator here
使用Xcode提示的Fix
修復(fù) - 還有一些
Fixme...
之類(lèi)的警告,是蘋(píng)果在自己代碼里定義的一些警告提示固蛾,就不處理了结执。
添加Debug Target
-
添加一個(gè)target 取名為 objc-test
-
為改target添加工程依賴(lài)
- 在objc-test中添加測(cè)試代碼
#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.reibang.com/p/9e0fc8295c4b
- https://blog.csdn.net/WOTors/article/details/54426316
- https://blog.csdn.net/wotors/article/details/52489464
總結(jié)
-
所有頭文件
-
所有其它開(kāi)源項(xiàng)目
- 推薦給技巧度陆,從別人博客中看到的:
當(dāng)缺少頭文件時(shí),不知道在哪個(gè)開(kāi)源項(xiàng)目中献幔,比如缺少CrashReporterClient.h
懂傀,那么在谷歌中輸入CrashReporterClient.h site:opensource.apple.com
,搜索結(jié)果: