swift-5.9-RELEASE源码编译(Xcode)

编译前提与注意事项

对于源码的版本要与Xcode的swift版本一致,对于macOS的版本参照一下CI说明文档

提供两个宝藏网站以帮你查询你的Xcode与swift的version信息:
Xcode Releases
Swift Version

当前环境

terminal 复制代码
MacOS Version: Sonoma 14.1 beta(23B5056e) (Apple M2)
Xcode Version: 15.0
python3 Version: 3.9.6
cmark Version: 0.30.3
ninja Version: 1.11.1(非必需)
sccache Version: 0.5.4(非必需)

编译过程

为项目创建文件夹

terminal 复制代码
mkdir swift-project
cd swift-project

clone swift-5.9-RELEASE源码(推荐SSH方式,设置SSH请参考此链接)

C++ 复制代码
git clone --branch swift-5.9-RELEASE git@github.com:apple/swift.git swift

通过update-checkout脚本对编译swift依赖库进行clone

C++ 复制代码
utils/update-checkout --tag swift-5.9-RELEASE --clone-with-ssh

此步骤失败几率很大,原因大都是由于网络导致的,如果在公司编译,建议早晨或者晚上稍晚一些,尽量规避一些网络问题。此前在测试编译过swift-5.3.1出现过python2.7问题,但是如果编译swift-5.9则可以完全使用python3,目前还没有遇到关于python的错误。

update-checkout执行成功的结果如图:

如果安装了sccache,将其运行。

C++ 复制代码
sccache --start-server

Sccache默认为10GB的缓存大小,与构建工件相比相对较小。您可以提高它,例如通过在dotfile中设置export SCCACHE_CACHE_SIZE="50G"。有关更多详细信息,请参阅Sccache README

通过Xcode方式build

sh 复制代码
bblv at xiaoBtongxuedeMac-mini in ~/Desktop/swift-project/swift (tags/swift-5.9-RELEASE) 

utils/build-script --swift-darwin-supported-archs="$(uname -m)" \
--release-debuginfo --debug-swift-stdlib \
--skip-ios --skip-watchos --skip-tvos \
--skip-early-swiftsyntax --skip-build-benchmarks \
--sccache --xcode 

参数说明:
--swift-darwin-supported-archs:设置构建平台,如果不设置,默认全平台构建
$(uname -m):获取当前mac的架构,我的mac为M2的arm64的架构
--release-debuginfo:构建所有的内容RelWithDebInfo(包含debug和release)带有调试信息
--debug-swift-stdlib: 编译带有调试信息的 Swift标准库stdlib --skip-ios --skip-watchos --skip-tvos:跳过iOS、watchos、tvos相关内容
--skip-early-swiftsyntax : 表示跳过earlyswiftsyntax, 这个不加会编译出错
--skip-build-benchmarks:跳过构建swift基准测试套件
--sccache:使用缓存工具,当删除构建目录重新构建的时候提高构建速度
--xcode:使用Xcode方式构建
build-script --help: 更多参数请参考help

在之前我编译Swift-5.5.1-RELEASE的过程中,build-script过程编译成功大约需要50G的空间。如果编译失败,原因基本是参数传入的问题(推测是某些参数构建需要特定环境支持),根据所需选择适当的参数。如果只是想在本地运行一些,调试代码,对测试没有过多要求,上述参数是我验证最优解了。
此次编译Swift-5.9-Release,我将build生成的产物Cmark、LLVM、Swift的.xcodeproj都进行了编译,一共使用了113G的空间

build-script编译成功如下图:

Build之后的排错操作

我之前在编译成功的时候是直接运行/Users/bblv/Desktop/swift-project/build/Xcode-RelWithDebInfoAssert+stdlib-DebugAssert/swift-macosx-arm64/Swift.xcodeproj这个xcodproj,然后会出现各种各样的问题,虽然不多,但是对于小白排查起来还是需要一些时间的。

小白都可以完成的不会报错的操作,一把直接出现 Build Succeed 的小锤子

顺序很重要!顺序很重要!顺序很重要!

  1. cmark-gfm.xcodeproj
  2. LLVM.xcodeproj
  3. Swift.xcodeproj

通过Xcode打开之后的操作都是一致的,点击Manually Manage Schemes,千万不要选择Automatically Create Schemes 会生成大量的scheme,我们的目的只是探索Swift,自动生成的scheme只会增加电脑的负载。通过编译多个版本的源码的经验,请不要点。

因为我们选择手动,所以要创建Scheme,选择All_BUILDScheme,全量编译。把Build Configuration改成RelWithDebInfo

上面的3个项目都要做一遍这个操作,到目前为止,最后的Swift.xcodeproj的build会直接一把过,刺不刺激!惊不惊喜!意不意外!

Cmark

LLVM

LLVM强调一下,在编译过程中会爆i386架构的问题,请你不用理会,虽然工程最终build以fail结束,但是Swift编译所需的arm64已经准备好了,这个是瑕疵,目前不会处理,在研究。

Swift

到目前为止,编译期间的操作全部完成。

创建Debug工程

Text 复制代码
1、创建新的Target-->BBlvProbe
    
2、为BBlvProbe添加依赖ALL_BUILD(Build Phases -> Dependencies -> +)
    
3、打开BBlvProbe的Build Settings,设置ENABLE_HARDENED_RUNTIME的值为NO

4、打开BBlvProbe的Build Settings,设置Swift Compiler的Optimization Level为No Optimization

5、打开BBlvProbe的Build Settings,设置Apple Compiler的Optimization Level为None

设定第4、第5步的原因是上面将Build Configuration设置为了RelWithDebInfo,用作动态调试。如果你使用的是默认的Debug那么就不需要设置了。

至此,所有关于环境设定相关都已经完成。

BBlvProbe-debug调试

目前源码在手总得干点什么吧,那我们就来探索一类的结构吧。 在BBlvProbe的main函数里面创建一个类,简单编写一些测试代码

Swift 复制代码
//
//  main.swift
//  BBlvProbe
//
//  Created by 小B同学 on 2023/10/12.
//
import Foundation

print("Hello, World!")

class BBLvHobby {
    var hobby = "girl"
    var name = "BBLv"
}

var p = BBLvPerson()

print(p)

我在Swift源码工程里面创建了一个macOS的Command Line Tool工程,在里面创建了一个BBLvHobby的class,通过初始化来了解class的数据结构

我用简单的源码来说明继承链

Swift 复制代码
HeapObject *swift::swift_allocObject(HeapMetadata const *metadata,
                                     size_t requiredSize,
                                     size_t requiredAlignmentMask) {
  CALL_IMPL(swift_allocObject, (metadata, requiredSize, requiredAlignmentMask));
  
//👇查找,找到HeapMetadata

using HeapMetadata = TargetHeapMetadata<InProcess>;

//👇查找,找到TargetHeapMetadata

template <typename Runtime>
struct TargetHeapMetadata : TargetMetadata<Runtime> {

};

//👇查找,找到TargetMetadata

template <typename Runtime>
struct TargetMetadata {
...
private:
  /// The kind. Only valid for non-class metadata; getKind() must be used to get
  /// the kind value.
  StoredPointer Kind;
  
...
  • 我通过给bt找到了class初始化的切入点swift_allocObject
  • 在swift_allocObject中找到了刻意变量metadata,通过打印得知了metadata就是我定义的class
  • 通过metadata的数据类型HeapMetadata向下追踪,找到了末班类型TargetHeapMetadata
  • 通过追踪TargetHeapMetadata找到了class的最终数据结构,是结构体TargetMetadata
  • TargetMetadata的主要数据结构我列出了Kind,这个是引用计数

通过上述对Swift源码的初步探索就可以了解到在Swift中的class的数据结构了,以及为什么推荐在Swift中尽量使用struct,在源码层面可以解释为struct在下层实现最终会转化为struct类型的TargetMetadata。后续还会更深入的探索class的数据结构,这里就不做过多解释了

总结

之前通过ninja构建过swift-5.2.4-RELEASE版本,通过vscode和lldb插件来调试过swift源码。相比之下对于iOS开发者来讲可能使用Xcode调试会更加的舒服。对于Xcode的使用也更加的娴熟。自定义一些类也更加的方便。虽然xcode有许多许多的问题,通过Xcode构建过swift-5.5.1-RELEASE版本,每次在动态调试的时候都会出现控制台log:

Swift 复制代码
warning: LibswiftCore.dylib was compiled with optimization - stepping may behave oddly; variables may not be available

本次使用MacOS14以及Xcode15.0构建最新版的swift-5.9-RELEASE版本,是一次非常完美的构建,调试过程中未出现系统Log

至此关于swift-5.9-RELEASE版本相关的编译问题以及如何调试研究基本讲解透彻,新手小白可以直接上手。

参考

github.com/apple/swift...

相关推荐
一丝晨光16 小时前
继承、Lambda、Objective-C和Swift
开发语言·macos·ios·objective-c·swift·继承·lambda
KWMax1 天前
RxSwift系列(二)操作符
ios·swift·rxswift
Mamong1 天前
Swift并发笔记
开发语言·ios·swift
小溪彼岸2 天前
【iOS小组件】小组件尺寸及类型适配
swiftui·swift
Adam.com2 天前
#Swift :回调地狱 的解决 —— 通过 task/await 来替代 nested mutiple trailing closure 来进行 回调的解耦
开发语言·swift
Anakki2 天前
【Swift官方文档】7.Swift集合类型
运维·服务器·swift
KeithTsui3 天前
集合论(ZFC)之 联合公理(Axiom of Union)注解
开发语言·其他·算法·binder·swift
東三城3 天前
【ios】---swift开发从入门到放弃
ios·swift
IT研究室4 天前
大数据毕业设计选题推荐-电影数据分析系统-数据可视化-Hive-Hadoop-Spark
大数据·hive·hadoop·spark·毕业设计·源码·课程设计