Swift 入门:编译 Swift 源码(2)

2020-11-18 14:31:12 浏览数 (1)

我们曾经在上一篇文章中 https://cloud.tencent.com/developer/article/1744552 提到 Swift 及相关组件的编译会耗费大量的磁盘空间。

本文希望能够进一步分享降低磁盘空间的一些技巧。

Tip1:压缩源码仓库

git 仓库的压缩方案比较简单,只需要通过 git gc 命令进行压缩即可。

git gc 文档:https://git-scm.com/docs/git-gc

压缩前

在 Swift 及相关组件中,只有 swift 和 llvm-project 两个仓库笔记体积较大,所以我们以这两个仓库为例进行讲解。

在笔者的电脑上,两个仓库的体积合计 9G 左右:

image.pngimage.png

压缩后

压缩后体积在 4G 左右:

image.pngimage.png

Tip2、编译中间文件

通常情况下,编译中间文件 会占用20G以上的空间。

scheme-clang 为例,如果读者按照上一篇文章提供的脚本进行编译,就会发现下面的目录包含21个中间文件。

scheme 定义: https://help.apple.com/xcode/mac/11.4/#/dev6fd4476d7

代码语言:txt复制
➜  RelWithDebInfo git:(master) ✗ pwd
~/swift-source/build/Xcode-1107/llvm-macosx-x86_64/tools/clang/tools/driver/LLVM.build/RelWithDebInfo
➜  RelWithDebInfo git:(master) ✗ tree
.
└── clang.build
    ├── Objects-normal
    │   └── x86_64
    │       ├── cc1_main.d
    │       ├── cc1_main.dia
    │       ├── cc1_main.o
    │       ├── cc1as_main.d
    │       ├── cc1as_main.dia
    │       ├── cc1as_main.o
    │       ├── cc1gen_reproducer_main.d
    │       ├── cc1gen_reproducer_main.dia
    │       ├── cc1gen_reproducer_main.o
    │       ├── clang.LinkFileList
    │       ├── clang_dependency_info.dat
    │       ├── driver.d
    │       ├── driver.dia
    │       ├── driver.o
    │       ├── dummy.d
    │       ├── dummy.dia
    │       └── dummy.o
    ├── Script-FEC9C3C23E8E4148A8447162.sh
    ├── clang.xcent
    ├── dgph
    └── dgph~

3 directories, 21 files

上面的21个文件,是通过 cmake 生成 clang 可执行文件时产生的。

当我们开始使用 Xcode 进行编译或者调试时,这些文件都可以被删除。

批量清理方案

考虑到 Swift LLVM lldb 3个工程加起来有几百个临时文件夹,一个个手动删除的效率较低。所以,我们我们可以通过一下脚本进行批量清理。

代码语言:txt复制
cd ~/swift-source/build/Xcode-1107
find . -name LLVM.build | xargs rm -rf
find . -name swift.build | xargs rm -rf
find . -name lldb.build | xargs rm -rf

Tip3、构建依赖

构建依赖是指:编译A项目时,必须先编译BC项目才能进行。

此时,A 项目的构建依赖就是 BC

构建依赖分两种:显示依赖 & 隐式依赖

显示依赖

显示依赖可以通过 build phasesDependencies 查看。

liblldb 为例,它共计包含 73显示依赖。每个 显示依赖 又包含多个的构建依赖,最后,liblldb 共计包含400构建依赖

image.pngimage.png

参考文章: What are build phases?

隐私依赖

隐式依赖 是指没有通过 显示依赖 指明,但是又确实存在的依赖项。

target PetKit 的构建产物是 PetKit.framework

如果 target host 存在下面的配置:

image.pngimage.png

则,target host隐式依赖 target PetKit

优化方案

因为每个target都会产出多个中间文件,为了避免产生这些中间文件,以及加快编译速度。

我们可以只保留强依赖target

如下所示,笔者整理一份缩减版的 lldb构建依赖图

弱依赖弱依赖

但是,大部分情况下,这些依赖都属于弱依赖

如果读者熟悉 预处理-编译-链接 三步曲很熟悉,我们很容易发现,上面的依赖并不是必须的。

我们真正依赖的是每个target的构建产物。

所以,我们将上图重新整理成下图所示的 强构建依赖图

强依赖项强依赖项

我们下面以一个具体的场景进行说明什么是强依赖target

  • 假设,我们需要在 CommandInterpreter.cpp 文件的 CommandInterpreter::HandleCommand 函数内增删代码。
  • 此时, liblldbInterpreter.a 需要被重新编译,target lldbInterpreter 就是lldb强依赖项
  • 因为 LLDB.framework 强依赖 liblldbInterpreter.a,所以,liblldb 同样是lldb强依赖项

如下所示,我们可以只保留两个强依赖项,移除其它的弱依赖项

image.pngimage.png
image.pngimage.png

经过一番操作后,Xcode 就可以从原来的几十G中间文件,变为只需要几十M中间文件。

总结

本文通过讲解 Swift 及 Xcode 依赖关系,提供了多个有效降低磁盘空间占用的方案。

0 人点赞