美文网首页
swift基础_编译和调试

swift基础_编译和调试

作者: 李永开 | 来源:发表于2022-02-09 16:18 被阅读0次

零.编译swiftc

  1. 网上很多教程有问题,建议多看看官网教程

  2. 准备环境
    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.

  3. 下载swift源码
    https://github.com/apple/swift/releases找到最新的版本,使用git clone --branch swift-5.5.2-RELEASE https://github.com/apple/swift.git下载

  4. 运行./swift/utils/update-checkout --tag swift-5.5.2-RELEASE --clone下载编译swift相关的库

图片.png
  1. 编译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
  1. 在vscode的launch.json里面配置我们的swiftc
图片.png
  1. 遇到问题,可以百度搜索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个小时左右,要有耐心,而且电脑尽量不要开其他东西,否则影响速度
  • 这是我参考的教程
  1. 终端执行./swift/utils/build-script --release-debuginfo --debug-swift-stdlib -x --skip-ios --skip-watchos --skip-tvos --swift-darwin-supported-archs="x86_64"
  2. 使用xcode打开cmark.xcodeproj
图片.png
将Scheme选择为cmake,然后 command+B 编译下,1秒就成功了。不要习惯性的command+R,这样的话它会一直run,永远不会结束
图片.png
特别快
图片.png
  1. 编译ALL_BUILD
    打开Swift.xcodeproj
图片.png

找到ALL_BUILD(话说真的难找啊)


图片.png

选中


图片.png
然后编辑scheme
图片.png
选择优化选项
图片.png

点击close,然后command+b编译吧。

  1. 创建自己的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
  1. 在自己的target的main里面写一个class,然后初始化,并打上断点
图片.png
HeapObject.cpp里面打上断点,然后编译,你会发现断点能走进源码了😄
图片.png

二.分析SIL

SIL:swift intermediate language -> swift中间语言


执行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'

相关文章

网友评论

      本文标题:swift基础_编译和调试

      本文链接:https://www.haomeiwen.com/subject/iypwkrtx.html