编译Objc源码
要诀:
能删则删, 不确定先注释,
需加须加, 能设置就设置.
准备工作
本次编译objc4-838源码, 即对应macOS 12.2, 高版本未尝试, 理论上大版本一致可行
以下相关源码均可在Apple Open Source中 macOS Monterey 12 -> macOS 12.2 分支看到
旧版源码下载
Libc-825.26 下载地址 在 OS X Mountain Lion 10.8 -> Mac OS X 10.8.4 分支下
libplatform-220.100.1 下载地址在 macOS Catalina 10.15 -> macOS 10.15.6 分支下
Project 相关
修改 Base SDK
在 Project -> Build Setting -> Base SDK 选择为macOS
选择编译 Targets 为 objc
Targets 配置相关
修改 Script
在 Targets -> objc -> Build Phases -> Run Script (markgc) 将 macosx.internal 改成 macosx
编译时 报错
文件缺失居多, xx file not found
在项目根目录新增一目录, 用来放缺失文件, (名字可以自定义, 比如/common)
然后在项目 Targets -> Build Settings -> Header Search Paths 新增 /common 路径:$(SRCROOT)/common
'sys/reason.h' file not found
在xnu源码的/bsd/sys/reason.h目录下载文件reason.h文件, 拷贝至/common下, 对应/sys/reason.h目录
'os/feature_private.h' file not found
直接注释即可, 共三处, 其NSObject.mm有两处
'mach-o/dyld_priv.h' file not found
在dyld源码的/include/mach-o/dyld_priv.h目录下载文件dyld_priv.h文件, 拷贝至/common下, 对应/mach-o/dyld_priv.h目录
然后要此文件添加宏定义:
1
2
3
4#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 0x000A0E00Expected ','在/mach-o/dyld_priv.h文件中
移除__API_AVAILABLE(macos(10.14), ios(12.0), watchos(5.0), tvos(12.0), bridgeos(3.0))中bridgeos(3.0)的条件即可
'os/lock_private.h' file not found
在libplatform源码的/private/os/lock_private.h目录下载文件lock_private.h文件, 拷贝至/common下, 对应/os/lock_private.h目录
Expected ','在/os/lock_private.h文件中
移除__API_AVAILABLE(macos(10.15), ios(13.0), tvos(13.0), watchos(6.0), bridgeos(4.0))中bridgeos(4.0)的条件即可
'os/base_private.h' file not found
在libplatform-220.100.1源码的/private/os/base_private.h目录下载文件base_private.h文件, 拷贝至/common下, 对应/os/base_private.h目录
'pthread/tsd_private.h' file not found
在libpthread源码的/private/pthread/tsd_private.h目录下载文件tsd_private.h文件, 拷贝至/common下, 对应/pthread/tsd_private.h目录
'System/machine/cpu_capabilities.h' file not found
在xnu源码的/osfmk/machine/cpu_capabilities.h目录下载文件cpu_capabilities.h文件, 拷贝至/common下, 对应/System/machine/cpu_capabilities.h目录
'os/tsd.h' file not found
在xnu源码的libsyscall/os/tsd.h目录下载文件tsd.h文件, 拷贝至/common下, 对应/os/tsd.h目录
'pthread/spinlock_private.h' file not found
在libpthread源码的/private/pthread/spinlock_private.h目录下载文件spinlock_private.h文件, 拷贝至/common下, 对应/pthread/spinlock_private.h目录
'System/pthread_machdep.h' file not found
在Libc-825.26源码的/pthreads/pthread_machdep.h目录下载文件pthread_machdep.h文件, 拷贝至/common下, 对应/System/pthread_machdep.h目录
'CrashReporterClient.h' file not found
在
Libc-825.26源码的/include/CrashReporterClient.h目录下载文件CrashReporterClient.h文件, 拷贝至/common下, 对应/CrashReporterClient.h目录
还未结束, 因为还缺少宏定义, 在
Targets -> objc -> Build Settings -> Preprocessor Macros中,添加LIBC_NO_LIBCRASHREPORTERCLIENT
- 在
pthread_machdep.h文件中一个typedef和三个函数, 这些全部注释即可
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
Unknown type name 'uint32_t' 'uint64_t, Use of undeclared identifier 'INT64_C'在/llvm-MathExtras.h文件中
导入头文件#include <cstdint>即可解决
Use of undeclared identifier 'dyld_fall_2020_os_versions'
Use of undeclared identifier 'objc4' 'preoptimizedCaches'
'objc-shared-cache.h' file not found
在dyld源码的/include/objc-shared-cache.h目录下载文件objc-shared-cache.h文件, 拷贝至/common下, 对应/objc-shared-cache.h目录
Use of undeclared identifier 'dyld_platform_version_macOS_10_13'
Use of undeclared identifier 'dyld_platform_version_macOS_10_11'
Use of undeclared identifier 'dyld_fall_2018_os_versions'注释部分判断条件
'Block_private.h' file not found
在libclosure源码的/Block_private.h目录下载文件Block_private.h文件, 拷贝至/common下, 对应/Block_private.h目录
'Cambria/Traps.h' file not found
直接注释即可1
2// #include <Cambria/Traps.h>
// #include <Cambria/Cambria.h>'_simple.h' file not found
在libplatform源码的/private/_simple.h目录下载文件_simple.h文件, 拷贝至/common下, 对应/_simple.h目录
'os/linker_set.h' file not found
在xnu源码的/bsd/sys/linker_set.h目录下载文件linker_set.h文件, 拷贝至/common下, 对应/os/linker_set.h目录
'kern/restartable.h' file not found
在xnu源码的/osfmk/kern/restartable.h目录下载文件restartable.h文件, 拷贝至/common下, 对应/kern/restartable.h目录
Use of undeclared identifier 'oah_is_current_process_translated' 和 'objc_thread_get_rip'注释此if分支
'os/reason_private.h' file not found
在xnu源码的/libkern/os/reason_private.h目录下载文件reason_private.h文件, 拷贝至/common下, 对应/os/reason_private.h目录
'os/variant_private.h' file not found
在Libc源码的/os/variant_private.h目录下载文件variant_private.h文件, 拷贝至/common下, 对应/os/variant_private.h目录
还要去掉文件里面的
bridgeos 、 bridgeos(4.0)参数Use of undeclared identifier 'dyld_platform_version_bridgeOS_2_0' iOS_10_0 macOS_10_12 tvOS_10_0 watchOS_3_0注释此if判断
'_static_assert' declared as an array with a negative size
链接时 报错
Library not found for -lCrashReporterClient
进入Targets -> objc -> Build Setting -> Other Linker Flags中,删除-lCrashReporterClientLibrary not found for -loah
进入Targets -> objc -> Build Setting -> Other Linker Flags中,删除-loah
终于 Build Succeded
添加测试 Target
新增Target
点击在Target左下角的+, 然后选择macOS -> Command Line Tool, 随便取名, 比如TestOC
链接
libobjc.A.dylib
选择Target -> TestOC -> General -> Frameworks and Libraries的+然后选择libobjc.A.dylib点击Add
编译 TestOC Target
选择新 Target - TestOC
愉快的在main中写代码吧
此时可能会发现, 断点发虚, 无法触发
断点失败, 解决方法有二
- 第一种: 关闭LTO(
Link-Time Optimization),
找到Targets -> Build Settings -> Link-Time Optimization, 选择值为NO即可
LTO 代码链接时候的一个优化选项, Apple官方解释:1
2
3
4
5
6
7Enabling this setting allows optimization across file boundaries during linking.
**No:*
Disabled. Do not use link-time optimization.
**Monolithic Link-Time Optimization:*
This mode performs monolithic link-time optimization of binaries, combining all executable code into a single unit and running aggressive compiler optimizations.
**Incremental Link-Time Optimization:*
This mode performs partitioned link-time optimization of binaries, inlining between compilation units and running aggressive compiler optimizations on each unit in parallel. This enables fast incremental builds and uses less memory than Monolithic LTO. - 第二种:
- 找到
Build Phases -> Compile Sources中,确保main.m在最最最前面 - 找到
Targets -> Build Settings -> Enable Hardened Runtime,确保值为NO
- 找到
- 第一种: 关闭LTO(