这章咱们继续探索,日常最常用的引进头文件,pch文件及module原理。

一、头文件与PCH

1、引进头文件

一般引进头文件的方法有两种:#include 和 #import
常见问题:#include 和 #import有什么区别呢?

  • #include:会把.h文件直接copy到你运用的.m中(header search path=一组目录+vc.h=完好途径)
  • #import:和include的区别是,仅有性现已引进过的不会在引进了。(import = include + pargam once = 仅有完好途径)

iOS工程06头文件PCH及module原理
iOS工程06头文件PCH及module原理
大约复习一下编译进程如上图:(如需了解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进来。

咱们来手动编译一次:

iOS工程06头文件PCH及module原理

clang -x c-header -c ./Zoo.pch - o ./Zoo.pch.gch

运转指令检查生成产品:

iOS工程06头文件PCH及module原理
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 只有预编译阶段。

检查生成文件:

iOS工程06头文件PCH及module原理

LLVM IR

  • Bitcode (.bc)
  • Text Format (.ll)
  • 这两种格局的文件能够彼此转化:
  • llvm-dis: .bc -> .ll
  • llvm-asm: .ll -> .bc
  • 两种文件都是全量无损文件,可在此阶段进行优化
  • 假如需求做优化,或许修正bitcode,或许编写pass,都需求了解IR

clang : 默许运转的是内部的driver

-cc1:前端选项仅供 clang 开发人员运用。用户不应该直接运转,由于不能确保选项是安稳的

Header

  1. pch:Precompiled Header,大局可⻅性,不需求导
  2. modulemap:描述了⼀组Precompiled Header,需求导⼊你需求的

iOS工程06头文件PCH及module原理

要现实优化把.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

iOS工程06头文件PCH及module原理
.idx 便是记录各个模块pcm的次序,安idx的记录次序加载。

优化关键

  1. 将App代码尽量涣散到组件中,削减pch文件的运用
  2. 尽量运用framework,自动生成
  3. 对.a敞开module
  4. 对遗失的无法正常运用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

编译运转经过:

iOS工程06头文件PCH及module原理

总结

  • #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文件。