最新版本的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’
可以看到搜索结果显示在./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
文件中的定义即可。
12. 提示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
文件中的定义注释掉。
12. 提示'CrashReporterClient.h' file not found
选择./Libc-825.40.1 2/include/CrashReporterClient.h
,放入Common
文件夹下之后还是报错,需要在Build Settings->Preprocessor Macros中加入:LIBC_NO_LIBCRASHREPORTERCLIENT
13. 提示'Block_private.h' file not found
选择./libdispatch-1008.220.2/src/BlocksRuntime/Block_private.h
14. 提示'objc-shared-cache.h' file not found
选择./dyld-551.3/include/objc-shared-cache.h
15. 提示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;
}
参考文章:
总结
- 所有头文件
- 所有其它开源项目
- 推荐给技巧,从别人博客中看到的:
当缺少头文件时,不知道在哪个开源项目中,比如缺少CrashReporterClient.h
,那么在谷歌中输入CrashReporterClient.h site:opensource.apple.com
,搜索结果:
看搜索结果的链接,很容易可知道它来自Libc项目。
·····················································
欢迎关注课程:
全面解析iOS中的Runtime机制