iOS高级进阶:链接与Symbol

系列文章:iOS高级进阶

前言

本篇文章学习的主要内容为:多环境配置,xconfig文件冲突解决,Mach-O与链接器,符号的种类与作用,strip命令

一、多环境配置

  • Project:包含了项目所有的代码,资源文件,所有信息。
  • Targets:对指定代码和资源文件的具体构建方式。
  • Scheme:对指定Target的环境配置。

我们创建好项目,项目默认两个环境DebugRelease环境,在开发过程中我们也会有两套或者多套服务器环境,每个环境的地址不同,粗糙的写法就是如下图所示:

1
2
3
4
5
#if DEBUG
//开发环境
#else
//正式环境
#endif

它只能满足两种环境,无法适应多环境,下面我们介绍几种多环境配置方法

(一)Targets进行多环境配置:

1.在项目时可以创建多个Target,复制一个target,成为新的dev_target

2.修改一下新的target 的 bundle Id

3.修改一下新的target的info.plist文件

4.两个target 都可以运行,并且是不同的项目,可以通过 配置不同 的icon 进行区分

5.在build setting 中 设置宏

5.1 OC宏配置

image-20220402100116578

5.2 swift 宏配置

image-20220402100001778

1
2
3
4
5
6
7
//开发环境
#if DEVELOPMENT == 1

//生产环境
#elif TARGET_VERSION == 0

#endif

6.总结

这种多环境配置有一个缺点: 会存在多info.plst文件,环境多了,配置会比较乱

(二)对指定Target进行多Schems的环境配置,进行不同的环境编译:

1.在Project中,首先添加需要的 Configuraction

image-20220401154815934

2.创建不同的schems,指定他们的Build Configuraction

image-20220401152503039

image-20220401152549890

image-20220401152612833

3.在build setting 中 设置宏

image-20220401142048234

1
2
3
4
5
6
7
8
9
10
//开发环境 可编译不同的请求地址
#if TARGET_VERSION == 0

//生产环境
#elif TARGET_VERSION == 1

//测试环境
#elif TARGET_VERSION == 2

#endif

4.这样可以愉快的开发了

总结:这种方式虽然不会存在多info.plst文件,但是环境多了,配置会比较乱, 修改的代码都在一起,影响主工程代码(这里可以开分支开发,不污染主分支,最后合并代码)

(三).xcconfig多环境配置:

初始.xcconfig

xcconfig文件正如其名字一样,就是xcode里的config文件。 我们在开发过程中,需要配置一些参数,这些都可以在xcode工程的setting对项目进行配置,xcconfig就是将这些配置项以文件的形式独立出来,方便共享与配置。比如两个项目用到相同的配置,那么只需要在xcode中选择对应的xcconfig文件即可,方便与灵活共,我们经常使用的 cocoapods 对第三方进行管理,其实就是通过.xcconfig文件进行管理的,创建好cocoapods会自动根据环境帮我们生成好.xcconfig文件。

.xcconfig文件内容是已Key-Value形式存在,’=’左侧是key值,右侧为value值

1、创建config文件

image-20220402102300444

注意命名规则:.xcconfig文件所在的文件夹名称+项目名称+.环境名称

2、编辑文件内容:

image-20220402102823762

3、回到Project中,将配置文件和schems 关联起来

image-20220402102642693

4、在info.plist中,配置

image-20220402220838584

5.需要在 Build Settings 中的 User-Defined 添加 自定义宏定义

image-20220404104617855

6、在项目中简单使用

1
2
3
4
5
6
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSString *path = [NSBundle.mainBundle pathForResource:@"Info" ofType:@"plist"];
NSDictionary *infoDic = [[NSDictionary alloc] initWithContentsOfFile:path];
NSLog(@"%@",infoDic[@"HOST_URL"]);
return YES;
}

总结:这种设置方式要比上面的简化了不少,但是.xcconfig文件的功能不只有这些,下面我们扩展一下

二、xconfig扩展与文件冲突解决

(一).xcconfig扩展

上面我们介绍了简单的配置URL.xcconfig文件是可以配置Build Settings里面的内容,比如我们平时配置动态库,静态库时,要配置到Other Link Flags,通过.xcconfig我们可以直接配置,例如:我们配置AFN

  • 在.xcconfig中写如下代码
1
2
HOST_URL=127.0.0.1
OTHER_LDFLAGS = -framework "AFNetworking"
  • 项目build之后,在Build Settings中查看 Other Link Flags,发现写的已经配置进去了
  • 过上面的操作我们可以知道,Build Settings的所有配置都是可以通过.xcconfig文件进行管理的。我们来解释下.xcconfig的内容:OTHER_LDFLAGS是Build Settings里面的一个缩写,其它设置缩写是什么呢?
  • 推荐个地址:Xcode Build Settings
  • 比如我们想配置Header Search Paths,它对应的缩写:HEADER_SEARCH_PATHS

(二).xcconfig文件冲突

问题一

我们项目都会通过cocoapods管理第三方,最开始介绍.xcconfig的时候,说了pods会自动帮我们生成.xcconfig文件,那此时项目中就会有4个.xccongig文件,直接运行会报错

解决办法:在我们自己的xccongig文件中,通过 #include 引入cocoapods的xccongig文件

1
2
3
4

#include "Pods/Target Support Files/Pods-LoginApp/Pods-LoginApp.debug.xcconfig"
HOST_URL = 127.0.0.1
OTHER_LDFLAGS = -framework "AFNetworking"

问题二

我们看到Pods生成的.xcconfig里也会有OTHER_LDFLAGS,我们自己写的.xcconfig也存在OTHER_LDFLAGS,我们再去看下项目的Other Linker Flags,发现Pods生成的.xcconfig没有生效,那么怎么才能让我们写的和Pods生成的都生效呢?

  • 使用 inherited 进行集成

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    #include "Pods/Target Support Files/Pods-LoginApp/Pods-LoginApp.debug.xcconfig"

    HOST_URL = 127.0.0.1

    // ld
    // key-value
    // OTHER_LDFLAGS 缩写
    OTHER_LDFLAGS = $(inherited) -framework "AFNetworking"
    HEADER_SEARCH_PATHS = /use/info/inclue

总结

我们通过.xcconfig对项目进行配置,我们可以通过.xcconfig+Scheme方式进行统一管理,这样既省时,又省事。

三、Mach-O与链接器

Mach-O初识

【Mach-O定义】:Mach-O(Mach Object)macOS、iOS、iPadOS存储程序和库文件格式。对应系统通过应用二进制接口(application binary interface,缩写为ABI)来运行该格式的文件

Mach-O格式用来替代BSD系统a.out格式Mach-O文件格式保存了在编译过程和链接过程产生机器代码和数据,从而为静态链接动态链接的代码提供单一文件格式

查看项目的Mach-O文件

1、当我们运行项目是,项目会生成一个.app文件

image-20220406164421333

2、右击查看包内容,会发现里面有个可执行文件,这个就是mach-o文件

image-20220406164827102

3、通过 file 命令来查看MachODome文件类型(这里用的真机,所以是arm64架构。)

image-20220406164755322

执行文件的调用过程大致如下:

1.调用fork函数,创建一个process

2.调用execve或其衍生函数,在该进程上加载,执行我们的Mach-O文件 当我们调用时execve(程序加载器),内核实际上在执行以下操作:

  • 1.将文件加载到内存
  • 2.开始分析Mach-O中的mach_header,以确认它是有效的Mach-O文件

分析Mach-O文件

Mach-O组成
1. Mach-O 结构:

image-20220406173248660

Mach-O的主要组成部分:Mach HeaderLoad CommandData(__TEXT、__DATA、符号表)

2. Mach Header

Mach Header 里有 Mach-OCUP信息,以及Load Command的信息。可以使用 otoolobjdump 命令来查看

  • otool命令:otool -v -h MachODome
  • objdump命令:objdump --macho --private-headers MachODome

下面就是使用objdump命令,查看的详情结果如下:在改文件中已经指定好项目入口,和已经需要引用的系统依赖库信息:

image-20220406171657395

image-20220406171330447

image-20220406171408888

3. Load Command

Load Command 包含 Mach-O里的命令类型信息,名称和二进制文件的位置(类似一本书的目录)。同样可以使用 otoolobjdump 命令来查看

  • otool:otool -v -l a.out
  • objdump: objdump --macho --private-headers MachOApp(注意这里是 headers)
  • 结果如下:

image-20220406172011378

4. Data

DataSegment 的数据组成,是 Mach-O 占比最多的部分,有代码有数据,比如符号表(类似一本书的具体内容)。

Data 共三个 Segment__TEXT、__DATA、__LINKEDIT。其中 __TEXT__DATA 对应一个或多个 Section__LINKEDIT 没有 Section,需要配合 LC_SYMTAB 来解析 symbol tablestring table。这些里面是 Mach-O 的主要数据。

使用 xcrun size 命令来查看 Data 内容的分部

  • xcrun size 命令:xcrun size -x -l -m MachOApp
  • 结果如下:

四、符号的种类与作用

五、strip命令