Objective-C runtime 源码调试

Objective-C runtime 源码调试Apple官方已经将Objective-C runtime的源码开源,在学习Objective-C runtime的过程中可以使用开源的代码一边调试一边学习。本文旨在帮助大家搭建调试环境。

前言

由于Apple官方已经将Objective-C runtime的源码开源,所以在学习Objective-C runtime的过程中可以使用开源的代码一边调试一边学习。但是因为Apple官方没很清晰地罗列依赖以及本地配置方法,故写下本文档作为参考。


Objc4源码Xcode调试方法

首先判断macOS的版本,若是macOS Big Sur (macOS 11)及以下,参考 github.com/hubupc/objc… 进行配置,并在 opensource.apple.com/tarballs/ 中下载所需依赖的库。

若是macOS Monterey (macOS 12),则可以参考接下来的配置方法。如果怕麻烦不想手动配置各种繁琐的操作,可以跳转至末尾【附录】下载已经配置好的工程直接上手调试。

objc4-838.1源码编译

以下配置操作,以Xcode 13.2.1面向Mac平台的编译操作为例。

下载objc4-838.1源码及其依赖

最新的objc4-838.1的源代码没有同步发到Apple官方的开源网站( opensource.apple.com/ )上,故需要到Apple官方的GitHub仓库( github.com/apple-oss-d… )上下载最新的源代码。

主源码库:

  • objc4-838.1

依赖库:

  • xnu-8019.41.5

  • dyld-940

  • Libc-1506.40.4

  • Libc-825.40.1

  • libclosure-79

  • libplatform-273.40.1

  • libpthread-485.60.2

配置依赖库目录
  1. 解压objc4-838.1并作为主工程使用

  2. 在主工程根目录下,新建名为PrivateHeaders的文件夹

image

  1. 打开objc工程

image

  1. 首先,点击左侧项目导航窗口中的工程文件objc。然后,在右侧设置窗口中,TARGETS 栏目下选中objc。接着,点击Build Settings,并选择All和Combined,在右上侧搜索栏中输入【search paths】。最后,在Search Paths栏目下,双击打开Header Search Paths,新增【$(SRCROOT)/PrivateHeaders】。

image

配置依赖

首先先将Scheme选择objc,设备选择My Mac。

image

image

然后使用快捷键command + B,即可进行编译。不出意料的话,编译器会报错。

image

虽然直接进行编译会报错,但是我们接下来的配置操作都基于Error的信息来操作。首先,点击左侧项目导航并排的感叹号图标。然后,点击Buildtime。最后,在下方的Filter栏中点击最右侧的叉号图标,即可筛选出Error信息。

image

接下来的配置操作,依赖于编译中产生的Error的信息。实际操作过程中,报错顺序可能跟下文有些差异,建议通过全局检索关键字的方式来查找解决Error对应的办法。以下是可能会产生Error信息以及对应的解决办法:

  1. unable to find sdk ‘macosx.internal’ (target: objc)

点击左侧项目导航窗口中的工程文件objc。然后,在右侧设置窗口中,TARGETS 栏目下选中objc。接着,点击Build Settings,并选择All和Combined,在右上侧搜索栏中输入【Architectures】。最后,在Architectures栏目下,将Base SDK由macosx.internal改为macOS。

image

  1. unable to find sdk ‘macosx.internal’ (target: objc-trampolines)

跟(1)的操作类似,只是Step 2中TARGETS选择objc-trampolines

  1. ‘os/feature_private.h’ file not found (target: objc ; file: objc-runtime.mm)

注释objc-runtime.mm Line 36、Line 444-446。

注释NSObject.mm Line 43。

  1. ‘sys/reason.h’ file not found (target: objc ; file: objc-os.h)

将xnu-8019.41.5根目录下的bsd/sys/reason.h文件拷贝到主工程依赖库文件夹PrivateHeaders的sys/(如没有对应的文件夹自行新建)。

  1. ‘mach-o/dyld_priv.h’ file not found (target: objc ; file: objc-os.h)

将dyld-940根目录下的include/mach-o/dyld_priv.h文件拷贝到主工程依赖库文件夹PrivateHeaders的mach-o/(如没有对应的文件夹自行新建)。

  1. Expected ‘,’ (target: objc ; file: dyld_priv.h)

在dyld_priv.h中检索所有的bridgeos(3.0),并删除。

  1. ‘os/lock_private.h’ file not found (target: objc ; file: objc-os.h)

将libplatform-273.40.1根目录下的private/os/lock_private.h文件拷贝到主工程依赖库文件夹PrivateHeaders的os/(如没有对应的文件夹自行新建)。

  1. ‘os/base_private.h’ file not found (target: objc ; file: lock_private.h)

将xnu-8019.41.5根目录下的libkern/os/base_private.h文件拷贝到主工程依赖库文件夹PrivateHeaders的os/(如没有对应的文件夹自行新建)。

  1. ‘pthread/tsd_private.h’ file not found (target: objc ; file: lock_private.h)

将libpthread-485.60.2根目录下的private/pthread/tsd_private.h文件拷贝到主工程依赖库文件夹PrivateHeaders的pthread/(如没有对应的文件夹自行新建)。

  1. ‘System/machine/cpu_capabilities.h’ file not found (target: objc ; file: tsd_private.h)

将xnu-8019.41.5根目录下的osfmk/machine/cpu_capabilities.h文件拷贝到主工程依赖库文件夹PrivateHeaders的System/machine/(如没有对应的文件夹自行新建)。

  1. Expected ‘,’ (target: objc ; file: lock_private.h)

在lock_private.h中检索所有的bridgeos(4.0),并删除。

  1. ‘os/tsd.h’ file not found (target: objc ; file: tsd_private.h)

将xnu-8019.41.5根目录下的libsyscall/os/tsd.h文件拷贝到主工程依赖库文件夹PrivateHeaders的os/(如没有对应的文件夹自行新建)。

  1. ‘pthread/spinlock_private.h’ file not found (target: objc ; file: tsd_private.h)

将libpthread-485.60.2根目录下的private/pthread/spinlock_private.h文件拷贝到主工程依赖库文件夹PrivateHeaders的pthread/(如没有对应的文件夹自行新建)。

  1. ‘System/pthread_machdep.h’ file not found (target: objc ; file: objc-os.h)

将Libc-825.40.1根目录下的pthreads/pthread_machdep.h文件拷贝到主工程依赖库文件夹PrivateHeaders的System/(如没有对应的文件夹自行新建)。

  1. ‘CrashReporterClient.h’ file not found (target: objc ; file: objc-os.h)

将Libc-825.40.1根目录下的include/CrashReporterClient.h文件拷贝到主工程依赖库文件夹PrivateHeaders。

接着,点击左侧项目导航窗口中的工程文件objc,在右侧设置窗口中,TARGETS 栏目下选中objc。然后,点击Build Settings,并选择All和Combined,在右上侧搜索栏中输入【Preprocessor Macros】。最后,在Apple Clang – Preprocessing栏目下,双击打开Preprocessor Macros,新增【LIBC_NO_LIBCRASHREPORTERCLIENT】。

image

  1. ‘objc-shared-cache.h’ file not found (target: objc ; file: objc-opt.h)

将dyld-940根目录下的include/objc-shared-cache.h文件拷贝到主工程依赖库文件夹PrivateHeaders。

  1. Typedef redefinition with different types (‘int’ vs ‘volatile OSSpinLock’ (aka ‘volatile int’)) Static & declaration of ‘_pthread_has_direct_tsd’ follows non-static declaration & Static declaration of ‘_pthread_getspecific_direct’ follows non-static declaration & Static declaration of ‘_pthread_setspecific_direct’ follows non-static declaration (target: objc ; file: pthread_machdep.h)

注释pthread_machdep.h Line 214-299。

  1. Use of undeclared identifier ‘dyld_platform_version_macOS_10_13’ (target: objc ; file: objc-os.mm)

注释objc-os.mm Line 568-575。

  1. ‘_simple.h’ file not found (target: objc ; file: objc-errors.mm)

将libplatform-273.40.1根目录下的private/_simple.h文件拷贝到主工程依赖库文件夹PrivateHeaders。

  1. ‘Cambria/Traps.h’ file not found (target: objc ; file: objc-cache.mm)

注释objc-cache.mm Line 87-88。

  1. ‘os/linker_set.h’ file not found (target: objc ; file: objc-class.mm)

将Libc-1506.40.4根目录下的os/linker_set.h文件拷贝到主工程依赖库文件夹PrivateHeaders的os/(如没有对应的文件夹自行新建)。

  1. ‘kern/restartable.h’ file not found (target: objc ; file: objc-cache.mm)

将xnu-8019.41.5根目录下的osfmk/kern/restartable.h文件拷贝到主工程依赖库文件夹PrivateHeaders的kern/(如没有对应的文件夹自行新建)。

  1. ‘Block_private.h’ file not found (target: objc ; file: objc-block-trampolines.mm)

将libclosure-79根目录下的Block_private.h文件拷贝到主工程依赖库文件夹PrivateHeaders。

  1. Use of undeclared identifier ‘oah_is_current_process_translated’ (target: objc ; file: objc-cache.mm)

注释objc-cache.mm Line 1123-1130。

  1. Use of undeclared identifier ‘dyld_fall_2020_os_versions’ (target: objc ; file: objc-runtime.mm)

注释objc-runtime.mm Line 379-380。

  1. ‘os/reason_private.h’ file not found (target: objc ; file: NSObject.mm)

将xnu-8019.41.5根目录下的libkern/os/reason_private.h文件拷贝到主工程依赖库文件夹PrivateHeaders的os/(如没有对应的文件夹自行新建)。

  1. ‘os/variant_private.h’ file not found (target: objc ; file: NSObject.mm)

将Libc-1506.40.4根目录下的os/variant_private.h文件拷贝到主工程依赖库文件夹PrivateHeaders的os/(如没有对应的文件夹自行新建)。

  1. Use of undeclared identifier ‘dyld_platform_version_bridgeOS_2_0’ & Use of undeclared identifier ‘dyld_platform_version_iOS_10_0’ & Use of undeclared identifier ‘dyld_platform_version_macOS_10_12’ & Use of undeclared identifier ‘dyld_platform_version_tvOS_10_0’ & Use of undeclared identifier ‘dyld_platform_version_watchOS_3_0’ (target: objc ; file: NSObject.mm)

注释NSObject.mm Line 1147-1151。

  1. Expected ‘,’ (target: objc ; file: variant_private.h)

在variant_private.h中检索所有的bridgeos和bridgeos(4.0),并删除。

  1. Mismatch in debug-ness macros (target: objc ; file: objc-runtime.mm)

注释objc-runtime.mm Line 128。

  1. Use of undeclared identifier ‘dyld_platform_version_macOS_10_11’ (target: objc ; file: objc-runtime-new.mm)

注释objc-runtime-new.mm Line 3528-3534。

  1. ‘_static_assert’ declared as an array with a negative size (target: objc ; file: objc-runtime-new.mm)

注释objc-runtime-new.mm Line 176-177。

  1. Use of undeclared identifier ‘dyld_fall_2018_os_versions’ (target: objc ; file: objc-runtime-new.mm)

注释objc-runtime-new.mm Line 8381-8403。

  1. Library not found for -lCrashReporterClient (target: objc)

点击左侧项目导航窗口中的工程文件objc,在右侧设置窗口中,TARGETS 栏目下选中objc。然后,点击Build Settings,并选择All和Combined,在右上侧搜索栏中输入【other linker】。最后,在Other Linker Flags栏目下,双击打开Any macOS SDK,删除【-lCrashReporterClient】。

image

(同样的操作删除Release下Any macOS SDK中的【-lCrashReporterClient】)

  1. Library not found for -loah (target: objc)

与(34)相同的操作删除【-loah】。

  1. SDK “macosx.internal” cannot be located (target: objc)

点击左侧项目导航窗口中的工程文件objc,在右侧设置窗口中,TARGETS 栏目下选中objc。然后,点击Build Phases。最后,展开Run Script (markgc)栏目,将脚本中的【macosx.internal】改为【macosx】。

image

附上完整脚本内容:

set -x
/usr/bin/xcrun -sdk macosx clang++ -Wall -mmacosx-version-min=10.12 -arch x86_64 -std=c++11 "${SRCROOT}/markgc.cpp" -o "${BUILT_PRODUCTS_DIR}/markgc"
"${BUILT_PRODUCTS_DIR}/markgc" "${BUILT_PRODUCTS_DIR}/libobjc.A.dylib"
源码编译成功

当编译后出现以下图标,代表编译成功:

image

至此,关于objc4-838.1源码前期配置以及编译的过程就结束了。

源码调试工程

通过上述的操作,我们成功编译了objc4-838.1。但是,直接学习objc4的源码难度还是太高了。此时,我们通过创建调试工程来达到学习源码的目的。

创建源码调试工程

首先我们需要创建调试工程:

  1. 点击左侧项目导航窗口中的工程文件objc,在右侧设置窗口中,TARGETS 栏目底部点击加号。然后,在弹出的项目创建框中,选中macOS,在搜索栏中输入【Command Line Tool】。接着,选择Command Line Tool,点击右下角的Next。

image

  1. 在跳转的项目信息框中,填入Product Name(本文例子填写的是【objc_test】,可以自行命名)。Language选择Objective-C。点击Finish。

image

  1. 点击左侧项目导航窗口中的工程文件objc,在右侧设置窗口中,TARGETS 栏目下选中objc_test。然后,点击General。接着,在Frameworks and Libraries栏目下点击加号。

image

  1. 选择libobjc.A.dylib,点击Add。

image

  1. 在Frameworks and Libraries栏目下,选中libobjc.A.dylib,点击Embed,选择Do Not Embed。

image

  1. 点击左侧项目导航窗口中的工程文件objc,在右侧设置窗口中,TARGETS 栏目下选中objc_test。然后,点击Build Phases。接着,展开Dependencies栏目,点击下方的加号。最后选中objc,点击Add。

image

  1. 点击左侧项目导航窗口中的工程文件objc,在右侧设置窗口中,TARGETS 栏目下选中objc_test。然后,点击Build Settings,并选择All和Combined,在右上侧搜索栏中输入【Signing】。最后,点击Enable Hardened Runtime,选择No。

image

  1. 点击左侧项目导航窗口中的工程文件objc,在右侧设置窗口中,TARGETS 栏目下选中objc_test。然后,点击Build Settings,并选择All和Combined,在右上侧搜索栏中输入【objc_msgSend】。最后,点击Enable Strict Checking of objc_msgSend Calls,选择No。

image

运行源码调试工程

展开左侧项目导航窗口中的工程文件objc_test,点击main.m。接着,将Scheme选择objc_test,设备选择My Mac。快捷键Command+R即可编译且运行工程。

image

至此,源码调试工程创建并运行成功。我们可以在objc_test工程中编写代码调用objc runtime相关的的API,并且可以同时在objc工程中添加断点来调试。

错误排查
  • objc工程无法触发断点

Scheme选择objc,快捷键command + B确保objc工程编译成功。若仍未能成功,参考【创建源码调试工程】和【运行源码调试工程】的操作,确保工程配置文件的设置符合预期。


附录

macOS Monterey (macOS 12)可以直接在 code.byted.org/caiyixian/o… 下载已经完全配置好的工程。


参考链接

今天的文章Objective-C runtime 源码调试分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/14373.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注