Xcode使用说明书

2021-07-21 » iOS开发进阶

目的:通过理解最原始的文件,更清晰的理解工程、XCode开发平台的运作原理

一、编译前看到的工程相关文件

1、APP.xcodeproj

一个工程的核心部分,本质是个文件、资源、配置的仓库,平时一般是通过xcode可视化看到的

实际可以拆分如下结构:

1.project.pbxproj

一个工程可以包含多个目标(target),每个目标可以对应一个应用程序、一个库或一个测试等。

一个工程中的多个目标可以相互依赖,例如一个库可以被多个应用程序所使用。

// !$*UTF8*$!
/* 每一个对象 可能是文件或者目录或者执行配置项或者虚拟类目(project、target、build parse、buildConfigurations等)
都会有唯一标识(24位十六进制表示的96bit标识码)isa表示当条记录的归属类别,通过唯一标识可能被别的对象关联,也会关联别的对象
{
    archiveVersion = 1;
    classes = {
    };
    objectVersion = 46;
    objects = {
        /* 构建所需的代码文件,资源文件,库文件等 */
        /* 平时git发生冲突也主要是在这个区域内冲突 */
        /* 你每新建一个.h/.m文件,就会修改这个区域, 各个branch都在创建的时候,容易冲突 */
        /* Begin PBXBuildFile section */
		2651FC30716F606082AE0CC2 /* libPods-APP.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 37002917260E91F33522321E /* libPods-APP.a */; };
            ...
        /* End PBXBuildFile section */
        
        /* 这里记录了每个target的targetProxy,与PBXTargetDependency相对应 */
        /* containerPortal 标识 此Target归属的project */
        /* Begin PBXContainerItemProxy  section */
		D6276B65192F2598001272A9 /* PBXContainerItemProxy */ = {
			isa = PBXContainerItemProxy;
			containerPortal = D64CADDF1923516F005721AC /* Project object */;
			proxyType = 1;
			remoteGlobalIDString = D64CADE61923516F005721AC;
			remoteInfo = APP;
		};
            ...
        /* End PBXContainerItemProxy section */
        
        /* 主要记录每个target的BuildPhase中的Embed App Extensions的部分 */
        /* Begin PBXCopyFilesBuildPhase section */
        /* End PBXCopyFilesBuildPhase section */

        /* 记录了每个代码文件的文件类型、路径path、sourceTree,不论引入文件的时候是create group还是create reference,都会在这里添加一条记录 */
        /* Begin PBXFileReference section */
        /* End PBXFileReference section */

        /* 工程中所依赖的Frameworks的信息,对应Build Phases中的`Link Binary With Libraries` */
        /* Begin PBXFrameworksBuildPhase section */
        /* End PBXFrameworksBuildPhase section */

        /* 工程中所有文件的group信息,这个和xcode文件目录是对应的,每一层的文件目录有唯一的UUID,
        同一层group下的子group会和上一层的group的UUID有很高的重合度(基本只有1-2位不同),这个PBXGroup section中,子group没有用树的方式,
        而是采用类似列表的方式呈现了所有的group目录,通过children控制,可以脑补:打开xcode左侧目录,然后让所有目录和文件"左对齐" */
        /* Begin PBXGroup section */ 
        /* End PBXGroup section */

        /* 每个Target的BuildSettings和BuildPhases(Sources/Frameworks/Resources/Script等)的信息 */
        /* Begin PBXNativeTarget section */  
        /* End PBXNativeTarget section */

        /* 整个项目工程Project的信息,包括项目路径、Config信息,相关版本号,所有的Target等信息 */
        /* Begin PBXProject section */
        4B74E19C1AB185A200A5A377 /* Project object */ = {
            isa = PBXProject;
            attributes = { ... };
            ...
            targets = (
                4B74E1A31AB185A200A5A377 /* xxxxPolenTestxxxx */,
                ...
            );
        };
        /* End PBXProject section */

        /* 列举了项目中每个Resources的信息, 包括Build Phase下`Copy Bundle Resources`文件、Assets.xcassets等资源文件 */
        /* Begin PBXResourcesBuildPhase section */
        /* End PBXResourcesBuildPhase section */

        /* 对应Xcode中Build Phases下的脚本文件,包括:Embed Pods Frameworks,Check Pods Manifest.lock以及其他本地或者第三方的脚本文件信息 */
        /* Begin PBXShellScriptBuildPhase section */
        /* End PBXShellScriptBuildPhase section */

        /* 对应Xcode中Build Phases的Complie Sources的代码文件 */
        /* Begin PBXSourcesBuildPhase section */
        /* End PBXSourcesBuildPhase section */

        /* 记录了每个Target的targetProxy,每个targetProxy都是一个PBXContainerItemProxy类型,暂时没找到Xcode中的对应项 */
        /* Begin PBXTargetDependency section */
        /* End PBXTargetDependency section */

        /* 不同地区的资源文件的引用信息,如果你项目使用了国际化,相关的xxx.string就在这个section中 */
        /* Begin PBXVariantGroup section */
        /* End PBXVariantGroup section */

        /* 对应Xcode中 Build Settings中的配置信息 */
        /* Begin XCBuildConfiguration section */
        /* End XCBuildConfiguration section */

        /* XCBuildConfiguration只是列举了所有Target的所有Setting项,下面这个文件区分,不同Target在Debug时使用哪个Setting项,在Release时使用哪个Setting项 */
        /* Begin XCConfigurationList section */
        /* End XCConfigurationList section */
    };
    rootObject = 4B74E19C1AB185A200A5A377 /* Project object */;
}

2.project.xcworkspace

project.xcworkspace 是项目工作区文件,用于组织和管理当前项目,以便于协作开发和构建项目,一般一个项目下是一个工程,但也会有其他情况比如添加了子工程等情况。

在一个工作区中,可以打开多个工程和目标,可以在不同的工程之间共享代码、资源和设置,还可以通过工作区级别的设置来管理构建、运行和调试等操作。

project.xcworkspace里面也会有对这个工作区的用户相关文件(xcshareddata / xcuserdata)和 contents.xcworkspacedata 配置文件

添加删除工程、文件夹、修改工作区设置都会发生配置文件变化

3.xcshareddata / xcuserdata

xcshareddata 文件夹:xcshareddata 文件夹用于存储一些共享数据,例如 Xcode 的代码片段、文件模板、编译器设置等。这些数据可以共享,因为它们不依赖于任何特定的用户或计算机。

xcuserdata 文件夹:xcuserdata 文件夹用于存储一些用户相关的数据,例如 Xcode 的用户偏好设置、代码折叠状态、窗口布局等。这些数据是与特定用户和计算机相关的,因此不能在多个项目之间共享。一般在gitignore 被忽略。

在 Xcode 工程中,每个项目都有一个与之对应的 xcshareddata 和 xcuserdata 文件夹。这些文件夹通常位于工程文件的同一级目录下,例如:

MyProject.xcodeproj/

├── project.pbxproj

├── xcshareddata/

└── xcuserdata/

2、APP.xcworkspace

整个项目的工作空间,通过组合多个工程(Project),实现一个复杂App

xcworkspace 里面是一个或多个工程(project)的 reference,方便协作和管理。project之间是独立的,可以通过Link Libraries的方式实现关联,Xcode在关联上后断点可以直接再对应工程生效,就和我们现在的Pod方式一致

在WeSing这种通过Pod构建的xcworspace里面就是关联了 pod project 和 主工程(APP.project)

<?xml version="1.0" encoding="UTF-8"?>
<Workspace
   version = "1.0">
   <FileRef
      location = "group:APP.xcodeproj">
   </FileRef>
   <FileRef
      location = "group:Pods/Pods.xcodeproj">
   </FileRef>
</Workspace>

3、其他主工程文件

1.Info.plist

Info.plist文件实际上是苹果预定义scheme 的XML文件,配置一些App参数,比如BundleId,BundleName,权限文案等

读取方式: [[NSBundle mainBundle] infoDictionary];  

可以添加自定义参数,可以在Build-Settings-Info.plist File 里面根据不同的 configuration 配置对应的infoplist文件(WeSing的不同分发包配置也通过这个在控制)

多语言方式: InfoPlist.strings 用于支持InfoPlist的国际化,翻译key值是Info.plist中的value

放哪都可以,但是编译打包后要存在mainBundle才能加载到,可以通过 [[NSBundle mainBundle] localizedInfoDictionary] 获取

2.APP-Prefix.pch

预编译头文件(Pre-Compiled Header),一般把大量被使用的头文件、宏 依赖在PCH文件(过度使用会无效依赖太多,反而影响编译效率)存放在工程目录下

在我们编译任意 .m 文件前, 编译器会先对 PCH 里的内容进行预编译,将其变为一种二进制的中间格式缓存起来,便于后续的使用。当开始编译 .m 文件时,如果需要 PCH 里已经编译过的内容,直接读取即可,无须再次编译

问题:维护成本较高,效率也低,后期代码复用迁移pch耦合性太重,依赖关系都被隐藏

二进制缓存文件:APP-Prefix.pch.gch

3.Entilements

授权赋予App特定的能力获安全权限说明文件(Capabilities),比如:通知、苹果支付等

可以根据不同Configuration 配置不同的Entilements

4.xcconfig

配置文件,存放对应configuration 的 Xcode build settings key-value

使用pod的时候,每个configuration会自动生成一份,来支持pod接入需要的build settings配置

4、Pod相关文件

pod原理简单图解: 工程依赖关系

1、Pod工程的主Target名称默认是 Pod-主工程名称,作用是收管所有接入的Pods,每一个Pod是一个Target,主Target 通过Target Dependencies 依赖所有的接入Pods对应的Target

2、Pod工程的主Target根据Podfile中配置的是否动态库,生成libPods-主工程名称.a 静态库,或 Pod_主工程名称.framework 动态库

然后主工程Target通过Link Binary的方式链接 Pod工程生成的静态库或者动态库

Pod Install都做了什么

1._Pods.xcodeproj

其实是Example/Pods/Pods.xcodeproj 的快捷方式,Pods.xcodeproj 就是Pod 挂载进来的管理Pods的工程,在pod install的时候被创建

2.Manifest.lock

Manifest.lock是 Podfile.lock的副本,它是在Example/Pods/ 目录里面。

它的作用是:

我们通常不会把Pods文件放到版本管理,而把Podfile.lock放到版本管理。

拉取代码之后是否需要更新pod,可以通过对比本地的Manifest.lock和远程Podfile.lock是否相同

3.每一个Pod Target自动生成的文件

yourPodName-umbrella.h

pod生成的头文件,方便引用整个pod库的所有头文件,会自动汇总所有的公共头文件

yourPodName.modulemap

构建framework会自动生成的管理Module的文件,modulemap是对Module的声明文件, umbrella.h是Framework 必备的头文件

yourPodName-dummy.m

构建pod会默认生成的一份防止空.m影响编译的文件,占位用

yourPodName-prefix.pch

pod的预编译头文件

yourPodName.debug.xcconfig

xcconfig文件是Build Setting配置项的文件形式,好处就是可以分离编译选项与设置

pod会自动生成debug和release两个环境下的xcconfig文件,并且cocoapods会修改我们的工程的configuration下的config配置

4.Pods-APP-frameworks.sh

这个脚本是build phases中的 [CP] Embed Pods Frameworks 操作

脚本文件主要的作用就是将三方库的frameworks导入到编译生成的的xxx.app/Frameworks目录下

5、隐藏文件

1..githooks 目录

git相关操作用的钩子,比如提交规范检查等

2..rfix.yml

热修复补丁改动记录,补丁构建流水线需要

二、编译后产生的编译产物文件

简单图解编译流程

main.m源文件

main.m 文件的完整编译流程代码解读:

main.m 文件编译成可执行文件 流程图解读:

1、源文件编译产物

tokens

词法分析产物

查看命令:clang -fsyntax-only -Xclang -dump-tokens main.m

运用场景:代码规范检查

ast

语法分析产物

查看命令:clang -fsyntax-only -Xclang -ast-dump main.m

运用场景:静态分析,代码依赖关系分析

.d

每个源文件依赖记录,提供给编译过程、链接器链接等场景使用(比如增量构建的时候判断依赖的头文件是否发生变更来判断是否需要重新编译相应源文件)

运用场景:依赖分析,协助解耦

.ll

生成后端用的IR代码

查看命令:clang -S -emit-llvm main.m -o main.ll

.s

后端优化后生成的汇编代码

查看命令:clang -S main.m -o main.s

.dia

.dia文件是GCC编译器生成的一种中间文件,它包含了源文件中定义的类、函数、变量等符号的元数据信息。

这些元数据信息可以被调试器、代码分析工具等工具使用,以帮助程序员更好地理解和分析源代码

运用场景:.dia 文件可以被用于生成文档、类图和序列图等

.o

目标文件,用于链接成可执行文件

通过nm命令,可以查看下main.o中的符号

.dependency_info.dat

库级别依赖关系记录,包括系统库依赖等,在Link阶段使用。Xcode可以根据记录判断是否受到影响需要重新编译,是Xcode构建过程中非常重要的一个文件,它可以加速构建过程,并提高构建的准确性。

(Libtool命令:libtool主要的一个作用是在编译大型软件的过程中解决了库的依赖问题,还有合并库、跨平台库兼容处理等)

Libtool /Users/lukahuang/Library/Developer/Xcode/DerivedData/APP-dqfxcgpgxnoipsdmmebopuxxcybu/Build/Products/Debug-iphoneos/WSUserProfileModule/libWSUserProfileModule.a 
normal (in target 'WSUserProfileModule' from project 'Pods')
    cd /Users/lukahuang/Desktop/workplace/wesing_iOS/Pods
    /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/libtool -static -arch_only arm64 -D 
    -syslibroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS16.2.sdk 
    -L/Users/lukahuang/Library/Developer/Xcode/DerivedData/APP-dqfxcgpgxnoipsdmmebopuxxcybu/Build/Products/Debug-iphoneos/WSUserProfileModule 
    -filelist /Users/lukahuang/Library/Developer/Xcode/DerivedData/APP-dqfxcgpgxnoipsdmmebopuxxcybu/Build/Intermediates.noindex/
    Pods.build/Debug-iphoneos/WSUserProfileModule.build/Objects-normal/arm64/WSUserProfileModule.LinkFileList 
    -dependency_info /Users/lukahuang/Library/Developer/Xcode/DerivedData/APP-dqfxcgpgxnoipsdmmebopuxxcybu/Build/
    Intermediates.noindex/Pods.build/Debug-iphoneos/WSUserProfileModule.build/Objects-normal/arm64/WSUserProfileModule_libtool_dependency_info.dat 
    -o /Users/lukahuang/Library/Developer/Xcode/DerivedData/APP-dqfxcgpgxnoipsdmmebopuxxcybu/Build/Products/Debug-iphoneos/WSUserProfileModule/libWSUserProfileModule.a

.LinkFileList

记录了需要链接到最终可执行文件中的所有目标文件和库文件的路径,LinkFileList文件会告诉链接器需要链接的所有文件的路径,从而确保最终的可执行文件包含了所有需要的代码和库文件

2、工程编译产物 DerivedData目录 /Users/lukahuang/Library/Developer/Xcode/DerivedData/

ModuleCache.noindex

用于存储模块的预编译头文件(pcm:precompiled header files)和模块的编译中间结果,所有项目共享。

Clang Module的出现,主要是为了确保合理和可扩展的编译时间。因为Clang Module,模块对应的头文件只被解析和编译一次。

具体的Clang Module 后面解释。

APP-dqfxcgpgxnoipsdmmebopuxxcybu

APP编译产物目录,工程名称后面一截是hash值,用于标识唯一构建 

1.Build / Intermediates.noindex 目录

构建工程 - 中间内容目录

重点文件、目录包括:

EagerLinkingTBDs

动态库构建用的TBD文件集(tbd文件:Text-Based Stub Definition。描述动态库的接口信息,函数名、符号、架构等)

PrecompiledHeaders

预编译头文件信息(pch、对应的二进制gch、依赖关系pch.d等)

APP.build、Pods.build

Objects-normal

各种源文件产物,详见前面源文件编译产物

all-product-headers.yaml

一个由 CocoaPods 自动生成的文件,用于存储 CocoaPods 依赖库中所有公共头文件的路径 (s.public_header_files =)

DerivedSources

能力项plist文件、脚本执行结果文件等

APP-LinkMap-normal-arm64.txt

在 iOS 应用程序的编译过程中,链接器会将各个目标文件合并成一个可执行文件。在这个过程中,链接器会生成一个链接映射文件(Link Map),用于记录各个符号在可执行文件中的位置和大小等信息。APP-LinkMap-normal-arm64.txt 就是这个链接映射文件的一种形式,它记录了应用程序在 arm64 架构下的符号表信息。

运用场景:通常用于分析应用程序的内存占用情况。通过分析该文件,可以了解每个模块、每个类、每个函数所占用的内存大小,以及它们之间的依赖关系等信息。

APP.app.xcent / APP.app.xcent.der

打包签名证书信息,plist 和对应的二进制文件(存入 ipa里面)

Launch Screen-SBPartialInfo.plist / Launch Screen.storyboardc

启动Launch Screen 相关配置,storyboard相关

hamp & modulemap

1、hmap是当我们开启 Build Setting 中的 Use Header Map 选项后,会自动生成的一份头文件名和头文件路径的映射表,二进制格式【hmap解析工具】,作用是让编译器快速找到相应的头文件位置

2、modulemap 是 Clang提出Module概念后,Module的具体呈现表示文件,对Framework里面的所有文件进行结构化的描述,通过这个文件,让编译器了解到 Module 的逻辑结构与头文件结构的关联方式

问题一:没有hmap之前,编译器是如何查找头文件的?

头文件 import 方式

#import <A/A.h>#import “A/A.h”#import #import "A.h"

有没有/ 区别是是否局限于在对应Search Path的 A目录下查找A.h 头文件

默认是根据 Build Settings - Search Paths 配置

1、Header Search Path (什么类型的 import方式都可以使用这里的Path)

2、System Header Search Path (一般是带尖括号的 import方式,一般是系统库)

3、User Header Search Path (一般是引号的import方式,表示非系统)

注意:cocoapods的工程基本上pod库都会挂载地址到Header Search Path,所以基本没啥区别了

问题二:这种头文件查找方式的问题?

通过Search Path 在进行头文件查找耗时较多,特别是文件量级别大了之后,大量的IO操作,耗时倍增。

如果可以缓存起搜索结果下次编译就不需要重复查找。这就是hmap的由来,开启hmap是在 Build Settings - Search Paths - Use Header Maps

1、源码编译的命令,可以看到中间文件hamp地址

2、编译结束后,在DerivedData/Build目录下 生成了一堆.hmap文件

1、-project-headers.hmap 当前工程依赖的公开头文件对应的文件与地址的映射

2、-generated-files.hmap 当前工程依赖的自动生成的文件与地址的映射

3、-own-target-headers.hmap 当前编译的主Target的header map

4、-all-target-headers.hmap 工程所有Target 的header map(比如所有的pod都各自算一个target)

5、-all-non-framework-target-headers.hmap 工程所有的 不是framework的目标Target的header map

问题三:Xcode编译在有 hmap后又是如何寻址的呢

我的理解:

1、Pod工程使用动态库,会有Clang Module逻辑

一个文件,比如MASConstraint.h 如果通过import “MASConstraint.h“的方式导入的,Clang通过 -project-headers.hmap 将import 转成 import “Masonry/MASConstraint.h“

再通过Masonry-own-target-headers.hmap 转成目标头文件绝对地址 “/Users/lukahuang/Desktop/workplace/yourPodName/Example/Pods/Masonry/Masonry/MASConstraint.h“

论证:

a、拆解使用了 use_frameworks! Pod Project 对应-project-headers.hmap文件,映射的并不是绝对头文件地址,而是包了一层库名称

b、拆解Pod Project 下的所有Target对应的 -all-target-headers.hmap文件,可以看到针对包了一层库名称的头文件key,有对应的绝对地址映射

2、Pod工程使用静态库

所有头文件直接存在一个文件,Clang可以直接通过-project-headers.hmap 获取绝对地址

论证:

除开-project-headers.hmap 的所有的hmap都没有内容,-project-headers.hmap 已转换为头文件绝对地址

问题四:头文件查找到了是如何依赖上的?

进行预处理源码(Xcode - Product - PerformAction - Preprocess)的时候,我们发现 import 的内容变成了源码,对应的import 还被换成了文件的绝对地址

#import 本质上是(#include + 去重),做的事情就是复制粘贴,也就是将依赖的头文件的代码,CV过来替换这句#import代码

1、#import 的缺点

假设你有 M 个源文件且每个文件会引入 N 个头文件,编译它们的时间就会是 M * N

2、PCH的优缺点

为了优化 #import 的问题,苹果提供了PCH文件,他的大体原理就是我们编译任意的.m文件之前 编译器会对PCH里的内容进行预编译

并且将编译结果作为一种二进制的中间格式缓存起来(APP-Prefix.pch.gch),后面.m编译的时候直接读取,无需再次编译

缺点:维护这个文件有成本,代码耦合性提高很多,特别是组件化拆分的时候,PCH就是噩梦

3、Clang Module

为了解决上面的问题而诞生,在实际编译之时,编译器会创建一个全新的空间,用它来存放已经编译过的 Module 产物 (pcm文件)。如果在编译的文件中引用到某个 Module 的话,

系统将优先在这个列表内查找是否存在对应的中间产物,如果能找到,则说明该文件已经被编译过,则直接使用该中间产物,如果没找到,则把引用到的头文件进行编译,并将产物添加到相应的空间中以备重复使用。

在这种编译模型下,被引用到的 Module 只会被编译一次,且在运行过程中不会相互影响,这从根本上解决了健壮性和拓展性的问题。

具体的使用:

Build Settings中的 Defines Module,如果使用 use_frameworks! ,这里是打开的,直接使用framework 默认的modulemap文件(静态库要使用需要自行配置modulemap文件,并手动开启)

framework 结构

开启这种特性(Build Settings - Defines Module),模块的依赖方式会自动转换:#import <Masonry/Masonry.h> 变成 @import Masonry ,这样就可以快速使用pcm缓存

问题五:依赖方式转换的流程是怎么判定的?

以 #import <Foundation/NSString.h> 为例,当我们遇到这个头文件的时候:

首先会去 Framework 的 Headers 目录下寻找相应的头文件是否存在,然后就会到 Modules 目录下查找 modulemap 文件

此时,Clang 会去查阅 modulemap 里的内容,通过 Umbrella Header 看看 NSString 是否为 Foundation 这个 Module 里的一部分。

至此,Clang 会判定 NSString.h 是 Foundation 这个 Module 的一部分并进行相应的编译工作,此时也就意味着 #import <Foundation/NSString.h> 会从之前的 textual import 变为 module import。

问题六:自定义的Pod库接入,是如何支持到Clang Module的?

神秘的 Virtual File System(VFS)

在自定义组件库这种文件结构中,压根就没有 Modules 和 Headers 目录。

为了解决这个问题,Clang 又提出了一个新的解决方案,叫做 Virtual File System(VFS)。

简单来说,通过这个技术,Clang 可以在现有的文件结构上虚拟出来一个 Framework 文件结构,进而让 Clang 遵守前面提到的构建准则,顺利完成 Module 的编译,同时 VFS 也会记录文件的真实位置,以便在出现问题的时候,将文件的真实信息暴露给用户。

XCBuildData

编译流程的一些产物,不同的target、scheme、configuration、架构都会对应不同的数据文件

buildRequest.json文件:描述Xcode构建过程中的构建请求的文件,包含构建目标、编译器选项、构建设置等信息,以及构建所需的依赖关系。

targetGraph.txt:描述Xcode项目中的构建目标(Build Target)之间的依赖关系。

manifest.xcbuild:描述项目的编译过程和依赖关系,Xcode会根据这个文件来决定编译、链接、打包等操作的顺序和方式(截取一条流程大概翻译:创建一个目录 → 目录名称 [ tool:”create-build-directory”,描述:”xxxx”, 输入: [xxx], 输出: [xxx],参数集:[xxx] ])

desc.xcbuild:描述项目的源文件编译的细节信息,比如编译配置,环境信息,sdk信息等,告诉编译器如何编译每个源文件,并指定输出路径和依赖关系

build.db:SQLite记录项目构建过程和编译器输出信息(每条编译命令、参数,输出信息,文件依赖关系,错误警告日志),是Xcode Build System实现增量编译和增量链接的重要依据之一,可以提高项目的构建效率和速度。

PIFCache:(Personal Information Folder)用户编译行为信息缓存数据(project、target、workspace维度)每次编译产生一笔

2.Build / Products

构建工程-产物目录(WeSing是禁掉了动态库使用,所以这个目录的各子库里面为空或者有对应的一些资源bundle)

APP.app

程序包

WeSingNotificationServiceExtension.appex

程序扩展包,包含可执行文件、profile描述文件、info.plist

每个Pod-Target 对应一个目录

本身接入是动态库或者静态库的的目录会为空,源码接入的根据动态库静态库不一样,目录内会有framework或者.a文件

XCFrameworkIntermediates

构建过程中处理Framework时临时用的目录,比如GoogleMobileAds.xcframework接入进来是包括多个架构的一套库,针对这种情况,需要剥离出所需的架构接入。这个时候用的临时目录。

3.Index.noindex

Xcode 当前工程索引存储目录,Xcode 的代码高亮、代码补全、代码跳转、查找调用链、重构、Open Quickly 等功能都是 Xcode 索引的一部分

扩展运用场景:工程索引缓存文件共享提高编译构建速度

Xcode索引有两种工作方式

工作方式图解:

1、闲时自动索引,当我们打开工程后一直在转的Indexing,就是SourceKit驱动Clang在执行

Index转圈的时候去找活动监视器可以看见下面这个进程,就是SourceKit的进程

/Applications/Xcode.app/Contents/SharedFrameworks/SourceKit.framework/Versions/A/XPCServices/com.apple.dt.SKAgent.xpc/Contents/MacOS/com.apple.dt.SKAgent

2、开启Build-Settings里面的 Index-While-Building,会再编译过程中同时生成Index数据(会影响编译耗时,官方数据:导致编译速度慢2-5个百分点)

Index.noindex都存放了什么?

主要是两个目录 DataStore(records + units)、UniDB。DataStore 存储了 Clang 编译的产物,是索引原始数据,UniDB 是为了加速查询建立的LMDB表,存储了经过处理后的信息

units 记录了源码文件的路径、依赖的文件路径、依赖的 records 文件的路径,它的命名规则是 test.o-hash (Hash of output file path),如果文件名、路径等不变化文件名则不会变化。

records 记录了每个源码文件由哪些符号构成,它主要由 Symbol、Occurence 两部分构成。它的命名规则是 test.m-hash (Hash of output file path),如果代码变更文件名就会变化。

 DataStore

records

WSPageView.h-34QT6TYSKB50G 

WSProfileKTVTableViewCell.m-X5MVBOW2NL6J

units

Foundation-A3SOD99KJ0S9.pcm-19BVOW03YK7ZF 

WSGiftMessageBaseVC.o-CZM8OW4UXWF9

UniDB

data.mdb

lock.mdb

4.Logs

Xcode日志

5.SymbolCache

用于存储符号表缓存文件。符号表是一种用于调试和分析程序的数据结构,它包含了程序中所有变量、函数、类等符号的地址和名称信息。

在 Xcode 编译过程中,编译器会生成符号表文件,以便在程序崩溃或者出现其他问题时进行调试。为了加快符号表的加载速度,Xcode 会将符号表缓存到 SymbolCache 目录中。

SymbolCache 目录中包含了多个以 UUID 命名的目录,每个目录对应一个应用程序或者库文件的符号表缓存。这些缓存文件可以跨多个 Xcode 项目共享,从而提高编译效率。

6.TextIndex

Xcode 编辑器中用于搜索和查找文本的索引文件。它包含了源代码文件中所有单词的位置信息,以及这些单词所在的上下文信息,例如它们所在的行号、函数名称、文件名等。

当你在 Xcode 编辑器中使用搜索功能时,Xcode 会使用 TextFragmentIndex-v8.idx 文件快速定位匹配的单词,从而提高搜索的速度和准确性。这个索引文件是在编译项目时自动生成的,它可以帮助开发者更快地定位代码中的问题,提高开发效率。

7.FindNavigator.history 

Xcode 当前工程导航搜索历史记录

8.info.plist

当次buildinfo,最后一次build是什么时候,workspace是哪个地址等

9.OpenQuickly-ReferencedFrameworks.index-v1

Xcode 用于快速查找和索引项目中引用的框架的索引文件。当你在 Xcode 中使用 Open Quickly(快速打开)功能时,Xcode 会搜索这个索引文件来确定项目中引用的框架,以便更快地定位和打开相关文件。

10.scm.plist

Xcode 用于管理源代码管理(SCM)配置的属性列表文件。SCM 是一种工具,用于管理软件开发过程中的源代码版本控制、协作和变更管理。

常见的 SCM 工具包括 Git、Subversion、Perforce 等。

在 Xcode 中,你可以通过选择 Source Control(源代码管理)菜单来配置和管理 SCM 工具。

scm.plist 文件包含了 SCM 工具的配置信息,如工具名称、路径、用户名、密码等。Xcode 会读取这个文件来确定使用哪个 SCM 工具以及如何连接到 SCM 服务器。