开发者

Learning and Understanding the Xcode Build System

Alrigh开发者_Go百科t, I'm curious about the build process with Xcode. Setting up multiple Targets, how to automate versioning and generally understanding the system so I can manipulate it to do what I want.

Does anyone have any books or can point me to some documentation somewhere so that I can figure all of this out?

Thanks a ton.

Another thing, if anyone actually sees this since changing it.

But any books anyone is aware of that will focus on Xcode 4? There's Xcode 3 Unleashed but I'd be real curious if there are any books that focus heavily on Xcode 4.


One thing that is really essential for consistent, reproducible, automatable builds is knowledge of the xcodebuild command. Sadly I can't find any official docs on it apart from the manpage (type man xcodebuild). There's a useful guide to automating iphone builds here that includes building with xcodebuild and versioning with agvtool. This is just as relevant to general building of Mac apps.

Generally building with xcodebuild is very simple:

cd project_dir
xcodebuild -project myproject.xcodeproj -configuration Release ARCHS="x86_64 i386" build

Once you can build from a script like this it's very easy to slot into an automated build system.


Xcode build process

[LLVM], Clang LLVM, Swift LLVM

Xcode uses xcodebuild internally[Example]

Learning and Understanding the Xcode Build System

Objective-C language

1. Preprocessing
[Driver][Preprocessing][Parsing and Semantic Analysis] Parser `.m -> AST`
    2.Compiling by compiler(Clang)
    [Code Generation and Optimization](GCC_OPTIMIZATION_LEVEL) LLVM IR Generation `AST -> LLVM IR`. 
    3. Assembling
    [LLVM backend] LLVM `LLVM IR -> .o`
4. Static Linking(ld)
5. Output binary

Xcode and Objective-C exposes some of these steps:

  1. Preprocessing:
  • Replace macros

  • Splits .h and .m.

    In Xcode, you can look at the preprocessor output of .m file by selecting

      select .m file -> Product -> Perform Action -> Preprocess
    
  1. Compiling - translates a low-level intermediate code.
    Often you can see this file when debug a code that you are not owned. Xcode allows you to review the output.

     select .m file -> Product -> Perform Action -> Assemble
    
  2. Assembling(produce .o) - translates code into object file (.o file)[Mach-O] In Xcode, you’ll find these object files inside the <product_name>.build/Objects-normal folder inside the derived data directory.

  3. Static Linking(produce .app, .a, .framework ...)[About] - It is a part of static linker that has to resolve symbols between object files and libraries/frameworks. This process produce a merged executable file which can contain additional resources and dynamic binary

  4. Output binary

Swift language

LVVM Frontend

1. Preprocessing
[Parse module] Parser `.m -> AST`
[Sema module] Type checking > type-checks AST and annotates it with type information
    2.Compiling by compiler(Swiftc)
    [SILGen module] SIL Generator `AST -> raw SIL` > optimizations
        `Guaranteed Optimization Passes`, `Diagnostic Passes` `raw SIL -> canonical SIL. This optimization is applied in any case 
        `Optimization Passes`(SWIFT_OPTIMIZATION_LEVEL) 
    [IRGen] LLVM IR Generation

LVVM Backend
    3. Assembling
    [LLVM backend] LLVM `LLVM IR -> .o`
4. Static Linking(ld)
5. Output binary

Swift Example

import Foundation

class ClassA {
    func foo(param: String) -> Int {
        return 1
    }
}

AST

-dump-parse            Parse input file(s) and dump AST(s)
-dump-ast              Parse and type-check input file(s) and dump AST(s)
-print-ast             Parse and type-check input file(s) and pretty print AST(s)
# xcrun swiftc -dump-parse "ClassA.swift" 

(source_file "ClassA.swift"
  (import_decl range=[ClassA.swift:8:1 - line:8:8] 'Foundation')
  (class_decl range=[ClassA.swift:10:1 - line:14:1] "ClassA"
    (func_decl range=[ClassA.swift:11:5 - line:13:5] "foo(param:)"
      (parameter "self")
      (parameter_list range=[ClassA.swift:11:13 - line:11:27]

...
#xcrun swiftc -dump-ast "ClassA.swift" 

(source_file "ClassA.swift"
  (import_decl range=[ClassA.swift:8:1 - line:8:8] 'Foundation')
  (class_decl range=[ClassA.swift:10:1 - line:14:1] "ClassA" interface type='ClassA.Type' access=internal non-resilient
    (func_decl range=[ClassA.swift:11:5 - line:13:5] "foo(param:)" interface type='(ClassA) -> (String) -> Int' access=internal
      (parameter "self")

...      
# xcrun swiftc -print-ast "ClassA.swift"
import Foundation

internal class ClassA {
  internal func foo(param: String) -> Int
  @objc deinit
  internal init()
}
#xcrun swiftc -frontend -emit-syntax "ClassA.swift" | python -m json.tool

{
    "kind": "SourceFile",
    "layout": [
        {
            "kind": "CodeBlockItemList",
            "layout": [
                {
                    "kind": "CodeBlockItem",
                    "layout": [
                        {
                            "kind": "ImportDecl",
                            "layout": [
                                {
                                   
...

SIL

-emit-silgen           Emit raw SIL file(s)
-emit-sil              Emit canonical SIL file(s)
# xcrun swiftc -emit-silgen  "ClassA.swift"                      

sil_stage raw

import Builtin
import Swift
import SwiftShims

import Foundation

class ClassA {
  func foo(param: String) -> Int
  @objc deinit
  init()
}

// ClassA.foo(param:)
sil hidden [ossa] @$s6ClassAAAC3foo5paramSiSS_tF : $@convention(method) (@guaranteed String, @guaranteed ClassA) -> Int {
// %0 "param"                                     // user: %2


sil_vtable ClassA {
  #ClassA.foo: (ClassA) -> (String) -> Int : @$s6ClassAAAC3foo5paramSiSS_tF // ClassA.foo(param:)
  #ClassA.init!allocator: (ClassA.Type) -> () -> ClassA : @$s6ClassAAACABycfC // ClassA.__allocating_init()
  #ClassA.deinit!deallocator: @$s6ClassAAACfD // ClassA.__deallocating_deinit
}



// Mappings from '#fileID' to '#filePath':
//   'ClassA/ClassA.swift' => 'ClassA.swift'

...

LLVM IR

-emit-ir               Emit LLVM IR file(s)
xcrun swiftc -emit-ir  "ClassA.swift"
; ModuleID = '<swift-imported-modules>'
source_filename = "<swift-imported-modules>"
target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx12.0.0"

%objc_class = type { %objc_class*, %objc_class*, %swift.opaque*, %swift.opaque*, %swift.opaque* }

define i32 @main(i32 %0, i8** %1) #0 {
entry:
  %2 = bitcast i8** %1 to i8*
  ret i32 0
}

...
-emit-object           Emit object file(s) (-c)
-emit-executable       Emit a linked executable

[Build With Timing Summary]

Also you can use Xcode Report Navigator to learn more about build process. Moreover Xcode v14 includes a great feature to visualisation and analyzation of build process

Show the Report navigator -> <select build> -> <right_click> -> Show in Timeline

//or

Show the Report navigator -> <select build> -> Editor -> Open Timeline

Learning and Understanding the Xcode Build System

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜