零.编译swiftc
-
网上很多教程有问题,建议多看看官网教程
-
准备环境
brew install cmake ninja sccache
检查环境
Run cmake --version: This should be 3.19.6 or higher.
Run python3 --version: Check that this succeeds.
Run ninja --version: Check that this succeeds.
Run sccache --version: Check that this succeeds. -
下载swift源码
去https://github.com/apple/swift/releases找到最新的版本,使用git clone --branch swift-5.5.2-RELEASE https://github.com/apple/swift.git
下载 -
运行
./swift/utils/update-checkout --tag swift-5.5.2-RELEASE --clone
下载编译swift相关的库
图片.png
- 编译swift源码,可以得到swfitc
- 设置sccache
sccache --start-server
export SCCACHE_CACHE_SIZE="100G"
- 3.1使用ninja编译
swiftRes ./swift/utils/build-script -r --debug-swift-stdlib --lldb
得到编译后的产物在
Build files have been written to: /Volumes/yulepan/swiftRes/build/Ninja-RelWithDebInfoAssert+stdlib-DebugAssert/llvm-macosx-x86_64
- 3.2 使用xcode编译
./swift/utils/build-script -x -R --debug-swift
得到编译后的产物在
Build files have been written to: /Volumes/yulepan/swiftRes/build/Xcode-ReleaseAssert+swift-DebugAssert
- 在vscode的launch.json里面配置我们的swiftc
图片.png
- 遇到问题,可以百度搜索
Swift源码编译
一.使用xcode编译swiftc
如果你使用上面的命令失败了,那么还是用xcode吧,毕竟苹果爸爸在mac上主要支持xcode,其他的例如vscode appcode都不支持。
- 我使用ninja在我的M1和MacBook Pro 2019款编译都失败了,后来经过断断续续一个月的尝试,终于成功了。
- 基于MacBook Pro 2019 Intel芯片,swift-5.5.3-RELEASE,cmake version 3.22.2, Xcode 13.1.0
- 不要用硬盘啊,否则会出现签名的错误
Command CodeSign failed with a nonzero exit code
,真的非常蛋疼 - 总编译时长为3个小时左右,要有耐心,而且电脑尽量不要开其他东西,否则影响速度
- 这是我参考的教程
- 终端执行
./swift/utils/build-script --release-debuginfo --debug-swift-stdlib -x --skip-ios --skip-watchos --skip-tvos --swift-darwin-supported-archs="x86_64"
- 使用xcode打开
cmark.xcodeproj
,
图片.png
将Scheme选择为cmake
,然后 command+B 编译下,1秒就成功了。不要习惯性的command+R,这样的话它会一直run,永远不会结束
图片.png
特别快
图片.png
- 编译ALL_BUILD
打开Swift.xcodeproj
图片.png
找到ALL_BUILD(话说真的难找啊)
图片.png
选中
图片.png
然后编辑scheme
图片.png
选择优化选项
图片.png
点击close,然后command+b编译吧。
- 创建自己的target
图片.png
点击+号
图片.png
创建好后是这样的,多了一个自己的target
图片.png
点击自己的target,在Build Settings里面搜索runtime,将Enable Handened Runtime
设置为NO,否则你是不能在源码里面打断点的
图片.png
然后找到Build Phases,点击+号将刚才在RelWithDebInfo
模式下的ALL_BUILD作为依赖
图片.png
同样的步骤,找到Edit Scheme
图片.png
将自己的target的编译模式设为RelWithDebInfo
图片.png
- 在自己的target的main里面写一个class,然后初始化,并打上断点
图片.png
在HeapObject.cpp
里面打上断点,然后编译,你会发现断点能走进源码了😄
图片.png
二.分析SIL
SIL:swift intermediate language -> swift中间语言
- Objective C语言是通过
clang
编译器将源码编译成IR - Swift 通过
swiftc
编译器编译成SIL,再生成IR - SIL官方文档: https://github.com/apple/swift/blob/main/docs/SIL.rst#abstract
执行swiftc -dump-ast main.swift
拿到main.swift的抽象语法树
(source_file "main.swift"
(class_decl range=[main.swift:8:1 - line:10:1] "LYKClass" interface type='LYKClass.Type' access=internal non-resilient
(destructor_decl implicit range=[main.swift:8:7 - line:8:7] "deinit" interface type='(LYKClass) -> () -> ()' access=internal
(parameter "self")
(parameter_list)
(brace_stmt implicit range=[main.swift:8:7 - line:8:7]))
(constructor_decl implicit range=[main.swift:8:7 - line:8:7] "init()" interface type='(LYKClass.Type) -> () -> LYKClass' access=internal designated
(parameter "self")
(parameter_list)
(brace_stmt implicit range=[main.swift:8:7 - line:8:7]
(return_stmt range=[main.swift:8:7 - line:8:7]))))
(top_level_code_decl range=[main.swift:11:1 - line:11:20]
(brace_stmt implicit range=[main.swift:11:1 - line:11:20]
(pattern_binding_decl range=[main.swift:11:1 - line:11:20]
(pattern_named type='LYKClass' 'cls')
Original init:
(call_expr type='LYKClass' location=main.swift:11:11 range=[main.swift:11:11 - line:11:20] nothrow arg_labels=
(constructor_ref_call_expr type='() -> LYKClass' location=main.swift:11:11 range=[main.swift:11:11 - line:11:11] nothrow
(declref_expr implicit type='(LYKClass.Type) -> () -> LYKClass' location=main.swift:11:11 range=[main.swift:11:11 - line:11:11] decl=main.(file).LYKClass.init()@main.swift:8:7 function_ref=single)
(type_expr type='LYKClass.Type' location=main.swift:11:11 range=[main.swift:11:11 - line:11:11] typerepr='LYKClass'))
(tuple_expr type='()' location=main.swift:11:19 range=[main.swift:11:19 - line:11:20]))
Processed init:
(call_expr type='LYKClass' location=main.swift:11:11 range=[main.swift:11:11 - line:11:20] nothrow arg_labels=
(constructor_ref_call_expr type='() -> LYKClass' location=main.swift:11:11 range=[main.swift:11:11 - line:11:11] nothrow
(declref_expr implicit type='(LYKClass.Type) -> () -> LYKClass' location=main.swift:11:11 range=[main.swift:11:11 - line:11:11] decl=main.(file).LYKClass.init()@main.swift:8:7 function_ref=single)
(type_expr type='LYKClass.Type' location=main.swift:11:11 range=[main.swift:11:11 - line:11:11] typerepr='LYKClass'))
(tuple_expr type='()' location=main.swift:11:19 range=[main.swift:11:19 - line:11:20])))
))
(var_decl range=[main.swift:11:5 - line:11:5] "cls" type='LYKClass' interface type='LYKClass' access=internal let readImpl=stored immutable))
执行swiftc -emit-sil main.swift > ./main.sil && open main.sil
拿到main.swift的sil
sil_stage canonical
import Builtin
import Swift
import SwiftShims
class LYKClass {
@_hasStorage @_hasInitialValue var age: Int { get set }
@_hasStorage @_hasInitialValue var name: String { get set }
@objc deinit
init()
}
@_hasStorage @_hasInitialValue let cls: LYKClass { get }
// cls
sil_global hidden [let] @$s4main3clsAA8LYKClassCvp : $LYKClass
// main
sil @main : $@convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 {
bb0(%0 : $Int32, %1 : $UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>):
alloc_global @$s4main3clsAA8LYKClassCvp // id: %2
%3 = global_addr @$s4main3clsAA8LYKClassCvp : $*LYKClass // user: %7
%4 = metatype $@thick LYKClass.Type // user: %6
// function_ref LYKClass.__allocating_init()
%5 = function_ref @$s4main8LYKClassCACycfC : $@convention(method) (@thick LYKClass.Type) -> @owned LYKClass // user: %6
%6 = apply %5(%4) : $@convention(method) (@thick LYKClass.Type) -> @owned LYKClass // user: %7
store %6 to %3 : $*LYKClass // id: %7
%8 = integer_literal $Builtin.Int32, 0 // user: %9
%9 = struct $Int32 (%8 : $Builtin.Int32) // user: %10
return %9 : $Int32 // id: %10
} // end sil function 'main'
// variable initialization expression of LYKClass.age
sil hidden [transparent] @$s4main8LYKClassC3ageSivpfi : $@convention(thin) () -> Int {
bb0:
%0 = integer_literal $Builtin.Int64, 10 // user: %1
%1 = struct $Int (%0 : $Builtin.Int64) // user: %2
return %1 : $Int // id: %2
} // end sil function '$s4main8LYKClassC3ageSivpfi'
// Int.init(_builtinIntegerLiteral:)
sil public_external [transparent] @$sSi22_builtinIntegerLiteralSiBI_tcfC : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int {
// %0 // user: %2
bb0(%0 : $Builtin.IntLiteral, %1 : $@thin Int.Type):
%2 = builtin "s_to_s_checked_trunc_IntLiteral_Int64"(%0 : $Builtin.IntLiteral) : $(Builtin.Int64, Builtin.Int1) // user: %3
%3 = tuple_extract %2 : $(Builtin.Int64, Builtin.Int1), 0 // user: %4
%4 = struct $Int (%3 : $Builtin.Int64) // user: %5
return %4 : $Int // id: %5
} // end sil function '$sSi22_builtinIntegerLiteralSiBI_tcfC'
// LYKClass.age.getter
sil hidden [transparent] @$s4main8LYKClassC3ageSivg : $@convention(method) (@guaranteed LYKClass) -> Int {
// %0 "self" // users: %2, %1
bb0(%0 : $LYKClass):
debug_value %0 : $LYKClass, let, name "self", argno 1 // id: %1
%2 = ref_element_addr %0 : $LYKClass, #LYKClass.age // user: %3
%3 = begin_access [read] [dynamic] %2 : $*Int // users: %4, %5
%4 = load %3 : $*Int // user: %6
end_access %3 : $*Int // id: %5
return %4 : $Int // id: %6
} // end sil function '$s4main8LYKClassC3ageSivg'
// LYKClass.age.setter
sil hidden [transparent] @$s4main8LYKClassC3ageSivs : $@convention(method) (Int, @guaranteed LYKClass) -> () {
// %0 "value" // users: %6, %2
// %1 "self" // users: %4, %3
bb0(%0 : $Int, %1 : $LYKClass):
debug_value %0 : $Int, let, name "value", argno 1 // id: %2
debug_value %1 : $LYKClass, let, name "self", argno 2 // id: %3
%4 = ref_element_addr %1 : $LYKClass, #LYKClass.age // user: %5
%5 = begin_access [modify] [dynamic] %4 : $*Int // users: %6, %7
store %0 to %5 : $*Int // id: %6
end_access %5 : $*Int // id: %7
%8 = tuple () // user: %9
return %8 : $() // id: %9
} // end sil function '$s4main8LYKClassC3ageSivs'
// LYKClass.age.modify
sil hidden [transparent] @$s4main8LYKClassC3ageSivM : $@yield_once @convention(method) (@guaranteed LYKClass) -> @yields @inout Int {
// %0 "self" // users: %2, %1
bb0(%0 : $LYKClass):
debug_value %0 : $LYKClass, let, name "self", argno 1 // id: %1
%2 = ref_element_addr %0 : $LYKClass, #LYKClass.age // user: %3
%3 = begin_access [modify] [dynamic] %2 : $*Int // users: %5, %8, %4
yield %3 : $*Int, resume bb1, unwind bb2 // id: %4
bb1: // Preds: bb0
end_access %3 : $*Int // id: %5
%6 = tuple () // user: %7
return %6 : $() // id: %7
bb2: // Preds: bb0
end_access %3 : $*Int // id: %8
unwind // id: %9
} // end sil function '$s4main8LYKClassC3ageSivM'
// variable initialization expression of LYKClass.name
sil hidden [transparent] @$s4main8LYKClassC4nameSSvpfi : $@convention(thin) () -> @owned String {
bb0:
%0 = string_literal utf8 "water" // user: %5
%1 = integer_literal $Builtin.Word, 5 // user: %5
%2 = integer_literal $Builtin.Int1, -1 // user: %5
%3 = metatype $@thin String.Type // user: %5
// function_ref String.init(_builtinStringLiteral:utf8CodeUnitCount:isASCII:)
%4 = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String // user: %5
%5 = apply %4(%0, %1, %2, %3) : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String // user: %6
return %5 : $String // id: %6
} // end sil function '$s4main8LYKClassC4nameSSvpfi'
// String.init(_builtinStringLiteral:utf8CodeUnitCount:isASCII:)
sil [always_inline] [readonly] [_semantics "string.makeUTF8"] @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String
// LYKClass.name.getter
sil hidden [transparent] @$s4main8LYKClassC4nameSSvg : $@convention(method) (@guaranteed LYKClass) -> @owned String {
// %0 "self" // users: %2, %1
bb0(%0 : $LYKClass):
debug_value %0 : $LYKClass, let, name "self", argno 1 // id: %1
%2 = ref_element_addr %0 : $LYKClass, #LYKClass.name // user: %3
%3 = begin_access [read] [dynamic] %2 : $*String // users: %4, %6
%4 = load %3 : $*String // users: %7, %5
retain_value %4 : $String // id: %5
end_access %3 : $*String // id: %6
return %4 : $String // id: %7
} // end sil function '$s4main8LYKClassC4nameSSvg'
// LYKClass.name.setter
sil hidden [transparent] @$s4main8LYKClassC4nameSSvs : $@convention(method) (@owned String, @guaranteed LYKClass) -> () {
// %0 "value" // users: %11, %8, %4, %2
// %1 "self" // users: %5, %3
bb0(%0 : $String, %1 : $LYKClass):
debug_value %0 : $String, let, name "value", argno 1 // id: %2
debug_value %1 : $LYKClass, let, name "self", argno 2 // id: %3
retain_value %0 : $String // id: %4
%5 = ref_element_addr %1 : $LYKClass, #LYKClass.name // user: %6
%6 = begin_access [modify] [dynamic] %5 : $*String // users: %8, %7, %10
%7 = load %6 : $*String // user: %9
store %0 to %6 : $*String // id: %8
release_value %7 : $String // id: %9
end_access %6 : $*String // id: %10
release_value %0 : $String // id: %11
%12 = tuple () // user: %13
return %12 : $() // id: %13
} // end sil function '$s4main8LYKClassC4nameSSvs'
// LYKClass.name.modify
sil hidden [transparent] @$s4main8LYKClassC4nameSSvM : $@yield_once @convention(method) (@guaranteed LYKClass) -> @yields @inout String {
// %0 "self" // users: %2, %1
bb0(%0 : $LYKClass):
debug_value %0 : $LYKClass, let, name "self", argno 1 // id: %1
%2 = ref_element_addr %0 : $LYKClass, #LYKClass.name // user: %3
%3 = begin_access [modify] [dynamic] %2 : $*String // users: %5, %8, %4
yield %3 : $*String, resume bb1, unwind bb2 // id: %4
bb1: // Preds: bb0
end_access %3 : $*String // id: %5
%6 = tuple () // user: %7
return %6 : $() // id: %7
bb2: // Preds: bb0
end_access %3 : $*String // id: %8
unwind // id: %9
} // end sil function '$s4main8LYKClassC4nameSSvM'
// LYKClass.deinit
sil hidden @$s4main8LYKClassCfd : $@convention(method) (@guaranteed LYKClass) -> @owned Builtin.NativeObject {
// %0 "self" // users: %6, %2, %1
bb0(%0 : $LYKClass):
debug_value %0 : $LYKClass, let, name "self", argno 1 // id: %1
%2 = ref_element_addr %0 : $LYKClass, #LYKClass.name // user: %3
%3 = begin_access [deinit] [static] %2 : $*String // users: %5, %4
destroy_addr %3 : $*String // id: %4
end_access %3 : $*String // id: %5
%6 = unchecked_ref_cast %0 : $LYKClass to $Builtin.NativeObject // user: %7
return %6 : $Builtin.NativeObject // id: %7
} // end sil function '$s4main8LYKClassCfd'
// LYKClass.__deallocating_deinit
sil hidden @$s4main8LYKClassCfD : $@convention(method) (@owned LYKClass) -> () {
// %0 "self" // users: %3, %1
bb0(%0 : $LYKClass):
debug_value %0 : $LYKClass, let, name "self", argno 1 // id: %1
// function_ref LYKClass.deinit
%2 = function_ref @$s4main8LYKClassCfd : $@convention(method) (@guaranteed LYKClass) -> @owned Builtin.NativeObject // user: %3
%3 = apply %2(%0) : $@convention(method) (@guaranteed LYKClass) -> @owned Builtin.NativeObject // user: %4
%4 = unchecked_ref_cast %3 : $Builtin.NativeObject to $LYKClass // user: %5
dealloc_ref %4 : $LYKClass // id: %5
%6 = tuple () // user: %7
return %6 : $() // id: %7
} // end sil function '$s4main8LYKClassCfD'
// LYKClass.__allocating_init()
sil hidden [exact_self_class] @$s4main8LYKClassCACycfC : $@convention(method) (@thick LYKClass.Type) -> @owned LYKClass {
// %0 "$metatype"
bb0(%0 : $@thick LYKClass.Type):
%1 = alloc_ref $LYKClass // user: %3
// function_ref LYKClass.init()
%2 = function_ref @$s4main8LYKClassCACycfc : $@convention(method) (@owned LYKClass) -> @owned LYKClass // user: %3
%3 = apply %2(%1) : $@convention(method) (@owned LYKClass) -> @owned LYKClass // user: %4
return %3 : $LYKClass // id: %4
} // end sil function '$s4main8LYKClassCACycfC'
// LYKClass.init()
sil hidden @$s4main8LYKClassCACycfc : $@convention(method) (@owned LYKClass) -> @owned LYKClass {
// %0 "self" // users: %6, %2, %14, %1
bb0(%0 : $LYKClass):
debug_value %0 : $LYKClass, let, name "self", argno 1 // id: %1
%2 = ref_element_addr %0 : $LYKClass, #LYKClass.age // user: %5
%3 = integer_literal $Builtin.Int64, 10 // user: %4
%4 = struct $Int (%3 : $Builtin.Int64) // user: %5
store %4 to %2 : $*Int // id: %5
%6 = ref_element_addr %0 : $LYKClass, #LYKClass.name // user: %13
%7 = string_literal utf8 "water" // user: %12
%8 = integer_literal $Builtin.Word, 5 // user: %12
%9 = integer_literal $Builtin.Int1, -1 // user: %12
%10 = metatype $@thin String.Type // user: %12
// function_ref String.init(_builtinStringLiteral:utf8CodeUnitCount:isASCII:)
%11 = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String // user: %12
%12 = apply %11(%7, %8, %9, %10) : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String // user: %13
store %12 to %6 : $*String // id: %13
return %0 : $LYKClass // id: %14
} // end sil function '$s4main8LYKClassCACycfc'
sil_vtable LYKClass {
#LYKClass.age!getter: (LYKClass) -> () -> Int : @$s4main8LYKClassC3ageSivg // LYKClass.age.getter
#LYKClass.age!setter: (LYKClass) -> (Int) -> () : @$s4main8LYKClassC3ageSivs // LYKClass.age.setter
#LYKClass.age!modify: (LYKClass) -> () -> () : @$s4main8LYKClassC3ageSivM // LYKClass.age.modify
#LYKClass.name!getter: (LYKClass) -> () -> String : @$s4main8LYKClassC4nameSSvg // LYKClass.name.getter
#LYKClass.name!setter: (LYKClass) -> (String) -> () : @$s4main8LYKClassC4nameSSvs // LYKClass.name.setter
#LYKClass.name!modify: (LYKClass) -> () -> () : @$s4main8LYKClassC4nameSSvM // LYKClass.name.modify
#LYKClass.init!allocator: (LYKClass.Type) -> () -> LYKClass : @$s4main8LYKClassCACycfC // LYKClass.__allocating_init()
#LYKClass.deinit!deallocator: @$s4main8LYKClassCfD // LYKClass.__deallocating_deinit
}
// Mappings from '#fileID' to '#filePath':
// 'main/main.swift' => 'main.swift'
开始分析
class LYKClass {
var age: Int = 10
var name: String = "water"
}
/*
class LYKClass {
@_hasStorage @_hasInitialValue var age: Int { get set }
@_hasStorage @_hasInitialValue var name: String { get set }
@objc deinit
init()
}
*/
let lykCls = LYKClass()
/*
@_hasStorage @_hasInitialValue let lykCls: LYKClass { get }
*/
// lykCls -> 创建了一个全局的类LYKClass
//sil_global hidden [let] @$s4main6lykClsAA8LYKClassCvp : $LYKClass
看不懂s4main6lykClsAA8LYKClassCvp
这个是什么,可以使用符号重组命令xcrun swift-demangle s4main6lykClsAA8LYKClassCvp
,可以看出来s4main6lykClsAA8LYKClassCvp
就是LYKClass
这个类
图片.png
这是main函数
0% 1% ... 9%等都是虚拟的寄存器
// main
sil @main : $@convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 {
bb0(%0 : $Int32, %1 : $UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>):
alloc_global @$s4main6lykClsAA8LYKClassCvp // id: %2 -> 创建了一个全局的LYKClass对象
%3 = global_addr @$s4main6lykClsAA8LYKClassCvp : $*LYKClass // user: %7
%4 = metatype $@thick LYKClass.Type // user: %6
// function_ref LYKClass.__allocating_init()
%5 = function_ref @$s4main8LYKClassCACycfC : $@convention(method) (@thick LYKClass.Type) -> @owned LYKClass // user: %6
%6 = apply %5(%4) : $@convention(method) (@thick LYKClass.Type) -> @owned LYKClass // user: %7
store %6 to %3 : $*LYKClass // id: %7
%8 = integer_literal $Builtin.Int32, 0 // user: %9
%9 = struct $Int32 (%8 : $Builtin.Int32) // user: %10
return %9 : $Int32 // id: %10
} // end sil function 'main'
网友评论