iOS源码objc 编译以及调试

614 阅读6分钟

前言

工欲善其事必先利其器,所以,我们在探究runtime的时候总需要一些工具(调试),在查看网上相关文章资料后,发现时间上都比较古早,本着积累和给后续的小伙伴提供便利,我打算写一篇文章。当然时间紧急的可以直接滑到最后获取相关预制菜进行服用。

食材购买地址

首先我们需要从 Apple OSS Distributions 下载相关资源。

厨房等级

本文基于目前手头设备进行的编译调试

  • macOS 版本 15.0.1
  • Xcode 版本 16.1

食材清单

image.png
大家可以点击相关文字链接直达资源下载:

在后续的Libcpthread_machdep.h已被去掉的,所以在从 Libc-Libc-825.40.1 库添加。

我们按照上面图片将下载的资源解压放入goods文件夹中,方便搜索objc4里缺少的头文件。同时在项目内创建 dependency文件夹,用于存放确实文件。如下图

image.png
并且 在Build Settings -> Header Search Paths中添加此路径$(SRCROOT)/dependency,如图所示

image.png

食材处理

前期需要准备的内容我们就差不多准备好了,接下来打开objc4工程,然后打开objc.xcodeproj,然后选择objctarget编译一下,可以看到报错如下:

食材确实

unable to find sdk 'macosx.internal'

image.png

Project->build setting->Base SDK,选择 macOS。依次对objc-evnobjc-trampolines进行修改

image.png

同时修改Run Script,修改objcRun Script(markgc)脚本,将 macosx.internal 改成macosx

注意是 Run Script(markgc)
在倒数第三个!!!!

image.png

配置菜品

在遇到报错的文件缺失,我们可以在终端输入

cd dependency 
find . -name "xxxxx.h"

为了方便大家,这里我一一书写命令行,直接说明相关文件路径。遇到没有的文件夹,直接创建一个。

'sys/reason.h' file not found

打开xnu文件夹,然后在xnu/bsd/sys目录下找到reason.h文件,copy到 dependency/sys/文件夹下

'mach-o/dyld_priv.h' file not found

打开dyld文件夹,然后在dyld/include/mach-o目录下找到dyld_priv.h文件,copy到 dependency/mach-o/文件夹下

'os/lock_private.h' file not found

打开在libplatform文件夹,然后在libplatform/private/os目录下找到lock_private.h文件,copy到 dependency/sys/文件夹下

'os/variant_private.h' file not found

打开Libc文件夹,然后在Libc/os目录下找到variant_private.h文件,copy到 dependency/os/文件夹下

'os/base_private.h' file not found

打开xnu文件夹,然后在xnu/libkern/os/目录下找到base_private.h文件,copy到 dependency/os/文件夹下

'pthread/tsd_private.h' file not found

打开libpthread文件夹,然后在libpthread/private/pthread/目录下找到tsd_private.h文件,copy到 dependency/pthread/文件夹下

'machine/cpu_capabilities.h' file not found

打开xnu文件夹,然后在xnu/osfmk/machine/目录下找到cpu_capabilities.h文件,copy到 dependency/machine/文件夹下

'os/tsd.h' file not found

打开xnu文件夹,然后在xnu/libsyscall/os/目录下找到tsd.h文件,copy到 dependency/os/文件夹下

'System/pthread_machdep.h' file not found

打开Libc-825.40.1文件夹,然后在Libc-825.40.1/pthreads/目录下找到pthread_machdep.h文件,copy到 dependency/System/文件夹下

'System/machine/cpu_capabilities.h' file not found

打开xnu文件夹,然后在xnu/osfmk/machine/目录下找到cpu_capabilities.h文件,copy到 dependency/System/machine/文件夹下

注意cpu_capabilities.h这里又加了一次,相同路径

'CrashReporterClient.h' file not found

打开Libc-825.40.1文件夹,然后在Libc-825.40.1/include/目录下找到CrashReporterClient.h文件,copy到 dependency/文件夹下

#include_next <CrashReporterClient.h> 这里报错

这里可以直接注释掉

image.png

'Block_private.h' file not found

打开libclosure文件夹,然后在libclosure/目录下找到Block_private.h文件,copy到 dependency/文件夹下

'objc-shared-cache.h' file not found

打开dyld文件夹,然后在dyld/include/目录下找到objc-shared-cache.h文件,copy到 dependency/文件夹下

'os/reason_private.h' file not found

打开xnu文件夹,然后在xnu/libkern/os/目录下找到reason_private.h文件,copy到 dependency/os/文件夹下

'os/bsd.h' file not found

打开Libc文件夹,然后在Libc/libdarwin/h/目录下找到bsd.h文件,copy到 dependency/os/文件夹下

'os/api.h' file not found

打开Libc文件夹,然后在Libc/os/目录下找到api.h文件,copy到 dependency/os/文件夹下

'os/linker_set.h' file not found

打开xnu文件夹,然后在xnu/bsd/sys/目录下找到linker_set.h文件,copy到 dependency/os/文件夹下

'_simple.h' file not found

打开libplatform文件夹,然后在libplatform/private目录下找到_simple.h文件,copy到 dependency/文件夹下

'kern/restartable.h' file not found

打开xnu文件夹,然后在xnu/osfmk/kern/目录下找到restartable.h文件,copy到 dependency/kern/文件夹下

食材处理

'os/feature_private.h' file not found

注释此头文件的引用

'os/log_simple_private.h' file not found

注释此头文件的引用

删除相关使用

image.png

dyld_priv.h中 Expected ','

image.png

删除dyld_priv.h的所有的bridgeos(3.0)(包括前面的','号)。

lock_private.h 中 expected ','

删除lock_private.h的所有的bridgeos(4.0)(包括前面的','号)。

Static declaration of '_pthread_has_direct_tsd' follows non-static declaration (pthread_machdep.h)

注释掉报错代码,如下图

image.png

Use of undeclared identifier 'dyld_platform_version_bridgeOS_2_0'

删除后面条件

// 修改前 
bool willTerminate = (DebugPoolAllocation == Fatal 
        || sdkIsAtLeast(10_12, 10_0, 10_0, 3_0, 2_0)); 


// 修改后
bool willTerminate = (DebugPoolAllocation == Fatal);

Use of undeclared identifier 'dyld_platform_version_macOS_10_13'

注释相关代码 如下图 image.png

variant_private.h 文件中报 error: expected ','

删除variant_private.h中所有的bridgeos(4.0)以及bridgeos相关内容(包括前面的','号)。

'malloc_private.h' file not found

注释掉相关 导入以及使用如下

第一步
image.png 第二步
image.png

第三步

image.png

Use of undeclared identifier 'dyld_fall_2020_os_versions'

错误内容包含了一些其他的
Use of undeclared identifier 'objc4'
Use of undeclared identifier 'classRxSigning'
Use of undeclared identifier 'classRoSigningFaults'
Use of undeclared identifier 'autoreleaseFaultsMacOS'
Use of undeclared identifier 'preoptimizedCaches'

image.png 老规矩 全部注释掉!!

'sandbox/private.h' file not found

image.png

注释注释注释!!

'Cambria/Traps.h' file not found

image.png

注释注释注释!!

Use of undeclared identifier 'CRSetCrashLogMessage'

image.png

注释注释注释!!

'Cambria/Cambria.h' file not found

image.png 注释注释注释!!

Use of undeclared identifier 'oah_is_current_process_translated'

修改如下 image.png

Library 'oah' not found

在 objc 这个 target 的 Build Settings 中,搜索 Other Linker Flags,然后在 debug 和release 中删除 -loah

image.png

到目前全部错误,我们就解决了,看到 build succeeded,悬着的心终于落下了!!

image.png

蒸煮炒

距离我们能成功调试代码就剩下最后这一步了,革命尚未成功,同志仍需努力!

锅碗

添加一个可供调试的target

步骤一

image.png 步骤二 起名 objcBuildDemo

image.png

瓢盆

添加相关依赖库 如下图所示

image.png

Build Settings中将Enable Hardened Runtime设置为NO,否则在objc源码下的断点没法断住,这个是Xcode 11的新特性!!!

image.png

至此,我们完成了所有需要操作的一些内容,接下来我们可以尽情享用。

食用

准备碗筷

我们通过 command + N 创建调试文件 Animal 如下图

image.png 在main文件中进行初始化

#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import "Animal.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        NSLog(@"Hello, World!");
        Animal *obj  = [[Animal alloc]init];
        NSLog(@"%zd", class_getInstanceSize(obj.class));
    }
    return 0; 
}

在如图处打上断点,选择target objcBuildDemo,运行

image.png 点击 step into就这样我们走进了objc 调试世界。

image.png

进食失败

筷子拿反

在运行的时候我们,可能遇到断点断不住的情况,这个时候,可能是我们的筷子拿反了,我们需要将他调换一下顺序。 image.png 将上图的两个位置进行调换,main 文件在上面即可继续服用!

and so on...

预制菜

为了方便大家更快享用,我将项目上传到了这里。时间不够的小伙伴,可以自取。 麻烦 star 一下哈,给个好评!