尝试解决从 class-dump 中导出的头文件不能直接编译的问题


#1

在做插件开发的时候,需要声明一些应用中自带的类结构。可以使用 class-dump 直接导出头文件:

class-dump -H executable -o PrivateHeaders

但我在直接拿到 Xcode 中编译的时候会遇到不少错误,总结了几个常见的:

缺少 NSObject.h

生成的许多头文件会包含 #import "NSObject.h" 一行,但生成的目录中没有这个文件。实测可以使用 Foundation/NSObject.h,可以批量替换头文件里的关键字,也可以直接在目录中创建一个 NSObject.h 引入之。

生成的文件名带有 -Protocol 后缀导致不匹配

编译的时候还会遇到大量的头文件找不到的问题,发现 class-dump 给一部分头文件加上了 -Protocol.h 后缀,写一个循环重命名,搞定

selector 中包含 .cxx_destruct

部分 class 的 selector 包含 - (void).cxx_destruct;,删除即可

block 参数

部分头文件方法中会遇到 CDUnknownBlockType 类型,如这个帖子(http://bbs.iosre.com/t/hook-block/3184)。改成 id 可以编译。

如果有其他的问题,等我遇到了再继续补充……

由于 Mac 自带的 sed 功能残缺,需要 brew install gnu-sed

#!/bin/bash
#
# NOTE: You need to `brew install gnu-sed` on Mac
# 
# by @codecolorist
# http://github.com/chichou
# 
# fix some compilation error of headers generated by class-dump
#
# usage: fixheader.sh DIRECTORY


usage() {
  echo "Fix compilation error of headers generated by class-dump"
  echo
  echo "Usage: $0 {PATH}"
}

if [ ! -d "$1" ]; then
  echo "Invalid path $1"
  usage
  exit 1
fi

for filename in $1/*.h; do
  if [ 'Darwin' == $(uname) ]; then
    sed="gsed"
  else
    sed="sed"
  fi

  # remove "- (void).cxx_destruct;"
  # replace "CDUnknownBlockType" with "id"
  # fix missing NSObject.h

  $sed -i -e '/- (void).cxx_destruct;/d' -e "s/\bCDUnknownBlockType\b/id/g" \
    -e "s/#import \"NSObject.h\"/#import <Foundation\/NSObject.h>/" $flag $filename

  # remove -Protocol suffix
  if [[ $filename == *"-Protocol.h" ]]; then
    echo "rename $filename"
    mv "$filename" "${filename%-Protocol.h}.h";
  fi

done;

#2

我是觉得这实际上是class-dump本身的问题。理论上通过提交pull request把原始的类型改放到注释里就好了


#3

你好 xcode8.2是否编译更加严格了?

引入后编译错误,因为引入的头文件有声明方法,没有.m实现,报错如下
Undefined symbols for architecture armv7:
OBJC_CLASS$_CCPersonController”, referenced from:
objc-class-ref in RECC.o
ld: symbol(s) not found for architecture armv7
clang: error: linker command failed with exit code 1 (use -v to see invocation)
老板xcode能通过吗?


#4

都不可以,请动态获取这个类


#5

:cold_sweat: 请问怎么获取呢?头大大


#6

NSClassFromString(@“CCPersonController”)

使用的时候可能需要一些强制类型转换


#7

给力:stuck_out_tongue_closed_eyes:


#8

谢谢你,解决了我的问题;
粘贴您说的这个帖子的代码,

  • (void)getCurrentUserFriendListSuccess:(CDUnknownBlockType)arg1 failure:(CDUnknownBlockType)arg2;
    其实明白成功和失败的操作,改成
  • (void)getCurrentUserFriendListSuccess:(id)arg1 failure:(id)arg2;
    就能hook成功了,
    希望对后面的人有帮助