objc-706工程搭建

环境

macOS 10.12.1
Xcode 8.1

代码

可编译 & 运行的工程 objc-706

流程

源代码下载

macOS10.12.1 objc4-706

编译 -> 失败 -> 编译 -> 失败… 编译 -> 成功

‘sys/reason.h’ file not found (objc-os.h)

Q1: 为什么<sys/param.h>可以找到?

按住⌘ 点击进入<sys/param.h>

实际路径

1
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/param.h

Q2: 为什么会去找这个路径?

A2 : 决定于Build Settings中的Use Standard System Header Directory Searching字段

Controls whether the standard system directories are searched for header files. When disabled, only the directories you have specified with -I options (and the directory of the current file, if appropriate) are searched.

实际目录下确实没有 <sys/reason.h>

A1: 实际目录下确实没有 <sys/reason.h>

原来的头文件查找目录在/tmp*下,为了方便,添加路径$(SRCROOT)/include*

objc-706工程目录中创建一个include目录,将相关的头文件放在这里

Q3: 如何找到对应的头文件

A3: Google ⏎ xxx.h site:opensource.apple.com

比如 reason.h site:opensource.apple.com

结果如下:

看上去应该在xnu这个目录下

根据有sys目录,最后找到 [reason.h](https://opensource.apple.com/source/xnu/xnu-3789.21.4/bsd/sys/reason.h)

更好的方法是将整个目录下载下来通过 find/grep 指令去查找

1
2
$ find ~/Downloads/objc-res/xnu-3789.21.4/* -name "reason.h"
/Users/Jason/Downloads/objc-res/xnu-3789.21.4/bsd/sys/reason.h*
  • include下创建sys目录
  • reason.h拷贝到sys目录下
  • ⌘ + B*

mach-o/dyld_priv.h file not found (objc-os.h)

dyld_priv.h

⌘ + B

os/lock_private.h file not found (objc-os.h)

没找到
换个思路,改搜github

比较过,两个都是一样的,选择一个即可
lock_private.h
lock_private.h

⌘ + B

‘System/pthread_machdep.h’ file not found (objc-os.h)

应该在Libc

macOS10.12.1Libc-1158.20.4并没有pthreads目录,找以前的版本,在Libc-825.40.1找到了pthread目录

pthread_machdep.h

include目录下新建System目录,拷贝pthread_machdep.h到该目录下

⌘ + B

System/machine/cpu_capabilities.h file not found (pthread_machdep.h)

cpu_capabilities.h

System目录下新建machine目录,拷贝cpu_capabilities.h到该目录下

⌘ + B

CrashReporterClient.h file not found (objc-os.h)

Libc-825.40.1中存在
CrashReporterClient.h

将其拷贝到include目录下

⌘ + B

CrashReporterClient.h file not found (CrashReporterClient.h)

#include_next 包含指定文件所在的路径的后面路径的那个文件

例如有个搜索路径链,在#include中,它们的搜索顺序依次是A,B,C,D和E。在B目录中有个头文件叫a.h,在D目录中也有个头文件叫a.h,如果在我们的源代码中这样写#include <a.h>,那么我们就会包含的是B目录中的a.h头文件,如果我们这样写#include_next <a.h>那么我们就会包含的是D目录中的a.h头文件

代码有如下注释

1
/* Include the real CrashReporterClient.h */

但我们没有真正的CrashReporterClient.h

Build Settings->Preprocessor Macros(Debug & Release)加入:

LIBC_NO_LIBCRASHREPORTERCLIENT

⌘ + B

错误就有些多了

参考 objc - 编译Runtime源码
将需要的压缩包先下载下来

先解决.h没有的问题

phread/workqueue_private.h file not found (objc-os.h)

✔︎ ./libpthread-218.20.1/private/workqueue_private.h
include目录下新建pthread目录,拷贝workqueue_private.hpthread目录中
⌘ + B

pthread/qos_private.h file not found (objc-os.h)

./libpthread-218.20.1/private/qos_private.h
✔︎ ./libpthread-218.20.1/sys/qos_private.h
⌘ + B

sys/qos_private.h file not found (objc-os.h)

./libpthread-218.20.1/private/qos_private.h
✔︎ ./libpthread-218.20.1/sys/qos_private.h
⌘ + B

objc-shared-cache.h file not found (objc-os.h)

✔︎ ./dyld-421.2/include/objc-shared-cache.h
⌘ + B

终于不报xxx.h not found的错误了

继续,解决变量未定义的问题

grep的方式去找出来

1
$ grep -rne "#define.*_PTHREAD_TSD_SLOT_MACH_THREAD_SELF" .

✔︎ /libpthread-218.20.1/private/tsd_private.h

workqueue_private.h*也是来自于/libpthread-218.20.1/private,拷贝到了pthread目录下,将tsd_private.h也拷贝至pthread*目录下

还是报错,仔细检查objc-os.h 发现并未引入tsd_private.h头文件

在第34行上下加一句

1
#include <pthread/tsd_private.h>

⌘ + B

‘os/tsd.h’ file not found (tsd_private.h)

./libdispatch-703.20.1/src/shims/tsd.h
✔︎ ./xnu-3789.21.4/libsyscall/os/tsd.h
⌘ + B

‘pthread/spinlock_private.h’ file not found (tsd_private.h)

✔︎./libpthread-218.20.1/private/spinlock_private.h
⌘ + B

错误”变多了”,看警告,发现重复定义了,参考上面的blog

重复定义了pthread_lock_t,切换到Terminal,⌘+T打开新的一个Tab,cd到objc4-680/include/那grep一下就好了:
cd ../objc4-680/include/
grep -rne “typedef.*pthread_lock_t” .
结果:
./pthread/spinlock_private.h:59:typedef volatile OSSpinLock pthread_lock_t;
./System/pthread_machdep.h:214:typedef int pthread_lock_t;
从结果发现我们之前引入的pthread_machdep.h已经typedef过了。注释掉其中一个就好。但我这里选择注释掉pthread_machdep.h的,在Line 214:
//typedef int pthread_lock_t;
为什么是它呢?因为它是我们从Libc拷过来的,而Libc我们下载了较旧的版本。…

因此注释掉pthread_machdep.h中重定义的部分

根据重定义pthread_lock_t的错误

1
$ grep -rne "typedef.*pthread_lock_t" .

./Libc-825.40.1/fbsdcompat/spinlock.h:65:typedef pthread_lock_t spinlock_t;
./Libc-825.40.1/pthreads/pthread_machdep.h:214:typedef int pthread_lock_t;
✔︎ ./libpthread-218.20.1/private/spinlock_private.h:59:typedef volatile OSSpinLock pthread_lock_t __deprecated_msg(“Use <os/lock.h> instead”);
./libpthread-218.20.1/tests/cond_hang3.c:14:typedef long pthread_lock_t;

⌘ + B

Unknown type name ‘pthread_priority_t’ (objc-os.h)

1
$ grep -rne "pthread_priority_t;" .

./libdispatch-703.20.1/src/shims.h:42:typedef unsigned long pthread_priority_t;
./libdispatch-703.20.1/src/shims.h:80:typedef unsigned long pthread_priority_t;
✔︎ ./libpthread-218.20.1/private/qos_private.h:38:typedef unsigned long pthread_priority_t;

1
#include <pthread/qos_private.h>

⌘ + B

1
$ grep -rne "os_unfair_lock" .

./libpthread-218.20.1/src/internal.h:105:typedef os_unfair_lock _pthread_lock;
./libpthread-218.20.1/src/internal.h:108:#define _PTHREAD_LOCK(lock) os_unfair_lock_lock_with_options_inline(&(lock), OS_UNFAIR_LOCK_DATA_SYNCHRONIZATION)
./libpthread-218.20.1/src/internal.h:109:#define _PTHREAD_LOCK_FROM_MACH_THREAD(lock) os_unfair_lock_lock_inline_no_tsd_4libpthread(&(lock))
./libpthread-218.20.1/src/internal.h:110:#define _PTHREAD_UNLOCK(lock) os_unfair_lock_unlock_inline(&(lock))
./libpthread-218.20.1/src/internal.h:111:#define _PTHREAD_UNLOCK_FROM_MACH_THREAD(lock) os_unfair_lock_unlock_inline_no_tsd_4libpthread(&(lock))

这里路径是src,有点不一样,先不要引入internal.h,先Google一下,os_unfair_lock

OSSpinlock is depreciated
os_unfair_lock

是个结构体,在facebook/folly - macOS Sierra issues
中提到了warning: ‘OSSpinLockUnlock’ is deprecated: first deprecated in macOS 10.12 - Use os_unfair_lock_unlock() from <os/lock.h> instead [-Wdeprecated-declarations]

所以引入

1
#include <os/lock.h>

⌘ + B

grep后发现又在internal.h中,根据lock.h,修改一下lock() & unlock()方法

修改后

⌘ + B

‘_simple.h’ file not found (objc-errors.mm)

✔︎ ./Libc-825.40.1/gen/_simple.h
⌘ + B

Use of undeclared identifier ‘os_unfair_lock_assert_owner’ (objc-lockdebug.mm)

1
$ grep -rne "os_unfair_lock_assert_owner" .

没有匹配项

Google了未发现,先将该函数的功能修改为输出日志

⌘ + B

‘Block_private.h’ file not found (objc-block-trampolines.mm)

✔︎ ./libclosure-67/Block_private.h
⌘ + B

链接动态库的时候不能打开libobjc.order,查看在对应路径下并没有libobjc.order文件,发现objc工程已经有libobjc.order,应该会有字段说明要引用的路径,想办法让工程引入本身的libobjc.order文件

最后找到Build SettingsOrder File

将该字段统一修改为$(PROJECT_DIR)/libobjc.order

⌘ + B

因为工程中并没有CrashReporterClient的库
Other Linker flags*中的
-lCrashReporterClient参数去掉
*
⌘ + B**

终于编译成功了☺,然后创建一个debug-objctarget,导入修改的libobjc.A.dylib

⌘ + R

正常运行并输出,lockdebug_mutex_assert_locked被调用了很多次,但不会影响,可注释掉它的输出

OK,已经可以进行调试了

可以调试,但是在debug-objc工程中还是无法访问objc_class

进行以下操作

  • 添加代码
1
2
3
objc_class *obj_1 = (objc_class *)[NSObject class];
objc_class *obj_2 = (objc_class *)[NSString class];
NSLog(@"%p,%p",obj_1,obj_2);
  • main.m 引入#import “objc-private.h” // 会报错
  • main.m -> main.mm 因为 objc-private.h 是objetive-c++类型的
  • CrashReporterClient.h 报错 -> 同 objc-706 工程类似处理,在 buildsetting ,设置LIBC_NO_LIBCRASHREPORTERCLIENT
  • objc-probes.h file not found => 从网上找到文件放到工程的 include 目录,并在 debug-objc 添加 $(SRCROOT)/include
  • maptable.h file not found(<objc/maptable.h>) => 从网上找到文件后放到工程的 include/objc(目录没有要创建)
  • 编译成功

截图如下:

参考

CentOS远程登陆SSH配置 越狱环境下iOS如何制作.deb类型的应用
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×