cd ~/Desktop
touch main.m
open main.m
vi main.m
#import <Foundation/Foundation.h>
int main() {
NSLog(@"Hello world");
return 0;
}
clang main.m -o main //直接生成一个可执行文件
错误原因:未识别Foundation框架
Undefined symbols for architecture x86_64:
"_NSLog", referenced from:
_main in main-276b38.o
"___CFConstantStringClassReference", referenced from:
CFString in main-276b38.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
clang -fmodules main.m -o main //-fmodules强转成@import形式
./main //run一下
clear
clang -fmodules -fsyntax-only -Xclang -ast-dump main.m //查看语法树
# 第一部分为环境
TranslationUnitDecl 0x7fec3180a6d0 <<invalid sloc>> <invalid sloc>
|-TypedefDecl 0x7fec3180abc8 <<invalid sloc>> <invalid sloc> implicit __int128_t '__int128'
| `-BuiltinType 0x7fec3180a920 '__int128'
|-TypedefDecl 0x7fec3180ac28 <<invalid sloc>> <invalid sloc> implicit __uint128_t 'unsigned __int128'
| `-BuiltinType 0x7fec3180a940 'unsigned __int128'
|-TypedefDecl 0x7fec3180acb8 <<invalid sloc>> <invalid sloc> implicit SEL 'SEL *'
| `-PointerType 0x7fec3180ac80 'SEL *'
| `-BuiltinType 0x7fec3180ab30 'SEL'
|-TypedefDecl 0x7fec3180ad98 <<invalid sloc>> <invalid sloc> implicit id 'id'
| `-ObjCObjectPointerType 0x7fec3180ad40 'id' imported
| `-ObjCObjectType 0x7fec3180ad10 'id' imported
|-TypedefDecl 0x7fec3180ae78 <<invalid sloc>> <invalid sloc> implicit Class 'Class'
| `-ObjCObjectPointerType 0x7fec3180ae20 'Class'
| `-ObjCObjectType 0x7fec3180adf0 'Class'
|-ObjCInterfaceDecl 0x7fec3180aec8 <<invalid sloc>> <invalid sloc> implicit Protocol
|-TypedefDecl 0x7fec3180b218 <<invalid sloc>> <invalid sloc> implicit __NSConstantString 'struct __NSConstantString_tag'
| `-RecordType 0x7fec3180b030 'struct __NSConstantString_tag'
| `-Record 0x7fec3180af90 '__NSConstantString_tag'
|-TypedefDecl 0x7fec3180b2a8 <<invalid sloc>> <invalid sloc> implicit __builtin_ms_va_list 'char *'
| `-PointerType 0x7fec3180b270 'char *'
| `-BuiltinType 0x7fec3180a760 'char'
|-TypedefDecl 0x7fec32000178 <<invalid sloc>> <invalid sloc> implicit __builtin_va_list 'struct __va_list_tag [1]'
| `-ConstantArrayType 0x7fec32000120 'struct __va_list_tag [1]' 1
| `-RecordType 0x7fec3180b3a0 'struct __va_list_tag'
| `-Record 0x7fec3180b2f8 '__va_list_tag'
# 第二部分为自己的代码部分
|-ImportDecl 0x7fec32000eb0 <main.m:1:1> col:1 implicit Foundation
|-FunctionDecl 0x7fec32000f38 <line:3:1, line:8:1> line:3:5 main 'int ()'
| `-CompoundStmt 0x7fec309f5550 <col:12, line:8:1>
| |-CallExpr 0x7fec309f54d0 <line:5:5, col:25> 'void'
| | |-ImplicitCastExpr 0x7fec309f54b8 <col:5> 'void (*)(id, ...)' <FunctionToPointerDecay>
| | | `-DeclRefExpr 0x7fec309f53a0 <col:5> 'void (id, ...)' Function 0x7fec309ed460 'NSLog' 'void (id, ...)'
| | `-ImplicitCastExpr 0x7fec309f5500 <col:11, col:12> 'id':'id' <BitCast>
| | `-ObjCStringLiteral 0x7fec309f5440 <col:11, col:12> 'NSString *'
| | `-StringLiteral 0x7fec309f5408 <col:12> 'char [12]' lvalue "Hello world"
| `-ReturnStmt 0x7fec309f5538 <line:6:5, col:12>
| `-IntegerLiteral 0x7fec309f5518 <col:12> 'int' 0
`-<undeserialized declarations>
生成汇编
clang -S main.m -o main.s
vi main.s
# 输出
retq
.cfi_endproc
.section __TEXT,__cstring,cstring_literals
L_.str: ## @.str
.asciz "Hello world"
.section __DATA,__cfstring
.align 3 ## @_unnamed_cfstring_
L__unnamed_cfstring_:
.quad ___CFConstantStringClassReference
.long 1992 ## 0x7c8
.space 4
.quad L_.str
.quad 11 ## 0xb
.section __DATA,__objc_imageinfo,regular,no_dead_strip
L_OBJC_IMAGE_INFO:
.long 0
.long 64
.subsections_via_symbols
<img
src = "http://chuantu.biz/t5/38/1476935851x981781122.png"
width = "100%"
align = "center"
</img>
我们能在Clang上做些什么
LibClang
(1)优缺点
1.C API 来访问Clang的上层能力,如获取Tokens、遍历语法树、代码补全、获取诊断信息
2.API稳定,不受Clang源码更新影响
3.只有上层的语法树访问,不能获取到全部信息
(2)LibClang - 如何使用
1.使用原始C API
2.脚本语言:使用官方提供的python binding 或开源的node-js/rubybinding
3.Object-c:开源库ClangKit
(3)LibClang-Demo
@inteface Sark : NSObject
@property (nonatomic , strong) NSString * backgrond;
@end
代码中一些常用单词的拼写错误
<img
src = "http://chuantu.biz/t5/38/1476940990x981781122.png"
width = "100%"
align = "center"
</img>
运行结果
$python property-linter.py main.m
获取正确的提示
typo: backgrond, do you mean: background?
LibTooling
(1)优缺点
1.对语法树有完全的控制权
2.可以作为一个standalore命令单独的使用,如clang-format
3.需要使用C++且对Clang源码熟悉
LibTooling -Demo
@interface Sark : NSObject
@property (nonatomic , copy)NSString *name;
- (void)becomeGay;
@end
实现一个建议的Object-c -> Swift源码转换器
<img
src = "http://chuantu.biz/t5/38/1476941655x981781122.png"
width = "100%"
align = "center"
</img>
创建RecursiveASTVisitor, 在AST中重写感兴趣节点的Visit方法
$objc2swift test.m -- -fsyntax-only -fmodules
转换完毕之后
class Sark: NSObject {<br>
var name: NSString?<br>
func becomeGay() {<br>
}<br>
} <br>
ClangPlugin
优缺点
1.对语法书有完全的控制权
2.作为插件注入到编译流程中,可以影响build和决定编译过程
3.需要使用C++且对Clang源码熟悉