前言
相信各位iOS開發(fā)愛好者,都會想研究一下runtime底層的一些東西,那么最好的方式莫過于調試。蘋果其實開源了很多的底層庫,詳見:蘋果開源網(wǎng)站首頁、蘋果開源網(wǎng)站下載頁、蘋果開源網(wǎng)站瀏覽頁。
objc是蘋果開源的包含runtime等核心邏輯的庫,由于macOS的更新和可能存在的其他原因,下載下來的objc4庫,是無法直接編譯成功的,其中主要的原因是頭文件更換了位置。
本文的初衷是,記錄這樣解決問題的過程,體驗折騰的魅力。文章主要參考了:
可調試工程下載
objc4-750.1可調試工程,在macOS Mojave下可運行
objc4-723_Debug
準備工作
本文使用 Xcode 10.0(10A255)
- 在蘋果開源網(wǎng)站下載最新的
objc4-723.tar.gz開源庫,該庫就是包含runtime的庫; - 在蘋果開源網(wǎng)站下載:
Libc-1244.50.9.tar.gz-
Libc-825.40.1.tar.gz、 -
dyld-551.4.tar.gz、 -
launchd-842.92.1.tar.gz、 -
libauto-187.tar.gz、 -
libclosure-67.tar.gz、 -
libdispatch-913.60.2.tar.gz、 -
libpthread-301.50.1.tar.gz、 -
xnu-4570.71.2.tar.gz、
因Libc-1244.50.9.tar.gz有些頭文件已經不在,因此也將其舊版本的Libc-825.40.1.tar.gz下載下來(也可只下載它)。下載上述文件的目的是為了方便找尋objc4-723編譯時所缺失的頭文件。
編譯Objc
- 1、解壓
objc4-723.tar.gz,進入objc4-723文件夾,打開工程;點擊編譯,此時會報錯:The i386 architecture is deprecated. You should update your ARCHS build setting to remove the i386 architecture. (in target 'objc');解決辦法是:將TARGETS->Build Settings->Architectures都改為Standard Archiectures。 - 2、再次進行編譯,發(fā)現(xiàn)提示
'sys/reason.h' file not found;在工程根目錄下面創(chuàng)建一個include文件夾,在TARGETS->Build Settings->Header Seach Paths中添加$(SRCROOT)/include。 - 3、將準備工作第2步中的壓縮包都解壓并放在同一個文件夾中(可以不在objc4-723的工程文件夾中,假設文件夾名為Source),在Source中搜索reason.h,可以看到之前報錯的地方引入的路徑之前有sys,因此在之前創(chuàng)建的
include文件夾中創(chuàng)建sys文件夾,將搜索到的reason.h文件復制到sys目錄下。 - 4、再次編譯,報錯:
'mach-o/dyld_priv.h' file not found,使用相同的方式解決。 - 5、編譯,報錯:
os/lock_private.h' file not found;此時搜索下載的庫時并不能發(fā)現(xiàn)該文件;于是在谷歌進行如下搜索:lock_private.h site:opensource.apple.com,點擊進入搜索結果,在include文件夾下創(chuàng)建相應的os文件夾,并創(chuàng)建lock_private.h文件,將在谷歌搜索到的內容填寫到創(chuàng)建的文件中。 - 編譯,
'os/base_private.h' file not found,使用以上描述的兩種方式解決。 - 后續(xù)的:
-
pthread/tsd_private.h、 -
cpu_capabilities.h、 -
os/tsd.h、 -
spinlock_private.h、 -
pthread_machdep.h、 -
workqueue_private.h、 -
pthread/qos_private.h、 -
sys/qos_private.h、 -
objc-shared-cache.h、 -
_simple.h,等文件也采用之前的方式進行解決;注意:cpu_capabilities.h使用搜索到的machine文件夾下的文件。
-
- 編譯,遇到
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,這種錯誤本是說如下情況:
// 在一個文件中如下代碼
void sayHello(void);
static void sayHello(void) {
}
上述代碼會使編譯器報出Static declaration of xxx follows non-static declaration錯誤,但是在objc4-723時實際上是因為重復定義(將static去掉之后編譯會發(fā)現(xiàn)Redefinition of錯誤),因此直接將重復定義處注釋就好。
- 編譯,有一個缺失的文件叫做
CrashReporterClient.h,你會發(fā)現(xiàn)在將其放入include后還是會報錯,此時需要:在Build Settings->Preprocessor Macros中加入:LIBC_NO_LIBCRASHREPORTERCLIENT。 - 編譯,能夠看到
objc-os.h文件報錯,在該文件中引入:# include <pthread/qos_private.h>。 - 編譯,看到:
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
- 編譯,缺少
Block_private.h,搜索解壓后的文件,發(fā)現(xiàn)有兩個結果,復制BlocksRuntime中的文件到include下。 - 編譯,此時 clang報錯:
ld: 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。 - 編譯,ld再次報錯:
ld: library not found for -lCrashReporterClient;此時在 Build Settings -> Linking -> Other Linker Flags里刪掉"-lCrashReporterClient"(Debug和Release都刪了)。 - 再次編譯,會發(fā)現(xiàn) Build Succeeded。
如果在編譯objc過程中遇到cast錯誤,可以直接點擊Fix。
添加Debug Target
- 1、添加一個target 取名為 objc-debug

- 2、為改target添加工程依賴

- 3、在objc-debug中添加你想寫的代碼,或者類,你就可以進行調試了。
為Mojave的更新
由于macOS 10.14 的發(fā)布,objc發(fā)布了新的objc4-750.1開源庫,對應的一些,如:dyld也進行了相關更新。因此針對macOS Mojave需要使用新的開源庫,進行配置。
為了簡單操作,我直接在objc4-750.1中引用了,之前配置好的objc4-723可調試工程中的頭文件(偷懶。不想一個一個找了)。其中的部分新的錯誤參考了:
可能是由于我直接使用objc4-723工程頭文件的問題出現(xiàn)了:os_unfair_recursive_lock未定義的bug。經過我簡單分析,其作用應該是替換原有的pthread_mutex_t加鎖機制,我直接將其替換成了:objc4-723工程中的pthread加鎖機制(又是偷懶)。