这章咱们继续探索,日常最常用的引进头文件,pch文件及module原理。
一、头文件与PCH
1、引进头文件
一般引进头文件的方法有两种:#include 和 #import
。
常见问题:#include 和 #import有什么区别呢?
-
#include
:会把.h文件直接copy到你运用的.m中(header search path=一组目录+vc.h=完好途径) -
#import
:和include的区别是,仅有性现已引进过的不会在引进了。(import = include + pargam once = 仅有完好途径)
大约复习一下编译进程如上图:(如需了解LLVM编译进程的点) 源码经过,词法,语法,语义剖析后到的编译进程。
编译器前端(clang)
->source code->Lexer->tokens->parser->AST-> Semantic Analysis->Code Generation
编译器后端(LLVM
)->LLVM IR(一致IR)->AsmPrinter->Assembler->object code->Linker->execuatble file
问题来了,那么improt导入头文件在编译的那个阶段呢?
在AST之前,的预处理阶段。先导入相关引用头文件,在进行语法,词法,语义剖析。
那么假如100个.m文件引进了同一个.h文件,屡次import会进入屡次编译语词剖析流程,这样会消耗编译功能。
那么要怎样优化这一进程呢?
Xcode就引进了PCH,预编译头文件来优化,削减冗余进程:预先生成好ast产品。
预编pch指令
:编译产品目录(.gch)[ast产品]
文件(ast产品 .h内容) ast产品大局的。可是ast产品仍是会被屡次copy到.m中,哪能不能优化把.m需求的ast产品copy进来。
咱们来手动编译一次:
clang -x c-header -c ./Zoo.pch - o ./Zoo.pch.gch
运转指令检查生成产品:
bitcode含义
:1.字节省格局 2.LLVM IR格局 现在生成的gch便是bitcode文件,pcm、gch格局包含了表明AST tree的结构体的bitstream
在LLVM中有专门的东西:llvm-bcanalyzer
来剖析bitcode格局文件。
咱们在来看一个指令:
clang -x c -include-pch include/Zoo.pch.gch -emit-llvm user.m -S
clang –help 检查帮助文档
-S 只有预编译阶段。
检查生成文件:
LLVM IR
- Bitcode (.bc)
- Text Format (.ll)
- 这两种格局的文件能够彼此转化:
- llvm-dis: .bc -> .ll
- llvm-asm: .ll -> .bc
- 两种文件都是全量无损文件,可在此阶段进行优化
- 假如需求做优化,或许修正bitcode,或许编写pass,都需求了解IR
clang
: 默许运转的是内部的driver
-cc1:前端选项仅供 clang 开发人员运用。用户不应该直接运转,由于不能确保选项是安稳的
Header
-
pch
:Precompiled Header,大局可⻅性,不需求导⼊ -
modulemap
:描述了⼀组Precompiled Header,需求导⼊你需求的
要现实优化把.m需求的ast产品从pch.gch->copy进来。就要学习module模块。
二、module原理
module的效果:你用哪一块二进制头文件就给你引进哪个二进制头文件;
1、module模块
怎样办理一组头文件呢?创立 module.modulemap文件。
// 怎样办理一组头文件
// Zoo [Cat Zoo]
module Zoo {
// 子module
module Cat {
header "Cat.h" //引用了其他的module
export * //有运用的模块 都露出 如:#import <Foundation/Foundation.h>
}
module Dog {
header "Dog.h"
}
}
运用创立的module.modulemap文件生成use.o文件
clang -x objective-c -fmodules -fmodule-map-file='./include/module.modulemap' -fmodules-cache-path="./ModuleCache" -c use.m -o use.o
.idx 便是记录各个模块pcm的次序,安idx的记录次序加载。
优化关键
- 将App代码尽量涣散到组件中,削减pch文件的运用
- 尽量运用framework,自动生成
- 对.a敞开module
- 对遗失的无法正常运用module映射的引进hmap*
看一段module 代码,来了解module的用法。
module Zoo {
umbrella header "NZoo.h"//一个头文件的映射
export *
module * { export * }
}
/**
module *
module Cat
module Dog
*/
NZoo.h 办理两个头文件:
#import "Cat.h"
#import "Dog.h"
那怎样在工程中装备运用module文件来编译工程呢?装备.xcconfig
OTHER_CFLAGS = -fmodule-map-file="${SRCROOT}/APP/zoo.modulemap" -fmodules-cache-path="${SRCROOT}/ModuleCache"
GCC_PRECOMPILE_PREFIX_HEADER = YES
GCC_PREFIX_HEADER = prefix.pch
编译运转经过:
总结
-
#include
:会把.h文件直接copy到你运用的.m中(header search path=一组目录+vc.h=完好途径) -
#import
:和include的区别是,仅有性现已引进过的不会在引进了。(import = include + pargam once = 仅有完好途径)
后面咱们了解了,pch 预编译头文件。可是pch 引进太多.h也会导致编译速度变慢,怎样优化呢?经过咱们对llvm编译进程的了解,在编译前端 IR之前,会生成AST产品,咱们操控module 的装备能够优化对AST产品的映射。
module:你用哪一块二进制头文件就给你引进哪个二进制头文件;经过clang -x objective-c -fmodules
指令会生成.idx和pcm文件投射生成对应.m .o文件。