iOS 编译与链接一:编译的过程

手机游戏开发者 2024-9-28 22:55:10 81 0 来自 中国
一:编译器

编译器是什么已不消多说,一句话从代码到呆板码就是编译器的工作.


左边输入源码,右边输出呆板码
Frontend表现前端,重要负责词法分析、语法分析、语义分析、生成中心代码.这时就会举行各种查抄,会报错大概告诫.
Optimizer表现优化器,负责中心代码的优化,去除冗余代码,优化布局
Backend表现后端,生成呆板码,而且举行链接,也就是将差异的二进制文件归并成一个可实行文件.
1.LLVM
Xcode5之后完全利用LLVM作为编译器.

2.png
LLVM也是上面说的那种Frontend ->  Optimizer ->Backend架构.
不外LLVM路子很野,可以有很多个接口,也就是前端(Frontend),每一种前端对应一种或多种语言,这些前端终极都会生成雷同的中心代码,叫做LLVM IR;
优化器的从始至终只处理处罚LLVM IR.
新增一个前端不须要对LLVM的优化器举行调解,只须要新增一个前端; 增长一个新的平台只须要增长一个后端即可.
相比力而言,GCC就支持一个新的前端大概后端就要贫困的多,本来的GCC眷属(C,C++,OC),以及Java、.NET、Python、Ruby等都可以利用LLVM编译.
LLVM IR有3种表现情势,
存在内存中.
存在硬盘中的.ll代码文件,可以阅读.
存在硬盘中的二进制文件,扩展名是.bc,也就是bitcode.
2.Clang
Clang就是一个LLVM前端,负责将C,C++,OC翻译成LLVM IR.
Clang的工作内容:
预处理处罚, 去掉解释,头文件的引用关系,把宏界说对应到各个位置
静态分析,给堕落误信息,告诫信息和修复方案
词法分析,这里会把代码切成一个个 Token,括号,符号,关键字等等都被切割出来
语法分析,验证语法是否精确,将全部节点构成抽象语法树AST
生成 LLVM IR, CodeGen会负责将语法树自顶向下遍历渐渐翻译成 LLVM IR
3.Swift
同样LLVM中还须要一个前端负责对 Swift 源代码举行静态分析和纠错,并转换为 LLVM IR,这个前端也叫swift.
不外swift比clang的过程要复杂一些,多了一个生成SIL的过程.
Swift的工作内容:
导入Clang模块并将它们导出的OC API 映射到相应的 Swift API
分析生成AST
生成SIL,将颠末类型查抄的 AST 降级为 SIL
优化SIL,为程序实行额外的高级 Swift 特定优化,包罗主动引用计数优化,假造化和通用专业化
将 SIL 降级到 LLVM IR
二.编译流程

引用戴铭老师的例子走一遍,原文
1.编译一个main.m
装了Xcode就自带LLVM,可以直接试一试.
创建一个项目,覆盖main.m的代码
#import <Foundation/Foundation.h>#define DEFINEEight 8#pragma 这是标志//这是解释int main(){    @autoreleasepool {        int eight = DEFINEEight;        int six = 6;        NSString* site = [[NSString alloc] initWithUTF8String:"starming"];        int rank = eight + six;        NSLog(@"%@ rank %d", site, rank);    }    return 0;}运行:
clang -ccc-print-phases main.m输出:
               +- 0: input, "main.m", objective-c            +- 1: preprocessor, {0}, objective-c-cpp-output         +- 2: compiler, {1}, ir      +- 3: backend, {2}, assembler   +- 4: assembler, {3}, object+- 5: linker, {4}, image6: bind-arch, "arm64", {5}, image第0步引入文件
第1步预编译,输出c++文件
第2步编译为LLVM IR文件
第3步输出汇编文件
第4步输出二进制文件
第5步链接各二进制文件
第6步根据架构输出对应可实行文件
实行:
clang -E main.m输出了非常多的东西,由于导入了foundation,先看末了几行
# 1 "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/Foundation.framework/Headers/FoundationLegacySwiftCompatibility.h" 1 3# 187 "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/Foundation.framework/Headers/Foundation.h" 2 3# 22 "main.m" 2#pragma 这是标志int main(){    @autoreleasepool {        int eight = 8;        int six = 6;        NSString* site = [[NSString alloc] initWithUTF8String:"starming"];        int rank = eight + six;        NSLog(@"%@ rank %d", site, rank);    }    return 0;}除了foundation,还可以看到DEFINEEight被替换成了8,解释没了,但是#pragma还在
以是预编译就做了这些事:导入文件,去除解释,替换宏界说.
这一步会生成main.cpp文件,在main.m的同一起径.几万行代码,在末了可以找到替换为C++的main函数
int main(){    /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;         int eight = 8;        int six = 6;        NSString* site = ((NSString * _Nullable (*)(id, SEL, const char * _Nonnull))(void *)objc_msgSend)((id)((NSString *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSString"), sel_registerName("alloc")), sel_registerName("initWithUTF8String:"), (const char *)"starming");        int rank = eight + six;        NSLog((NSString *)&__NSConstantStringImpl__var_folders_y4_681pp9bd3c31j1_m0jqnt4h00000gn_T_main_3eda9c_mi_0, site, rank);    }    return 0;}接下来是词法分析
实行:
clang -fmodules -fsyntax-only -Xclang -dump-tokens main.m输出
annot_module_include '#import <Foundation/Foundation.h>#define DEFINEEight 8#pragma 这是标志//这是解释int main(){    @autoreleasepool {        int eight = DEFINEEight;        int six = 6;        NSString* site = [[NSString alloc] initWithUTF8String:"starming"];        int rank = eight + six;        NSLog(@"%@ rank %d", site, rank);    }    return 0;}@???W?\?V?A?`'      Loc=<main.m:21:1>int 'int'    [StartOfLine]  Loc=<main.m:26:1>identifier 'main'    [LeadingSpace] Loc=<main.m:26:5>l_paren '('     Loc=<main.m:26:9>r_paren ')'     Loc=<main.m:26:10>l_brace '{'     Loc=<main.m:26:11>at '@'   [StartOfLine] [LeadingSpace]   Loc=<main.m:27:5>identifier 'autoreleasepool'        Loc=<main.m:27:6>l_brace '{'  [LeadingSpace] Loc=<main.m:27:22>int 'int'    [StartOfLine] [LeadingSpace]   Loc=<main.m:28:9>identifier 'eight'   [LeadingSpace] Loc=<main.m:28:13>equal '='    [LeadingSpace] Loc=<main.m:28:19>numeric_constant '8'     [LeadingSpace] Loc=<main.m:28:21 <Spelling=main.m:22:21>>semi ';'        Loc=<main.m:28:32>int 'int'    [StartOfLine] [LeadingSpace]   Loc=<main.m:29:9>identifier 'six'     [LeadingSpace] Loc=<main.m:29:13>equal '='    [LeadingSpace] Loc=<main.m:29:17>numeric_constant '6'     [LeadingSpace] Loc=<main.m:29:19>semi ';'        Loc=<main.m:29:20>identifier 'NSString'    [StartOfLine] [LeadingSpace]   Loc=<main.m:30:9>star '*'        Loc=<main.m:30:17>identifier 'site'    [LeadingSpace] Loc=<main.m:30:19>equal '='    [LeadingSpace] Loc=<main.m:30:24>l_square '['     [LeadingSpace] Loc=<main.m:30:26>l_square '['        Loc=<main.m:30:27>identifier 'NSString'       Loc=<main.m:30:28>identifier 'alloc'   [LeadingSpace] Loc=<main.m:30:37>r_square ']'        Loc=<main.m:30:42>identifier 'initWithUTF8String'  [LeadingSpace] Loc=<main.m:30:44>colon ':'       Loc=<main.m:30:62>string_literal '"starming"'     Loc=<main.m:30:63>r_square ']'        Loc=<main.m:30:73>semi ';'        Loc=<main.m:30:74>int 'int'    [StartOfLine] [LeadingSpace]   Loc=<main.m:31:9>identifier 'rank'    [LeadingSpace] Loc=<main.m:31:13>equal '='    [LeadingSpace] Loc=<main.m:31:18>identifier 'eight'   [LeadingSpace] Loc=<main.m:31:20>plus '+'     [LeadingSpace] Loc=<main.m:31:26>identifier 'six'     [LeadingSpace] Loc=<main.m:31:28>semi ';'        Loc=<main.m:31:31>identifier 'NSLog'   [StartOfLine] [LeadingSpace]   Loc=<main.m:32:9>l_paren '('     Loc=<main.m:32:14>at '@'      Loc=<main.m:32:15>string_literal '"%@ rank %d"'       Loc=<main.m:32:16>comma ','       Loc=<main.m:32:28>identifier 'site'    [LeadingSpace] Loc=<main.m:32:30>comma ','       Loc=<main.m:32:34>identifier 'rank'    [LeadingSpace] Loc=<main.m:32:36>r_paren ')'     Loc=<main.m:32:40>semi ';'        Loc=<main.m:32:41>r_brace '}'  [StartOfLine] [LeadingSpace]   Loc=<main.m:33:5>return 'return'  [StartOfLine] [LeadingSpace]   Loc=<main.m:34:5>numeric_constant '0'     [LeadingSpace] Loc=<main.m:34:12>semi ';'        Loc=<main.m:34:13>r_brace '}'  [StartOfLine]  Loc=<main.m:35:1>eof ''      Loc=<main.m:35:2>可以看出词法分析只须要处理处罚main.m中的代码,把全部的字符串,符号,括号都拆分开,拆出来的每一个部分,叫做token.
在接下来是语法分析
实行:
clang -fmodules -fsyntax-only -Xclang -ast-dump main.m输出
-FunctionDecl 0x15ab12390 <line:26:1, line:35:1> line:26:5 main 'int ()'  `-CompoundStmt 0x15b026d48 <col:11, line:35:1>    |-ObjCAutoreleasePoolStmt 0x15b026d00 <line:27:5, line:33:5>    | `-CompoundStmt 0x15b026cc8 <line:27:22, line:33:5>    |   |-DeclStmt 0x15ab12530 <line:28:9, col:32>    |   | `-VarDecl 0x15ab124a8 <col:9, line:22:21> line:28:13 used eight 'int' cinit    |   |   `-IntegerLiteral 0x15ab12510 <line:22:21> 'int' 8    |   |-DeclStmt 0x15ab4e6f8 <line:29:9, col:20>    |   | `-VarDecl 0x15ab12560 <col:9, col:19> col:13 used six 'int' cinit    |   |   `-IntegerLiteral 0x15ab125c8 <col:19> 'int' 6    |   |-DeclStmt 0x15b024be8 <line:30:9, col:74>    |   | `-VarDecl 0x15ab4e750 <col:9, col:73> col:19 used site 'NSString *' cinit    |   |   `-ObjCMessageExpr 0x15ab50b90 <col:26, col:73> 'NSString * _Nullable':'NSString *' selector=initWithUTF8String:    |   |     |-ObjCMessageExpr 0x15ab4eb58 <col:27, col:42> 'NSString *' selector=alloc class='NSString'    |   |     `-ImplicitCastExpr 0x15ab50b78 <col:63> 'const char * _Nonnull':'const char *' <NoOp>    |   |       `-ImplicitCastExpr 0x15ab50b60 <col:63> 'char *' <ArrayToPointerDecay>    |   |         `-StringLiteral 0x15ab4ebc8 <col:63> 'char [9]' lvalue "starming"    |   |-DeclStmt 0x15b0252a8 <line:31:9, col:31>    |   | `-VarDecl 0x15b024c18 <col:9, col:28> col:13 used rank 'int' cinit    |   |   `-BinaryOperator 0x15b024d20 <col:20, col:28> 'int' '+'    |   |     |-ImplicitCastExpr 0x15b024cf0 <col:20> 'int' <LValueToRValue>    |   |     | `-DeclRefExpr 0x15b024c80 <col:20> 'int' lvalue Var 0x15ab124a8 'eight' 'int'    |   |     `-ImplicitCastExpr 0x15b024d08 <col:28> 'int' <LValueToRValue>    |   |       `-DeclRefExpr 0x15b024cb8 <col:28> 'int' lvalue Var 0x15ab12560 'six' 'int'    |   `-CallExpr 0x15b026c48 <line:32:9, col:40> 'void'    |     |-ImplicitCastExpr 0x15b026c30 <col:9> 'void (*)(id, ...)' <FunctionToPointerDecay>    |     | `-DeclRefExpr 0x15b0252c0 <col:9> 'void (id, ...)' Function 0x15b024d48 'NSLog' 'void (id, ...)'    |     |-ImplicitCastExpr 0x15b026c80 <col:15, col:16> 'id':'id' <BitCast>    |     | `-ObjCStringLiteral 0x15b025340 <col:15, col:16> 'NSString *'    |     |   `-StringLiteral 0x15b025318 <col:16> 'char [11]' lvalue "%@ rank %d"    |     |-ImplicitCastExpr 0x15b026c98 <col:30> 'NSString *' <LValueToRValue>    |     | `-DeclRefExpr 0x15b025360 <col:30> 'NSString *' lvalue Var 0x15ab4e750 'site' 'NSString *'    |     `-ImplicitCastExpr 0x15b026cb0 <col:36> 'int' <LValueToRValue>    |       `-DeclRefExpr 0x15b025398 <col:36> 'int' lvalue Var 0x15b024c18 'rank' 'int'    `-ReturnStmt 0x15b026d38 <line:34:5, col:12>      `-IntegerLiteral 0x15b026d18 <col:12> 'int' 0这一步会查抄语法的精确性,给出告诫,报错,以及修改发起.生成的内容叫做抽象语法树AST.
生成AST之后就可以开始生成IR代码了
实行:
clang -O3 -S -fobjc-arc -emit-llvm main.m -o main.ll输出main.ll文件,路径和main.m雷同,是可读的.
这里"-O3"是LLVM的优化策略,有-O1,-O3,-Os,也可以不设置.
如果设置了bitcode,还可以进一步优化.
接下来生成汇编
clang -S -fobjc-arc main.m -o main.s生成目的文件
clang -fmodules -c main.m -o main.o生成可实行文件并实行
clang main.o -o main./main输出
starming rank 142.从Xcode观察编译过程
这里的过程可以在buildsetting,Build Phases 和 Build Rules中举行设置

3.png 起首是预编译,可以看到new build system等内容.

然后是编译cocoapods的targets,包罗创建framework(cocoapods利用use framework),copy头文件,以及编译.m文件

5.png 接下来是主target,其实是与cocoapods的targes划一的,这一步主target也会被打包成framework.
也是拷贝.h文件,编译swift文件,编译.m文件,编译xib文件,拷贝资源文件,

6.png 接下来实行cocoapods脚本,Build Phases的脚本.

7.png 末了拷贝swift尺度库以及署名.

每一个都可以点开详情.
好比编译.m文件可以看到clang信息,这些根本是可以在build setting中举行设置的.
前面是CompileC任务形貌
然后是切换路径
末了clang -x objective-c -target x86_64-apple-ios12.0-simulator ...就是编译的下令

9.png

  • 编译的流程
    1.处理处罚文件信息
    2.实行CocoaPod编译前脚本
    3.编译.m文件(h文件是不须要编译的),实行clang下令
    4.链接framework
    5.拷贝和编译xib,bundle文件
    6.编译 ImageAssets
    7.处理处罚 info.plist
    8.实行CocoaPod脚本
    9.拷贝Swift尺度库
    10.创建.app文件和署名
3.设置编译选项

  • Build settings设置在build的过程中各个阶段的选项,clang的设置就属于这个范围.
  • Build Phases构建可实行文件的规则,指定 target 的依靠项目,指定在target build之前须要先build的依靠.
    在Compile Source中指定必须编译的文件,这些文件同样会根据Build Setting和Build Rules里的设置来处理处罚.
    在Link Binary With Libraries里会列出全部的静态库和动态库,它们会和编译生成的目的文件链接.
    把静态资源拷贝到bundle里.
    别的还可以通过在build phases里添加自界说脚原来做些变乱,好比像CocoaPods所做的那样.
  • Build Rules指定差异文件类型怎样编译,每条build rule指定了该类型如那边置处罚以及输出在哪,可以增长新规则对特定文件类型添加处理处罚方法.
上面这些都是在Xcode UI中可视化的,这些信息终极须要以文件的格式生存下来,那就是.pbxproj文件,
路径在[项目名称].xcodeproj包里的project.pbxproj.
打开这个文件,在末了一行有一个
rootObject = F7036F002511EC050031CE83 /* Project object */;搜刮这个rootObject ID,可以找到PBXProject section,
这个文件就是以section为单元形貌设置.
/* Begin PBXProject section */        F7036F002511EC050031CE83 /* Project object */ = {            isa = PBXProject;            attributes = {                CLASSPREFIX = XX;                LastUpgradeCheck = 1310;                ORGANIZATIONNAME = XXXX;                TargetAttributes = {                    F7036F072511EC050031CE83 = {                        CreatedOnToolsVersion = 11.6;                        LastSwiftMigration = 1240;                    };                };            };    ...这PBXProject section里找到target
targets = (            F7036F072511EC050031CE83 /* XXXXX */,        );再搜刮这个ID,就可以找到更多设置,这个.pbxproj文件就是以这种id索引的方式举行记载和查找.
好比继续顺着这个ID,可以找到更多的界说,可以看到buildPhases,buildConfiguration.
再顺着找可以看到cocoapods, copy resource等等界说.
/* Begin PBXNativeTarget section */        F7036F072511EC050031CE83 /* XXXXX */ = {            isa = PBXNativeTarget;            buildConfigurationList = F7036F212511EC080031CE83 /* Build configuration list for PBXNativeTarget "XXXXX" */;            buildPhases = (                2E9C3A1138A1AED934114EBC /* [CP] Check Pods Manifest.lock */,                F7036F042511EC050031CE83 /* Sources */,                F7036F052511EC050031CE83 /* Frameworks */,                F7036F062511EC050031CE83 /* Resources */,                34DB7EF940E3C9401AD2798F /* [CP] Embed Pods Frameworks */,                25DB3E569FEFB4DC91CF364D /* [CP] Copy Pods Resources */,            );  ...
您需要登录后才可以回帖 登录 | 立即注册

Powered by CangBaoKu v1.0 小黑屋藏宝库It社区( 冀ICP备14008649号 )

GMT+8, 2024-11-24 21:15, Processed in 0.198555 second(s), 36 queries.© 2003-2025 cbk Team.

快速回复 返回顶部 返回列表