本系列博客是本人的源码阅读笔记,如果有 iOS 开发者在看 runtime 的,欢迎大家多多交流。为了方便讨论,本人新建了一个微信群(iOS技术讨论群),想要加入的,请添加本人微信:zhujinhui207407,【加我前请备注:ios 】,本人博客http://www.kyson.cn 也在不停的更新中,欢迎一起讨论
本文完整版详见笔者小专栏:https://xiaozhuanlan.com/runtime
背景
全局搜索TARGET_OS_WIN32
可以看到有很多相关代码。
不言而喻,TARGET_OS_WIN32
的意思是目标系统是不是在windows32上。那么TARGET_OS_WIN32
究竟是什么,知道这个宏对我们阅读runtime源代码有什么帮助,本文笔者将带大家分析一下。
分析
点击runtime中的任意一个TARGET_OS_WIN32
,进入其定义
#define TARGET_OS_WIN32 0
该宏位于
#if defined(__GNUC__) && ( defined(__APPLE_CPP__) || defined(__APPLE_CC__) || defined(__MACOS_CLASSIC__) )
#define TARGET_OS_MAC 1
#define TARGET_OS_WIN32 0
#define TARGET_OS_UNIX 0
//......后面还有很多这里就不展示了
/*
* CodeWarrior compiler from Metrowerks/Motorola
*/
#elif defined(__MWERKS__)
#define TARGET_OS_MAC 1
#define TARGET_OS_WIN32 0
#define TARGET_OS_UNIX 0
#define TARGET_OS_EMBEDDED 0
//......后面还有很多这里就不展示了
#else
#define TARGET_OS_MAC 1
#define TARGET_OS_WIN32 0
#define TARGET_OS_UNIX 0
#define TARGET_OS_EMBEDDED 0
可以发现 不管走哪个分支
#define TARGET_OS_WIN32 0
都是生效的,那么实际是不是这样呢,我们写个Demo来验证一下:
int main() {
printf("TARGET_OS_MAC: %d\n",TARGET_OS_MAC);
printf("TARGET_OS_WIN32: %d\n",TARGET_OS_WIN32);
}
可以看到log如下:
TARGET_OS_MAC: 1
TARGET_OS_WIN32: 0
Program ended with exit code: 0
完美验证了我们的想法。
接下来我们从代码角度来分析一下走的是哪个分支:
第一个分支:
#if defined(__GNUC__) && ( defined(__APPLE_CPP__) || defined(__APPLE_CC__) || defined(__MACOS_CLASSIC__) )
大概意思是判断
- 有没有定义
__GNUC__
,如果定义了,进入第二步 - 有没有定义
__APPLE_CPP__
或者__APPLE_CC__
或者__MACOS_CLASSIC__
- 如果1,2都为真,则走该分支。
因此我们可以写如下测试程序:
int main() {
printf("__GNUC__: %d\n",__GNUC__);
// printf("__APPLE_CPP__: %d\n",__APPLE_CPP__);
printf("__APPLE_CC__: %d\n",__APPLE_CC__);
// printf("__MACOS_CLASSIC__: %d\n",__MACOS_CLASSIC__);
// printf("__APPLE_CPP__: %d\n",__APPLE_CPP__);
}
运行结果如下:
__GNUC__: 4
__APPLE_CC__: 6000
Program ended with exit code: 0
注释的部分是因为如果不注释,程序不能运行,间接也说明__APPLE_CPP__
和__MACOS_CLASSIC__
和__APPLE_CPP__
是没有被定义的,只有__APPLE_CC__
被定义的,也满足条件1、2了。
接下来我们详细讲述一下这几个宏:
__GNUC__
GCC官方文档 这里描述了__GNUC__
的含义
These macros are defined by all GNU compilers that use the C preprocessor: C, C++, and Objective-C. Their values are the major version, minor version, and patch level of the compiler, as integer constants. For example, GCC 3.2.1 will define
__GNUC__
to 3,__GNUC_MINOR__
to 2, and__GNUC_PATCHLEVEL__
to 1. They are defined only when the entire compiler is in use; if you invoke the preprocessor directly, they are not defined.
大致翻译一下:
本文完整版详见笔者小专栏:https://xiaozhuanlan.com/runtime
这里介绍了__APPLE_CC__
的含义:
__APPLE_CC__
is also hard-coded to 6000 in the open-source clang compiler. So it seems appropriate to ask what the point of this macro is here.
作用
了解了TARGET_OS_WIN32
这个宏永远是0,也就是说,有些代码永远被执行,对我们阅读runtime源码有很大帮助,这里举个例子:
在objc-os.mm文件中有如下代码:
把如下代码清除:
#include "objc-runtime-old.h"
#include "objcrt.h"
int monitor_init(monitor_t *c)
{
// fixme error checking
HANDLE mutex = CreateMutex(NULL, TRUE, NULL);
while (!c->mutex) {
// fixme memory barrier here?
if (0 == InterlockedCompareExchangePointer(&c->mutex, mutex, 0)) {
// we win - finish construction
c->waiters = CreateSemaphore(NULL, 0, 0x7fffffff, NULL);
c->waitersDone = CreateEvent(NULL, FALSE, FALSE, NULL);
InitializeCriticalSection(&c->waitCountLock);
c->waitCount = 0;
c->didBroadcast = 0;
ReleaseMutex(c->mutex);
return 0;
}
}
// someone else allocated the mutex and constructed the monitor
ReleaseMutex(mutex);
CloseHandle(mutex);
return 0;
}
void mutex_init(mutex_t *m)
{
while (!m->lock) {
CRITICAL_SECTION *newlock = malloc(sizeof(CRITICAL_SECTION));
InitializeCriticalSection(newlock);
// fixme memory barrier here?
if (0 == InterlockedCompareExchangePointer(&m->lock, newlock, 0)) {
return;
}
// someone else installed their lock first
DeleteCriticalSection(newlock);
free(newlock);
}
}
void recursive_mutex_init(recursive_mutex_t *m)
{
// fixme error checking
HANDLE newmutex = CreateMutex(NULL, FALSE, NULL);
while (!m->mutex) {
// fixme memory barrier here?
if (0 == InterlockedCompareExchangePointer(&m->mutex, newmutex, 0)) {
// we win
return;
}
}
// someone else installed their lock first
CloseHandle(newmutex);
}
WINBOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
environ_init();
tls_init();
lock_init();
sel_init(3500); // old selector heuristic
exception_init();
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
OBJC_EXPORT void *_objc_init_image(HMODULE image, const objc_sections *sects)
{
header_info *hi = malloc(sizeof(header_info));
size_t count, i;
hi->mhdr = (const headerType *)image;
hi->info = sects->iiStart;
hi->allClassesRealized = NO;
hi->modules = sects->modStart ? (Module *)((void **)sects->modStart+1) : 0;
hi->moduleCount = (Module *)sects->modEnd - hi->modules;
hi->protocols = sects->protoStart ? (struct old_protocol **)((void **)sects->protoStart+1) : 0;
hi->protocolCount = (struct old_protocol **)sects->protoEnd - hi->protocols;
hi->imageinfo = NULL;
hi->imageinfoBytes = 0;
// hi->imageinfo = sects->iiStart ? (uint8_t *)((void **)sects->iiStart+1) : 0;;
// hi->imageinfoBytes = (uint8_t *)sects->iiEnd - hi->imageinfo;
hi->selrefs = sects->selrefsStart ? (SEL *)((void **)sects->selrefsStart+1) : 0;
hi->selrefCount = (SEL *)sects->selrefsEnd - hi->selrefs;
hi->clsrefs = sects->clsrefsStart ? (Class *)((void **)sects->clsrefsStart+1) : 0;
hi->clsrefCount = (Class *)sects->clsrefsEnd - hi->clsrefs;
count = 0;
for (i = 0; i < hi->moduleCount; i++) {
if (hi->modules[i]) count++;
}
hi->mod_count = 0;
hi->mod_ptr = 0;
if (count > 0) {
hi->mod_ptr = malloc(count * sizeof(struct objc_module));
for (i = 0; i < hi->moduleCount; i++) {
if (hi->modules[i]) memcpy(&hi->mod_ptr[hi->mod_count++], hi->modules[i], sizeof(struct objc_module));
}
}
hi->moduleName = malloc(MAX_PATH * sizeof(TCHAR));
GetModuleFileName((HMODULE)(hi->mhdr), hi->moduleName, MAX_PATH * sizeof(TCHAR));
appendHeader(hi);
if (PrintImages) {
_objc_inform("IMAGES: loading image for %s%s%s%s\n",
hi->fname,
headerIsBundle(hi) ? " (bundle)" : "",
hi->info->isReplacement() ? " (replacement)":"",
hi->info->hasCategoryClassProperties() ? " (has class properties)":"");
}
// Count classes. Size various table based on the total.
int total = 0;
int unoptimizedTotal = 0;
{
if (_getObjc2ClassList(hi, &count)) {
total += (int)count;
if (!hi->getInSharedCache()) unoptimizedTotal += count;
}
}
_read_images(&hi, 1, total, unoptimizedTotal);
return hi;
}
OBJC_EXPORT void _objc_load_image(HMODULE image, header_info *hinfo)
{
prepare_load_methods(hinfo);
call_load_methods();
}
OBJC_EXPORT void _objc_unload_image(HMODULE image, header_info *hinfo)
{
_objc_fatal("image unload not supported");
}
删掉以后可以更加专注我们的代码如下:
怎么样,是不是感觉源代码更清爽了?
广告
我的首款个人开发的APP壁纸宝贝上线了,欢迎大家下载。