美文网首页
iOS 编译与链接五:import,search Path和hm

iOS 编译与链接五:import,search Path和hm

作者: Trigger_o | 来源:发表于2022-08-09 17:40 被阅读0次

一:从include开始

首先看看include做了什么,新建一个app项目,语言选择OC,然后把main.m里的代码注了;
新建一个A.h和A.c
A.h不用引入任何头文件,定义一个变量a, 一个结构体mach_header,两个宏定义

//A.h

struct mach_header {
    int magic;
};

#define MH_MAGIC  114
#define MH_CIGAM  514

A.c用include引入A.h ,然后添加一个main函数

//A.c
#include "A.h"

int main(){
    return MH_MAGIC + MH_CIGAM;
}

接下来用clang -E看看预编译做了什么

clang -E A.c

输出

# 1 "A.c"
# 1 "<built-in>" 1
# 1 "<built-in>" 3
# 400 "<built-in>" 3
# 1 "<command line>" 1
# 1 "<built-in>" 2
# 1 "A.c" 2

# 1 "./A.h" 1

struct mach_header {
    int magic;
};
# 9 "A.c" 2

int main(){
    return 114 + 514;
}

可以看到,除去#注释,做了两件事:
1.把.h的东西copy进来
2.替换了宏定义

这种copy非常无脑,重复的引用就会重复的copy,可以试一下看看会发生什么;
分别创建BCD的.h和.c文件,.h里内容全部注释
然后在B.h和C.h里#include "A.h";
在D.h里#include "B.h",#include "C.h"

//A.h
struct mach_header {
    int magic;
};

#define MH_MAGIC  114
#define MH_CIGAM  514

//B.h
#include "A.h"

//C.h
#include "A.h"

//D.h
#include "C.h"
#include "B.h"

然后编译,可以看到A.h中报错,Redefinition of 'mach_header',
重复定义的mach_header. copy两遍当然会重复定义.

import也是做的和include一样的事,但是它可以防止重复的引入,就是通过这样一种结构来实现的

#ifndef A_h
#define A_h

//h的具体内容

#endif

这是一种编译器约定用法,A_h是一个标记,ifndef表示如果没有这个标记,那么就define定义这个标记,标记是唯一的,一般命名为"文件名_h"

实际上现在Xcode创建C文件已经自带这个了,刚才都特意注释的,也就是说include加上这个结构就可以防止重复的引用
而用import可以直接实现这个效果,并且没有显式的#ifndef.

所以现在下面这两种情况都可以编译成功
1.给A.h加ifndef

#ifndef A_h
#define A_h

struct mach_header {
    int magic;
};

#define MH_MAGIC  114
#define MH_CIGAM  514

#endif /* A_h */

2.把include都换成import,同时A.h也不必加ifndef了

//B.h
#import "A.h"

//C.h
#import "A.h"

//D.h
#import "B.h"
#import "C.h"

二:import "" 和import <>

先增加一个文件夹,创建一个E.m和E.h


增加一个物理文件夹

既然include和import是拷贝内容,那么编译器就得找到这个文件.
build setting -> search paths中有一个 use header maps,默认是开启的,先把它关了
然后在A.c添加

#import "E.h"

编译,报错 'E.h' file not found

改成

#import "RealFolder/E.h"

这样就不报错了,因为引入头文件本来是需要相对路径的.
而use header maps所做的,就是生成一份"头文件"->"相对路径"的隐射文件,项目中创建的所以的头文件都会添加进去,
当import时,编译器通过隐射去找路径.
当关闭use header maps时,引入头文件就需要补充相对路径;

不写相对路径也行,Xcode还有其他方案search方案,那就是Header search paths和user header search paths


image.png

首先两者添加的方式是一样的,添加一个路径,比如$(PROJECT_DIR)/CommonProject_OC/RealFolder,可以添加多条.
其次这两者的区别很小,对于用户添加的头文件,包括库,对于其路径:
添加在Header search paths的,import "" 和import <>都可以引入;
添加在user header search paths的,只能import "" 引入
另外还有一个废弃的always search user paths,如果设置true,也是一样import "" 和import <>都可以引入

现在在user header search paths中添加$(PROJECT_DIR)/CommonProject_OC/RealFolder
现在引入#import "E.h"就可以编译成功了.
换成会#import <E.h> 会报错 'E.h' file not found with <angled> include; use "quotes" instead

use header maps不会作用于Framework search paths和library search paths,这俩要分别设置,一般add进来就会自动设置.

cocoapods (use Framework)会在header search path和framework search path都添加


image.png

所以这三种都可以

#import "AFNetworking.h"
#import <AFNetworking.h>
#import <AFNetworking/AFNetworking.h>

二.hmap文件

打开use header maps,编译,查看编译记录,搜索hmap


image.png

然后打开路径


image.png
每个target都会生成一个.build文件夹,因此cocoapods会更多.每个.bulid里有6个.hmap文件

这个hmap文件就是前面说到的隐射表,是一个二进制文件,用来提高头文件的查找速度,是这样一种结构.
HeaderMapTypes.h

image.png

hmap由HMapHeader, HMapBucket和头文件的内容字符串组成
HMapHeader是一些描述信息,包含几个HMapBucket
HMapBucket由key,prefix和suffix组成,key是头文件的名称,可能是ViewController.h或者AFNetworking/AFSecurityPolicy.h,
prefix是文件夹路径,suffix是文件名.pre-suff就是文件路径.
几个头文件对应几个bucket,通过在偏移对应到文件具体的位置,和mach-o类似.

可以用brew安装hmap工具来查看:

brew install milend/taps/hmap

查看内容

hmap print  .../xxx.hmap

输出

A.h -> /Users/trigger/Demo/CommonProject_OC/CommonProject_OC/A.h
AppDelegate.h -> /Users/trigger/Demo/CommonProject_OC/CommonProject_OC/AppDelegate.h
B.h -> /Users/trigger/Demo/CommonProject_OC/CommonProject_OC/B.h
C.h -> /Users/trigger/Demo/CommonProject_OC/CommonProject_OC/C.h
D.h -> /Users/trigger/Demo/CommonProject_OC/CommonProject_OC/D.h
E.h -> /Users/trigger/Demo/CommonProject_OC/CommonProject_OC/RealFolder/E.h
FirstObjc.h -> /Users/trigger/Demo/CommonProject_OC/CommonProject_OC/FirstObjc.h
SceneDelegate.h -> /Users/trigger/Demo/CommonProject_OC/CommonProject_OC/SceneDelegate.h
SecondObjc.h -> /Users/trigger/Demo/CommonProject_OC/CommonProject_OC/SecondObjc.h
ViewController.h -> /Users/trigger/Demo/CommonProject_OC/CommonProject_OC/ViewController.h

相关文章

网友评论

      本文标题:iOS 编译与链接五:import,search Path和hm

      本文链接:https://www.haomeiwen.com/subject/bcvwwrtx.html