今天我们来对iOS开发的常用工具Xcode的编译流程进行一个简单的了解和分析

OC:source code > Clang -> LLVM -> Backend -> Executable
Clang做的事情是词法分析-> token流->语法分析-> AST -> LLVM IR
AST(Abstract Syntax Tree 抽象语法树)
IR(intermediate representation 中间代码)
swift:source code > swiftc -> LLVM -> Backend -> Executable
swiftc:swift AST -> Raw Swift IL -> Canonical Swift IL -> LLVM IR
Raw Swift IL : Swift特有的中间代码
Canonical Swift IL:将Raw Swift IL进行降级简化成更加简洁的中间代码版本
swift的编译器前端是swiftc,于Clang相比,LLVM的前端编译过程中,AST和IR之间,多了一层SIL(Swift Intermediate Language),这么做的目的是希望弥补clang编译器的一些缺陷,比如无法执行一些高级分析,可靠的诊断和优化,而 AST 和LLVM IR 都不是合适的选择。因此,SIL应运而生,用来解决现有的缺陷
生成AST的过程
词法分析(lexical analysis)
也叫扫描器,让源代码的字符流根据构词规范生成token流
tokenize:tokenize就是按照一定的规则,例如token令牌(通常代表关键字,变量名,语法符号等),将代码分割为一个个的“串”,也就是语法单元)。涉及到词法解析的时候,常会用到tokennize。
语法分析(parse analysis)是编译过程的一个逻辑阶段。语法分析的任务是在词法分析的基础上将单词序列组合成语法树,如“程序”,“语句”,“表达式”等等.语法分析程序判断源程序在结构上是否正确。源程序的结构由上下文无关文法描述。

AST的转换例子
@property (nonatomic, strong) NSString *haoyuString;
PS:属性(Property)是Objective-C语言的其中一个特性,它把类对象中的实例变量及其读写方法统一的封装
生成的AST如下:
ObjCPropertyDecl 0x7f96f693a400 <line:13:1, col:41> col:41 haoyuString 'NSString *' readwrite nonatomic strong
| |-ObjCMethodDecl 0x7f96f693a478 <col:41> col:41 implicit - haoyuString 'NSString *'
| |-ObjCMethodDecl 0x7f96f693a4f8 <col:41> col:41 implicit - setHaoyuString: 'void'
| | `-ParmVarDecl 0x7f96f693a578 <col:41> col:41 haoyuString 'NSString *'
常见的数据类型声明在AST中表示
NSString *str = @"hahahah"; //oc中赋值代码
AST中的表示为:
VarDecl 0x7fd06cc91ae8 <line:24:5, col:22> col:15 str 'NSString *__strong' cinit //声明局部变量
| | | `-ObjCStringLiteral 0x7fd06cc91ba8 <col:21, col:22> 'NSString *' //声明变量类型
| | | `-StringLiteral 0x7fd06cc91b88 'char [8]' lvalue "hahahah" //右边的字符串有char类型表示
String:StringLiteral
NSInteger ,Int: IntegerLiteral
Float: FloatingLiteral
Array: ObjCArrayLiteral
Dictionary : ObjCDictionaryLiteral
将源代码生成语法树 AST:
clang -fmodules -fsyntax-only -Xclang -ast-dump main.m
生成AST的方式和Clang类似,这里着重介绍下swiftc编译器的SIL(Swift Intermediate Language )
import Foundation
class Teacher {
var age: Int = 18
var name: String = "Tom"
}
var person = Teacher()
person.age = 6
通过终端进入main.swift所在的文件夹,输入如下指令:
swiftc -emit-sil main.swift //生成了main.sil文件
// 打开`main.sil` 文件,首先看到了Teacher的声明
class Teacher {
@_hasStorage @_hasInitialValue var age: Int { get set }
@_hasStorage @_hasInitialValue var name: String { get set }
@objc deinit
init()
}
@_hasStorage @_hasInitialValue var person: Teacher { get set }
// person
sil_global hidden @main.person : main.Teacher : $Teacher
这里声明了Teacher类,并定义了一个全局的person属性,属于Teacher类
每个程序的开始都是main函数,swift语言也不例外,但是swift中的main函数被隐藏了,main.swift文件就代表了整个main函数,在文件里写的代码会在main中运行
// main函数,相当于c程序入口函数int main(int argc, char * argv[])
sil @main : $@convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 {
//%0,%1……在SIL也叫寄存器,这里我们可以理解为我们日常开发的常量,
//一旦赋值之后就不可以在修改,如果SIL中还要继续使用,那么就不断的累加数字
bb0(%0 : $Int32, %1 : $UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>):
//初始化全局变量person alloc_global是创建一个全局变量
alloc_global @main.person : main.Teacher // id: %2
//创建对之前由alloc_global初始化的全局变量地址的引用
//global_addr是拿到全局变量的地址,赋值给%3
%3 = global_addr @main.person : main.Teacher : $*Teacher // users: %7, %8
//元类型Teacher
//metatype是拿到Teacher的Metaldata赋值给%4
%4 = metatype $@thick Teacher.Type // user: %6
// 方法__allocating_init()的引用
//接下来就是将__allocating_init()的函数地址赋值给%5
%5 = function_ref @main.Teacher.__allocating_init() -> main.Teacher : $@convention(method) (@thick Teacher.Type) -> @owned Teacher // user: %6
//调用函数__allocating_init,并传入参数元类型Teacher
//apply是调用函数,这里是调用%5也就是__allocating_init(),%4是参数,并将返回值给%6
%6 = apply %5(%4) : $@convention(method) (@thick Teacher.Type) -> @owned Teacher // user: %7
//将函数__allocating_init的结果存入person的引用
//然后将%6的值存储到%3,也就是我们刚刚创建的全局变量的地址
store %6 to %3 : $*Teacher // id: %7
//开始访问全局变量地址的引用
%8 = begin_access [read] [dynamic] %3 : $*Teacher // users: %9, %11
//将内容载入%9
%9 = load %8 : $*Teacher // users: %16, %14, %15, %10
//引用计数加一
strong_retain %9 : $Teacher // id: %10
//结束访问
end_access %8 : $*Teacher // id: %11
//创建字面量6
%12 = integer_literal $Builtin.Int64, 6 // user: %13
//生成Int值6,swift中Int是结构体
%13 = struct $Int (%12 : $Builtin.Int64) // user: %15
//Teacher.age的setter方法
%14 = class_method %9 : $Teacher, #Teacher.age!setter : (Teacher) -> (Int) -> (), $@convention(method) (Int, @guaranteed Teacher) -> () // user: %15
//调用setter方法,传入Int值6,和类实例本身
%15 = apply %14(%13, %9) : $@convention(method) (Int, @guaranteed Teacher) -> ()
//引用计数减一
strong_release %9 :
//创建字面量0
%17 = integer_literal $Builtin.Int32, 0 // user: %18
//生成Int值0,swift中Int是结构体
%18 = struct $Int32 (%17 : $Builtin.Int32) // user: %19
//最后将0从main函数中返回出去
return %18 : $Int32 // id: %16
} // end sil function 'main'
1.初始化一个引用
//初始化全局变量person
alloc_global @main.person : main.Teacher
//创建对之前由alloc_global初始化的全局变量地址的引用
%3 = global_addr @main.person : main.Teacher
2.调用一个方法
// 方法__allocating_init()的引用
%5 = function_ref @main.Teacher.__allocating_init() -> main.Teacher : $@convention(method) (@thick Teacher.Type) -> @owned Teacher
//调用函数__allocating_init,并传入参数元类型Teacher
%6 = apply %5(%4) : $@convention(method) (@thick Teacher.Type) -> @owned Teacher
3.获得swfit的基本类型
//创建字面量6
%12 = integer_literal $Builtin.Int64, 6
//生成Int值6,swift中Int是结构体
%13 = struct $Int (%12 : $Builtin.Int64)
生成可执行文件:swiftc -o main.out main.swift
生成抽象语法树的命令(AST):swiftc main.swift -dump-ast
生成中间语言(SIL):swiftc main.swift -emit-sil
LLVM中间表示层(LLVM IR):swiftc main.swift -emit -ir
生成汇编语言:swiftc main.swift -emit-assembly
我实际上是在尝试使用RVM在我的OSX10.7.5上更新ruby,并在输入以下命令后:rvminstallruby我得到了以下回复:Searchingforbinaryrubies,thismighttakesometime.Checkingrequirementsforosx.Installingrequirementsforosx.Updatingsystem.......Errorrunning'requirements_osx_brew_update_systemruby-2.0.0-p247',pleaseread/Users/username/.rvm/log/138121
我不知道为什么,但是当我设置这个设置时它无法编译设置:static_cache_control,[:public,:max_age=>300]这是我得到的syntaxerror,unexpectedtASSOC,expecting']'(SyntaxError)set:static_cache_control,[:public,:max_age=>300]^我只想将“过期”header设置为css、javaascript和图像文件。谢谢。 最佳答案 我猜您使用的是Ruby1.8.7。Sinatra文档中显示的语法似乎是在Ruby1.
最近因为项目需要,需要将Android手机系统自带的某个系统软件反编译并更改里面某个资源,并重新打包,签名生成新的自定义的apk,下面我来介绍一下我的实现过程。APK修改,分为以下几步:反编译解包,修改,重打包,修改签名等步骤。安卓apk修改准备工作1.系统配置好JavaJDK环境变量2.需要root权限的手机(针对系统自带apk,其他软件免root)3.Auto-Sign签名工具4.apktool工具安卓apk修改开始反编译本文拿Android系统里面的Settings.apk做demo,具体如何将apk获取出来在此就不过多介绍了,直接进入主题:按键win+R输入cmd,打开命令窗口,并将路
是否有适用于Ruby语言的.NETFramework编译器?我听说过DLR(动态语言运行时),这是否将使Ruby能够用于.NET开发? 最佳答案 IronRuby是Microsoft支持的项目,建立在动态语言运行时之上。 关于.net-是否有Ruby.NET编译器?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/199638/
关闭。这个问题是off-topic.它目前不接受答案。想改进这个问题吗?Updatethequestion所以它是on-topic用于堆栈溢出。关闭10年前。ImprovethisquestionLinux专家正在转向Mac(10.8)。因为我懒...我使用MacPorts安装MacVim。它似乎安装没有错误。我只需要mvim中的python、ruby和perl支持。$/opt/local/bin/mvim--version|egrep'patches|python|ruby|perl'Includedpatches:1-244,246-646+multi_lang-mzscheme+
我已经开始学习Ruby,我已经阅读了一些教程,甚至还买了一本书(“ProgrammingRuby1.9-ThePragmaticProgrammers'Guide”),我遇到了一些以前从未见过的新东西使用我知道的任何其他语言(我是一名PHP网络开发人员)。block和过程。我想我明白它们是什么,但我不明白的是为什么它们如此伟大,以及我应该在何时何地使用它们。我到处都看到他们说block和过程是Ruby中的一个很棒的特性,但我不理解它们。这里有人能给像我这样的Ruby新手一些解释吗? 最佳答案 block有很多好处。电梯演讲:bloc
当我刚刚运行middleman时服务,all.css编译得很好,只包含对+box-shadow(none)的调用:/*line1,/home/yang/asdf/source/stylesheets/content.css.sass*/div{-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;}但是当我构建网站时,我得到了这个Sass/Compass错误:$middlemanbuildSlim::EmbeddedEngineisdeprecated,itiscalledSlim::EmbeddedinSlim2.0
我找遍了所有我能找到的地方,但似乎找不到解决这个问题的办法。我在Lion10.8.2上使用Xcode4.5.1,并尝试为Rails项目运行bundle,但它一直卡在这上面。我正在为Heroku使用Thingem。Bolanos@Jeremys-Mac-mini⦿-1.9.3fishfarm$sudogeminstalleventmachinePassword:Buildingnativeextensions.Thiscouldtakeawhile...ERROR:Errorinstallingeventmachine:ERROR:Failedtobuildgemnativeextens
我知道Ruby是动态和强类型的,但据我所知,由于每个参数缺少显式类型表示法(或契约),当前语法不允许在编译时检查参数类型。如果我想执行编译时类型检查,我有哪些(实际成熟的)选项?更新我的意思是类型检查类似于典型的静态类型语言。比如C。例如,C函数表示每个参数的类型,编译器检查传入的参数是否正确。voidfunc1(structAAAaaa){structBBBbbb;func1(bbb);//Wrongtype.Compiletimeerror.}作为另一个例子,Objective-C通过放置显式类型信息来做到这一点。-(id)method1:(AAA*)aaa{BBB*bbb=[[A
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭7年前。ImprovethisquestionC、Java、C#和Python都是从头编译的。感谢Facebook,PHP现在也可以编译并可以在HHVM上运行,从而提高程序的性能。Ruby不可编译并且比上述语言慢。Ruby有没有可能在未来被编译(就像PHP和HHVM一样)?或者可能有一些原因不能做到?