본문 바로가기
WWDC

WWDC 18 - Behind the Scenes of the Xcode Build Process

by vapor3965 2021. 6. 27.

목차


    • 세션보면서 정리한 내용입니다. 해석이 잘못된 경우가 있을수있으니 발견하시면 댓글로 남겨주시면 감사하겠습니다🙏🏻

     

     

    https://developer.apple.com/videos/play/wwdc2018/415/

     

    Behind the Scenes of the Xcode Build Process - WWDC18 - Videos - Apple Developer

    Ever wonder what happens when you build your project in Xcode? Learn how Xcode automates the steps required to build an application, and...

    developer.apple.com

     

     

     


     

    관련내용

    • Xcode가 어떻게 빌드하는 과정을 자동화하는지 ,
    • 어떻게 나누어진파일들, 또는 파일들의위치가변경되도 호출되어질수있는지,
    • clang, swiftc, linker 가어떻게 같이 작동하는지

    👍요약

    • xcode는 커맨드라인으로실행되는데 수천개의명령어가있고, 이를 xcodebuild가 자동화해준다.
    • 👍xcode10부터는 incremental build ( 증분빌드 ) 라는 개념이 생겼다.
      • 이는, 빌드정보들을 저장하여, 변화가있을때만 리빌드하는 개념이다.
      • 가능한이유는, 각 작업들은 hash값들을 가지고있고, 빌드시스템은 이전빌드와 현재의 정보들을 비교하여 구현해낸다.
    • 👍Clang은 각 호출한 헤더들을 헤더맵을 만들어냄으로써 호출이가능해진다.
    • 다양한파일들에서 같은 헤더들을 호출하면 코드들이 방대해지는데, 이를 Clang Module을 통하여 한번만 만들어지도록 하여 더 빠르게 실행되도록한다.
    • 👍swift타깃은 header파일이없기때문에, 컴파일할때 추가적인작업이필요하다. 즉, 사용된타입을 하나의타깃안에서 모두찾도록한다. 하지만 xcode10부터는 이러한 파일들을 최대한 공통적으로 그룹으로만들어, 오버헤드를 줄이도록 개선했다.
      • 즉, swift는 objective-c보다 컴파일이 느릴수밖에없다

     


    빌드시스템

    • 다양한작업들의실행은 커맨드라인으로 통해 실행된다
    • Clang, LD, AC tool, IB tool, Code sign,

    • 이러한 실행들은 특정한arguments, configuration에 지정된순서로 실행되어져야한다
    • xcode build system은 이러한 ㅈ가업들을 자동하해준다.
      • 수천개이상이될텐데, 이러한 코드들을직접 타이핑하는건싫자나~
      • 아래와같이 하나로 쏵~실행가능!


    • 아래와같이 이어진다.
    • swift, objective-c, storyboard, xcassets,


    • 의존성정보로부터 실행순서들이결정되어진다.
      • 즉, PetViewController.m을파일을 인풋으로 컴파일하여, PetViewController.o 파일로만들고, 링커가 이파일들을 인풋으로받아, Petwall 결과물을만들고,
      • petwall인풋은 petWall.app 번들로 만들어진다.
    • 아래와같이 병렬적으로실행되면서 마지막에 링커가받는다.
      • 각 실행들은 의존성ㅇ을갖는다.

    빌드과정

    • 우선, build description을 받는다.
    • parse하고, 프로젝트안에 있는 파일들, target, 의존성관계, build setting을 계산하고,
    • 아래와같이 트리과정이생긴다


    • low-level engin 은 위의 그래프를 아래와같이 의존성, 순서들을찾고, 어떤것을실행하고, 어떤것을병렬적으로처리할지한다.
      • 이러한것은 llbuild라는 오픈소스로 운영된다

    • Clang은 objective-C 파일을 object(.o)파일로만들뿐만아니라, .d라는 어떤헤더파일들이 포함되어있는지 리스트가담긴. 것을생성한다!
      • 이는, 다음에빌드할때, 파일에 헤더파일의변화가있을경우 재컴파일하도록 하게해준다.

    • 앱이커질수록 파일들도많아지고, 매번 빌드할때마다 모든 컴파일하고싶지는않을것이다 - 오래걸리니까,
    • 그래서대신 빌드시스템은 몇개의 subset만실행할수도있다
      • 이전에빌드했을때, 달라진점만 빌드하도록!
      • 이를👍 incremental build 라한다! - 증분빌드
      • 그래서, 각 정확한의존성을갖는것이 중요하다!


    • 그래서, 어떻게 변화가 증분빌드에영향을주는지보자
    • 또한 어떻게 변화를감지할까?
      • 각작업들은 특정 singature를가진다 - 관련정보들을 바탕으로 계산된 해시종류로,
      • 그래서 빌드시스템은 이러한 이전의 singature와 현재 signature를 추적한다.
      • 그러므로, 다르면 다시 리빌드한다.
    • 그럼어떻게 내가 이러한 빌드시스템에도움을줄수있을까?
      • 작업순서실행을 고려하지말라, 이것은 빌드시스템이할일이니까,
      • 대신우리는 의존성을 생각할수있다.
      • Buit in 단계에서 asset, storyboard, 등등 파일들을 지정해줄수있다.


      • Target dependencies 를 지정한다.
        • xcode10부터는 이를통해 병렬적으로? 수행잘되도록해주다.
        • 하지만, 따로 run script를 작성하면, 이러한 병렬적 실행전에 우선적으로 runscript가실행된다.

      • 라이브러리들을 지정해준다.

      • 빌드phase에 잘지정해준다.
        • 하지만 빌드시스템은 더 나은방법을생각한다면 무시되어질수있다.

      • build parel 를 체크하도록함으로써 병렬적으로실행하도록 하게하라.
        • 체크해재한다면 명시된순서대로 하나하나씩실행하게된다

    • 마지막으로는 개발자가 script를 작성하는것이다.
      • input, output 지정
      • 이러한경우, 빌드시스템은 불필요하게리빌드하지않는다.

    • 정학한의존성정보들은 빌드시스템이 더 병렬적으로, 더일관된결괄르줄것이다
    • 만약 모든코어를 잘활용할수있도록하기위해서는 Building Faster in xcode session을참고하셈!

     


     

    Clang

    • apple의 공식적인 C컴파일러다. C,C++, Objective
    • 컴파일과정
      • api를접근하고싶다면, ios로부터, 구현을, 헤더파일을 추가해야한다.
      • 헤더파일은 약속이다. 구현된어떠한파일이존재할것이라고
        • 만약그렇지않다면, 컴파일타임때 오류를발생시키지않는다?
        • 대신 링크타임때 오류를발생시킨다.
    • 파일,헤더들을 위치를 변경시켜도 문제없이 빌드가가능하다.
    • 그럼 어떻게 컴파일러는 헤더파일을찾을까?
      • import 헤더를 하면, 헤더맵이 생성? 사용되어진다. 이것은 Xcodebuildsystem에의해, 헤더파일이어디있는지찾기위해.
        • 헤더맵은 프레임워크이름을 추가시키고,
      • 항상 헤더파일을 프로젝트에 추가시켜랑, -import 할때, 프레임워크이름도붙여라.
      • 그리고이름은 유니크하게지어라 .그렇지않으면 다른헤더를 가리게된다
      • 시스템헤더파일은 헤더맵을 만들지않는다. 왜냐하면 이미유니크하기때문이고. 그래서 설치된sdk에서 경로를 찾는다. 다양한경로를찾아보고, 그래도없다면 더이상찾지않는다.
    • 여튼, 그런 헤더파일을 호출하고나면, 엄청많은 코드들이생성되어진다. 즉, 같은 헤더를 다른파일에서 가각호출하면 이러한코드들이엄청방대해진다.
    • 하지만, Clang modules은 프레임워크안의 헤더들을 오직한번만 찾고,파싱하게한다. 그리고이러한정보들을 디스크에 저장하고, 캐싱한다그럼으로써 빌드시간이빨리된다!
      • 시스템프레임워크들은 이렇게 찾아지고, 캐시되어진다.
    • 우리가만든 프레임워크는 어떻게 찾고 어떻게 빌ㄷ할까?
      • 여기서 Clang의 Virtual File system이 소개된다
      • 컴파일러는 가상의 추상적으로 파일을만들어, 헤더와모듈을 생성해낸다.

     

     

    swift compile

    • swift는 objective-c와 달리 헤더파일을 작성하지않는다 .
    • 이덕분에 초보자들이시작하기좋다.
    • 하지만 이 덕분에 컴파일러는 추가적인 book-keeping 을 한다.
    • 아래와같은 4가지작업을한다.


    • 우선, 작성된코드안에 다른 코드에서 생성된 타입을 사용하는 타입이있는지 확인한다(load and parse)
      • 즉 하나의 swift파일을 컴파일하기위해서 target안에 작성된 모든코드들을 탐색한다
      • xcode9에서는 이를 병렬적으로 모두탐색했다
    • xcode10부터는 이러한오버헤드를 줄였다
      • 각파일들을 최대한공유할수있도록 그룹으로나누었다
      • 그리고 각그룹별로만 모두탐색하도록하게했다.
      • 즉그룹별 상대적으로덜관련있어야 더 빌드속도가빨라진다
    • swift코드뿐만아니라 objective-c를 사용할때는 Clang을 사용한다.
    • swift는 objective-c가 사용할수있도록 Objective-C header 인터페이스를 생성한다.

    • 다른 swift타겟에서도 사용될수있도록하기위해 Clang’s의 모듈과같은개념을 빌드한다.
      • 즉, import를 사용해야한다. ( XCTest에서 테스트코드작성시, swift모듈을 import해야사용할수있다.
      • .swiftmodule을통하여 선언부를확인할수있게된다
        • 바이너리형태이고, 함수, 디버깅을위해 private도 포함되어있다.
    • 증분빌드( Incremental build ) 를하기위해, swiftc컴파일러는 부분적으로 .swiftmoudle 파일을만들고, 이를 나중에 전체 moudle로 합친다 또한 objective C Header를 만들어낸다.
      • 이것은 링커가 하나의 실행가능한파일로만들기위한방법과비슷하다


    링커

    • 마지막작업으로, 두개의컴파일러에의해 만들어진 두 object file을 하나의 실행파일로만들기위한작업을한다.
    • 두개의파일을 취하는데, Object file과, 라이브러리 ( .dylib, .tbd, .a, static archive )
    • 링커단계에서는 코드를생성하거나 삭제하지않는다. 오직 카피, 분리할뿐이다
    • symbol
      • 코드,데이터의 fragment를 위한이름이다
      • 코드들은 다른 symbols를 참조할수있고,
      • 이 symols는 링커가어떻게행동할지를 명시할수있는 속성을가지고있다.
        • 예로, Weak symbols
    • object file
      • 컴파일되었지만, 실행가능한파일이이아니다.
    • 라이브러리
      • target의 부분으로써 build되어진것이 아닌 symbol 명시한다
      • Dylibs - 다이나믹라이브러리
      • TBDs - Text Based Dylibs
        • mapKit,이나 이러한 프레임워크는 코드가굉장히방대해서, 모두다 넣기보다는, body를지우고, name만남긴형태로사용한다.
      • static archive
        • .o 파일들의 컬렉션이다 - AR?
    • 링커과정
      • object file들은 이미컴파일과정에서 실제코드이름이아닌, mangle된 symbol로 변형되있다.
      • __Text영역에 string과 실행가능한 영역으로분리하고, 각각에맞는 코드들을 넣는다. 각 mangled symbol들을 각 다른 파일에서 찾아, 같은 symbol이 있따면, 그에관련한 코드들을 또 집어넣어준다.
      • 찾는과정에서 링커파일에 없는 symbol들은 추가하지않는다.
      • 그리고 .tbd파일에서도 찾으며, .tbd파일관련 함수들은 모두 고대로 복사하지않는다. 대신 어느정도 유추할수있도록만 복사한다.
      • 글로벌변수들을 _Data영역에저장한다.
      • __LINKEDIT 에는 metadata로, 링커툴이 Opertaing system을 위한 정보를 남기기위해 사용하는, ( dynamic linker가 런타임때 고치기위한 ? )

    댓글