Understanding Xcode Build System

Eddy📱·2022년 8월 23일
0

Swift

목록 보기
11/11
post-thumbnail

해당 Understanding Xcode Build System를 변역해서 올리는 글입니다.

저의 글보다 실제 영문을 보시는 것을 더 추천합니다!

모든 Swift 프로그램은 실제 기기에서 실행되기 전에 많은 변환이 이루어진다.

이 과정은 보통 Xcode Build System에 의해서 다루어진다.

그래서 Xcode Build System에 대해 알아보록 하자

Problem Statement

모든 프로그램 시스템은 하드웨어와 소프트웨어가 존재한다.

하드웨어는 컴퓨터의 물리적인 파트로 모니터, 키보드 등을 이야기한다.

하드웨어는 보통 소프트웨어에 의해 조작되며 소프트웨어는 하드웨어에게 어떤 것을 일해야할지 알려준다.

소프트웨어는 process를 조작하고 하드웨어는 보통 work를 한다.

소프트웨어 개발자는 보통 소프트웨어 부분에 집중을 한다. 하지만 하드웨어는 Swift로 쓰여진 코드를 직접적으로 읽을 수 없다.

오로지 0, 1만 읽을 수 있다!

그러면 어떻게 Swift code가 어떤 형식으로 변환되어서 하드웨어가 다룰 수 있을까?

이에 대한 답변은 language processing system에 있다!

Language Processing System

Language Processing System는 임의적인 소스 언어로 쓰여진 명령들의 집합으로 생성되는 실행할 수 있는 프로그램의 집합체이다.

이것은 프로그래밍적으로 복잡한 기계어를 사용하는 것을 줄이고 higher-level 언어들을 사용할 수 있도록 허락한다.

이는 iOS, macOS에서 우리가 주로 사용하고 있는데 이것의 이름은 Xcode Build System이라고 부른다.

Xcode Build System

Xcode Build System의 주된 목적은 실행할 수 있는 프로그램을 생성할 것인 여러개의 tasks의 실행을 다룬다.

그래서 Xcode는 많은 arguments, tools를 실행할 수 있다.

이것은 Swift Project에서 쓰여질 때 사용되는 원하는 방식은 아닐 것이다.

그래서 Xcode Build System를 포함해서 대부분의 language processing systems은 5가지로 구성되어 있다.

  • Preprocessor
  • Compiler
  • Assembler
  • Linker
  • Loader

그림으로 보면 아래처럼 작동이 된다.

이제 이것들을 하나씩 살펴 볼 것이다.

Preprocessing

전처리의 목적은 compiler에게 줄 수 있는 방식으로 사용하는 프로그램을 변환시킨다.

macros를 정의로 대체하고 dependencies(의존성)를 발견한 다음 preprocessor directives(전처리 지시문)을 해결한다.

만약에 Swift compiler가 전처리를 가지고 있지 않다면 Swift project에서 macros를 정의하는 것을 허락하지 않는다.

그럼에도 불구하고 Xcode Build System는 부분적으로 이것을 다루고 project build settings에서 설정할 수 있는 Active Compilation Conditions의 방법으로 전처리를 한다.

Xcode는 하위 레벨 빌드 시스템 llbuild를 활용해서 위에서 언급한 의존성(dependencies)을 해결한다.
llbuild는 lower-level build system이라고 부른다.

llbuild

Compiler

컴파일러는 Swift, Objective-C 그리고 C/C++ 의 코드를 의미의 변화없이 기계어로 바꿔주는 역할을 한다.

Xcode는 두 가지 다른 compiler를 사용한다.

  1. 하나는 Swift를 위해서
  2. 하나는 Objective-C, Objective-C++, C/C++ files를 위해서

clang 는 C언어의 family에서 애플의 공식적인 컴파일러다.

이거에 대한 자세한 내용은 clang 에서 볼 수 있다.

swiftc는 Xcode에 의해 Swift 소스 코드를 컴파일하고 실행해서 사용하는 Swift 컴파일러다.

Compiler는 아래의 다이어그램으로 표현할 수 있다

Xcode -> Build Settins에서 보면
Swift Compiler 설정이랑 Apple Clang 설정이 따로 있는 것을 볼 수 있다

Swift Compiler

Apple Clang

컴파일러는 2가지의 주요 부분으로 나뉜다: frontend, backend

frontend는 source 프로그램을 어떤 문법과 type 정보없이 조각들로 나눈다. 그리고 그들을 문법적인 구조를 준수할 것을 강요하다.

그리고나서 컴파일러는 이 구조를 사용해서 source program의 intermediate representation를 생성한다.

source program에 대한 정보를 수집한 symbol table를 생성하고 관리한다.

Symbol는 코드나 데이터의 일부에 대한 이름을 말한다.

symbol table는 변수, 함수, 클래스의 이름을 저장하고 symbol는 특정 데이터의 조각으로 매핑한다.

Swift 컴파일러의 경우 intermediate representation 는 Swift Intermediate Language(SIL)이라고 부른다.

이것은 코드의 분석과 최적화에 사용된다.

SIL로부터 기계어를 직접적으로 만드느 것은 불가능해서 SIL는 LLVM Intermediate Representation 를 통해 하나 이상을 변환한다.

backend 과정동안 Intermediate representation는 어셈블리 코드로 변환한다.

Assembler

Assembler는 사람이 읽을 수 있는 어셈블리 코드를 relocatable(재배치 가능한)로 바꾼다.

코드나 데이터의 집합체인 Mach-O 파일로 이를 만든다.

이 기계어와 Mach-O 파일에 대한 설명이 더 필요하다.

기계어는 numeric 언어로 CPU에 의해서 실행할 수 있는 명령들의 집합을 말한다.

이는 재배치할 수 있다. 그 이유로는 object file이 address space에 있는지에 상관없이 명령이 해당 공간에 대해 상대적으로 실해오디기 때문이다.

Mach-O 파일은 object file, 라이브러리 등을 사용할 수 있는 iOS, macOS 운영체제에서의 특별한 file format이다.

Mac의 인텔 processor, iOS 기기의 ARM processor에서 실행되는 의미있는 chunks로 그룹화된 바이트 스트림이다.

실제로 이 경로로 들어가면

Library/Developer/Xcode/DerivedData/본인프로젝트/Build/Intermediates.noindex/본인프로젝트.build/Debug-iphonesimulator/본인프로젝트.build/Objects-normal/ViewController.o

어셈블리 코드를 확인할 수 있다

확인하는 방법은 여기에서 배워서 했습니다!

Xcode에서 빌드한 이후에 들어가보면 된다.

스크린샷 2022-08-23 오전 8 53 58

Linker

Linker는 iOS, MacOS 시스템에서 실행되는 하나의 Mach-O 파일을 만들기위해서 함께 object fileds, 라이브러리들을 합친 computer program를 말한다.

Build -> Settings 에서 All, Combined를 누르면 Linking를 볼 수 있다.

여기에서 Mach-O Type이 있는 것을 확인할 수 있다

Linker input으로써 두가지 종류의 파일들을 가진다.

이 object 파일들은 여러개의 타입(.dylib, .tbd, .a)들의 assembler phase와 라이브러리들이다.

어셈블러와 링커 모두 Mach-O 파일을 출력으로 생성한다.
하지만 이 둘 사이에 약간의 차이가 있다.

어셈블리 단계에서 나오는 object files은 아직 완료되지 않았다.
일부는 다른 object files나 라이브러리들을 참조하는 누락된 부분을 포함한다.

예를들어 printf 를 코드에 사용한 경우
이 symbol을 libc library (printf function이 구현되어있는 라이브러리)와 연결시켜주는 것은 바로 링커다.

컴파일러 단계에서 생성된 symbol table을 사용해서 여러 object files과 라이브러리들에 대한 참조를 확인한다.

Loader

로더는 운영체제의 하나의 파트로 메모리에서 프로그램을 가져오고 실행시킨다.

로더는 프로그램을 실행하기위해 필요한 메모리 공간을 할당하고 레지스터를 초기 상태로 초기화한다.

추가로 더 많은 지식을 위해서는
Behind the Scenes of the Xcode Build Process가 있다.

이는 꼭 공부하기로..!

profile
Make a better world

0개의 댓글