我们曾经在上一篇文章中 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 左右:
压缩后
压缩后体积在 4G 左右:
Tip2、编译中间文件
通常情况下,编译中间文件 会占用20G以上的空间。
以 scheme-clang
为例,如果读者按照上一篇文章提供的脚本进行编译,就会发现下面的目录包含21个中间文件。
代码语言:txt复制scheme 定义: https://help.apple.com/xcode/mac/11.4/#/dev6fd4476d7
➜ 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个工程加起来有几百个临时文件夹,一个个手动删除的效率较低。所以,我们我们可以通过一下脚本进行批量清理。
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
项目时,必须先编译B
、C
项目才能进行。
此时,A
项目的构建依赖就是 B
和 C
。
构建依赖分两种:显示依赖 & 隐式依赖
显示依赖
显示依赖可以通过 build phases
的 Dependencies
查看。
以 liblldb
为例,它共计包含 73
个 显示依赖。每个 显示依赖 又包含多个的构建依赖,最后,liblldb
共计包含400
个构建依赖。
参考文章: What are build phases?
隐私依赖
隐式依赖 是指没有通过 显示依赖 指明,但是又确实存在的依赖项。
target PetKit
的构建产物是 PetKit.framework
。
如果 target host
存在下面的配置:
则,target host
会隐式依赖 target PetKit
。
优化方案
因为每个target
都会产出多个中间文件,为了避免产生这些中间文件,以及加快编译速度。
我们可以只保留强依赖target。
如下所示,笔者整理一份缩减版的 lldb
的构建依赖图
。
但是,大部分情况下,这些依赖都属于弱依赖。
如果读者熟悉 预处理-编译-链接
三步曲很熟悉,我们很容易发现,上面的依赖并不是必须的。
我们真正依赖的是每个target
的构建产物。
所以,我们将上图重新整理成下图所示的 强构建依赖图
。
我们下面以一个具体的场景进行说明什么是强依赖target:
- 假设,我们需要在
CommandInterpreter.cpp
文件的CommandInterpreter::HandleCommand
函数内增删代码。 - 此时,
liblldbInterpreter.a
需要被重新编译,target lldbInterpreter
就是lldb
的强依赖项 - 因为
LLDB.framework
强依赖liblldbInterpreter.a
,所以,liblldb
同样是lldb
的强依赖项
如下所示,我们可以只保留两个强依赖项,移除其它的弱依赖项。
经过一番操作后,Xcode 就可以从原来的几十G中间文件,变为只需要几十M中间文件。
总结
本文通过讲解 Swift 及 Xcode 依赖关系,提供了多个有效降低磁盘空间占用的方案。