Xcode의 빌드 과정
GCC를 통해 C언어를 빌드 하듯, Swift 언어는 Xcode를 통해 빌드가 됩니다. 따라서 이번에는 Xcode의 빌드 과정에 대해 학습해보았습니다. Swift는 C언어 기반이기 때문에 컴파일 과정이 매우 비슷합니다.
전처리기 (Preprocessing)
전처리기는 소스 코드를 컴파일러가 읽을 수 있는 형식으로 전환해줍니다. Swift에는 전처리기가 없기 때문에 매크로 등을 정의할 수 없습니다. 하지만 전처리문을 부분적으로라도 사용할 수 있도록 [Build Settings] → ‘Active Compilation Coditions’를 제공해줍니다. Swift에서는 release와 debug를 구분하거나, OS를 구분할 때에 전처리문을 사용합니다.
#if DEBUG
print("디버그")
#endif
컴파일러 (Compiler)
Xcode는 swiftc와 clang이라는 두 가지의 컴파일러를 사용합니다. 용어에서 유추할 수 있듯이 swiftc는 Swift 언어를, clang은 objective-c, C, C++ 등을 컴파일 해줍니다. 스위프트 또한 Frontend → IR → Backend로 변환되고, Backend 단계에서 IR이 어셈블리 코드로 변환됩니다. 스위프트의 컴파일러는 추후에 자세히 살펴보겠습니다.
[Target] → [Build Settings]를 보면 Swift Compiler와 Clang이 각각 나뉘어져 있는 것을 확인할 수 있었습니다.
여기서 새로 알게 된 점은 디버그 모드와 릴리즈 모드의 최적화 수준(Optimization Level)이 다른 것을 알 수 있었습니다. 제 생각으론 해당 코드가 정상적으로 동작하는지 확인하기 위해 디버그 모드에선 No Optimization이 기본값이고, 릴리즈 모드에서는 이미 디버그를 완료했다고 가정한 뒤 앱의 속도가 중요하기 때문에 최적화를 수행하는 것이라 생각합니다.
어셈블러 (Assembler)
어셈블러는 어셈블리 코드를 재배치가능(relocatable)한 기계어로 변환해주는데, 이때 Mach-O 파일을 생성합니다. (C언어의 .o 파일을 생성하는 것과 비슷한 원리입니다.) 재배치 가능한 파일이란 실행 가능한 파일을 생성하기 위해 다른 오브젝트 파일들과 링킹할 수 있는 코드와 데이터를 갖는 파일입니다. 바이너리 코드와 데이터를 가지고 있으며, 메모리로 직접 할당되어 실행됩니다. [Library] → [Developer] → [Xcode] → [DerivedData]에서 앱을 하나 골라 .o file을 찾아 열어보았습니다.
.o 파일을 열어보는 명령어는 다음과 같습니다.
hexdump ~/[파일이름].o
링커 (Linker)
링커는 위에서 확인한 Mach-O 파일을 병합하여 iOS 또는 macOS가 실행될 수 있는 하나의 실행 가능한 Mach-O 파일로 만듭니다. 어셈블러와 링커는 둘 다 오브젝트 파일을 생성한다는 공통점이 있지만, 어셈블러는 재배치가능한 파일로, 다른 오브젝트 파일을 참조하는 부분이 없고, 링커는 symbol table을 활용하여 오브젝트 파일들에 대한 참조를 확인하고, 연결까지 해준다는 차이점이 있습니다. 만약 Executable 설정을 다른 설정으로 변경하게 되면 실행이 되지 않습니다.
로더 (Loader)
마지막으로 운영체제의 일부인 로더에서 프로그램을 메모리에 적재하고 실행합니다. 로더는 프로그램을 초기화하고 실행하기 위한 메모리 공간을 할당합니다.
[출처]
'iOS' 카테고리의 다른 글
[UIKit] UILabel.text와 문자열 보간법의 옵셔널 표현의 차이 (0) | 2025.01.03 |
---|---|
[iOS] SwiftLint 설치 및 적용하기 (0) | 2023.12.23 |
[iOS] 협업 시 하나의 Bundle Identifier로 설정하기 (Provisioning Profile, Certificate 공유) (0) | 2023.11.21 |
[iOS] Firebase FCM을 이용한 서버 푸시 구현 (4) | 2023.11.15 |
[iOS] UserNotification을 사용하여 로컬 알림 만들기 (0) | 2023.10.03 |