์‹ค์ œ ์ปดํŒŒ์ผ, ๋งํ‚น์ด ๋๋‚œ ๋’ค์˜ ๊ฒฐ๊ณผ๋ฌผ์— ๋Œ€ํ•ด์„œ๋Š” ์ž˜ ๋ชจ๋ฅด๋Š” ๊ฒƒ ๊ฐ™๋‹ค. ์‹คํ–‰ ํŒŒ์ผ์€ ์–ด๋–ป๊ฒŒ ๊ตฌ์„ฑ๋˜์–ด ์žˆ๋Š” ๊ฑธ๊นŒ?

์šฐ๋ฆฌ๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” ํ”„๋กœ๊ทธ๋žจ๋“ค์€, ๋ฐ”์ด๋„ˆ๋ฆฌํ™”๋˜์–ด ์žˆ๋Š” ํŒŒ์ผ์˜ ํ˜•ํƒœ๋กœ ์กด์žฌํ•œ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ, ์ด ์‹คํ–‰ํŒŒ์ผ์˜ ํ˜•ํƒœ๋Š” OS์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ํ˜•ํƒœ๋กœ ์กด์žฌํ•œ๋‹ค. ํ„ฐ๋ฏธ๋„์—์„œ ์šฐ๋ฆฌ๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” ls์˜ binary file ์ •๋ณด๋ฅผ ์ณ๋ณด์ž.

file /bin/ls
/bin/ls: Mach-O universal binary with 2 architectures: [x86_64:Mach-O 64-bit executable x86_64] [arm64e:Mach-O 64-bit executable arm64e]

Mach-O? ์ด๊ฑด ์ฒ˜์Œ ๋“ค์–ด๋ณด๋Š” ๊ฒƒ ๊ฐ™๊ณ , x86, arm64๋Š” ๋“ค์–ด๋ณธ ๊ฒƒ ๊ฐ™๋‹ค. ํ›„์ž๋Š” cpu architecture๋ฅผ ๋งํ•œ๋‹ค. x86์€ ์ธํ…”์—์„œ๋งŒ๋“  cpu ์•„ํ‚คํ…์ณ์ด๊ณ , arm์€ apple ์‹ค๋ฆฌ์ฝ˜ ์ž‘ํ’ˆ์ด๋‹ค. ๊ทธ๋Ÿผ ์ดํ›„๋กœ๋Š” ์‹คํ–‰ ํŒŒ์ผ์˜ ํ˜•ํƒœ์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด์ž.

Executable File Format

  • Comparison of executable file formats - wikipedia

  • Mach-O : Mach Object File Format

    • Mach kernel์„ ๊ธฐ๋ณธ์œผ๋กœ ํ•˜๋Š” OS๋“ค์—์„œ ์‚ฌ์šฉํ•˜๋Š” ์‹คํ–‰ํŒŒ์ผ, ๋ชฉ์ ํŒŒ์ผ, ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ, ์ฝ”์–ด๋คํ”„ ํŒŒ์ผ ํฌ๋ฉง
    • Mach kernel์„ ์‚ฌ์šฉํ•˜๋Š” OS : macOS, iOS, tvOS, watchOS, NeXTSTEP
  • PE: Portable Executable

    • Windows OS์˜ ์‹คํ–‰ํŒŒ์ผ, ๋ชฉ์ ํŒŒ์ผ, ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ(DLL) ํŒŒ์ผ ํฌ๋ฉง
    • ์‹คํ–‰ํŒŒ์ผ ํ™•์žฅ์ž: .EXE
  • ELF: Executable and Linkable Format

    • Unix ๊ณ„์—ด ์‹คํ–‰ํŒŒ์ผ, ๋ชฉ์ ํŒŒ์ผ, ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํŒŒ์ผ ํฌ๋ฉง
    • DWARF: ํ‘œ์ค€ ๋””๋ฒ„๊น… ํŒŒ์ผ ํฌ๋ฉง - โ€˜Debugging With Attributed Record Formatsโ€™
  • a.out: Assembler Output

    • ์˜ค๋ž˜๋œ Unix-like OS์˜ ์‹คํ–‰ํŒŒ์ผ, ๋ชฉ์ ํŒŒ์ผ, ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—์„œ ์‚ฌ์šฉ๋˜๋Š” ํŒŒ์ผ ํฌ๋ฉง
    • a.out์€ ์ผ๋ถ€ complier๋‚˜ linker๋“ค์— output ์ด๋ฆ„์„ ์ง€์ •ํ•˜์ง€ ์•Š์•˜์„ ๋•Œ default output name์œผ๋กœ ์‚ฌ์šฉ๋จ
      • ์‹ค์ œ๋กœ a.out format์„ ์‚ฌ์šฉํ•˜์ง€๋Š” ์•Š์Œ

Mach-O Terminology

WWDC16, Optimizing App StartUp Time์— ์žˆ๋Š” ๋‚ด์šฉ์ด๋‹ค.

  • File Types
    • Executable
      • ์•ฑ ์‹คํ–‰์„ ์œ„ํ•œ main binary
    • Dylib
      • dynamic library (a.k.a DSO, DLL)
    • Bundle
      • ๋งํฌ๋  ์ˆ˜ ์—†๋Š” Dylib, dlopen()์œผ๋กœ ์‹คํ–‰๋œ๋‹ค.
      • plug-ins
  • Image
    • ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ dylib, bundle ์˜๋ฏธ
  • Framework
    • resource, header์™€ ํ•จ๊ป˜ directory๊ฐ€ ์žˆ๋Š” dylib

์—ฌ๊ธฐ์„œ ํ—ท๊ฐˆ๋ฆฌ๋Š”๊ฒŒ ์šฉ์–ด๋‹ค. Framework๋Š” ๊ทธ์ž์ฒด๋กœ Bundle์ด๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ทธ Bundle์•ˆ์— ์žˆ๋Š” Resource๋“ค์„ NSBundle๋กœ ๊ฐ€์ ธ์™€์„œ ์‚ฌ์šฉ๊ฐ€๋Šฅํ•˜๋‹ค. ์—ฌ๊ธฐ์„œ Bundle์€ ๋˜ ๋‹ค๋ฅธ ์˜๋ฏธ์ด๋‹ค. ๋ฌธ๋งฅ์— ๋”ฐ๋ผ ์ดํ•ดํ•˜๋Š” ๊ฒƒ์ด ํ•„์š”ํ•˜๋‹ค.

CPU Architectures

Build Setting์˜ Excluded Architectures์—์„œ ์„ค์ • ๊ฐ€๋Šฅํ•˜๋‹ค.

|architecture|์ ์šฉ ๊ธฐ๊ธฐ|๋น„๊ณ | |:----------:|:---:--------|::----| |armv7|iPhone 4s, iPad3, iPad Mini1, ~iPod Touch5|32bit| |armv7s|iPhone 5, iPhone 5C, iPad4|32bit, armv7 ํ˜ธํ™˜| |arm64|iPhone 5S ~ iPhone X [Max],
iPad Air1 ~ 2, iPad Pro1 ~ 2, ~iPad7, ~iPad Mini4
~iPad Touch7|64bit| |arm64e|iPhone XR, iPhone XS [Max], iPhon 11 [Pro [Max]
iPad Pro3, iPad Air3, iPad Mini5|64bit, arm64 ํ˜ธํ™˜| |i386|32bit ๊ธฐ๊ธฐ์— ๋Œ€์‘ํ•˜๋Š” Simulator|32bit| |x86_64|64bit ๊ธฐ๊ธฐ์— ๋Œ€์‘ํ•˜๋Š” Simulator, Mac|64bit|

Universal binary (Fat binary)

๋‘ ๊ฐœ ์ด์ƒ์˜ ์•„ํ‚คํ…์ณ๋ฅผ ์ง€์›ํ•˜๋Š” ๋ฐ”์ด๋„ˆ๋ฆฌ ํŒŒ์ผ(์‹คํ–‰ ํŒŒ์ผ)

์„œ๋กœ ๋‹ค๋ฅธ ์•„ํ‚คํ…์ณ๋กœ ๋นŒ๋“œ๋œ ๋ฐ”์ด๋„ˆ๋ฆฌ๋ฅผ ํ•˜๋‚˜์˜ ๋ฐ”์ด๋„ˆ๋ฆฌ๋กœ ๋ถ™์—ฌ ๋†“์€ ๊ฒƒ (concatenating)

  • Xcode > Build Settings > Architectures > Build Active Architecture Only

ํ•ด๋‹น ์˜ต์…˜์„ ํ‚ค๋ƒ/๋„๋ƒ์— ๋”ฐ๋ผ output๋˜๋Š” app์˜ ์•„ํ‚คํ…์ณ๊ฐ€ ๋‹ฌ๋ผ์ง„๋‹ค. ๋ณดํ†ต Debug๋Š” on, Release๋Š” off์ด๋‹ค. Debug๋Š” ๋ณดํ†ต simulator, ํŠน์ • device ํƒ€๊ฒŸ์œผ๋กœ๋งŒ ๋นŒ๋“œํ•˜๊ณ  ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ตณ์ด ๋‹ค๋ฅธ ์•„ํ‚คํ…์ณ์— ๋Œ€ํ•ด ๋นŒ๋“œํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค. ํ•˜์ง€๋งŒ realease ์‹œ๋Š” ์ž„์˜์˜ ๊ธฐ๊ธฐ์— ๋Œ€์‘ํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ์—ฌ๋Ÿฌ๊ฐœ ์•„ํ‚คํ…์ณ๋กœ ํ•˜๋‚˜๋กœ ํ•ฉ์ณ์ ธ ์žˆ๋Š” ์‹คํ–‰ํŒŒ์ผ์„ ๋งŒ๋“ค์–ด์•ผ ํ•œ๋‹ค. ์ด๋Ÿฐ ๋ ‡๊ฒŒ ์—ฌ๋Ÿฌ ์•„ํ‚คํ…์ณ๋ฅผ ๋Œ€์‘ํ•˜๋Š” ์‹คํ–‰ํŒŒ์ผ์„ **Universal binary(fat binary)**๋ผ ํ•œ๋‹ค.

# Simulator, Build Active Architecture Only : Yes 
$ file testFramework
testFramework: Mach-O 64-bit executable x86_64
 
# Simulator, Build Active Architecture Only, Apple Silicon Mac : Yes 
$ file testFramework
testFramework: Mach-O 64-bit executable arm64
 
# Simulator, Build Active Arhitecture Only : No
$ file testFramework
testFramework: Mach-O universal binary with 3 architectures: [x86_64:Mach-O 64-bit executable x86_64] [i386:Mach-O executable i386] [arm64:Mach-O 64-bit executable arm64]
testFramework (for architecture x86_64):     Mach-O 64-bit executable x86_64
testFramework (for architecture i386):       Mach-O executable i386
testFramework (for architecture arm64):      Mach-O 64-bit executable arm64
 
# Generic iOS Device, Build Active Architecture Only : No
$ file testFramework
testFramework: Mach-O universal binary with 2 architectures: [arm_v7:Mach-O executable arm_v7] [arm64:Mach-O 64-bit executable arm64]
testFramework (for architecture armv7):      Mach-O executable arm_v7
testFramework (for architecture arm64):      Mach-O 64-bit executable arm64

simulator๋ฅผ ์—†์• ๋‹ˆ i386 ์•„ํ‚คํ…์ณ๊ฐ€ ์‚ฌ๋ผ์กŒ๋‹ค. ๋˜ ๊ฐ๊ฐ์˜ ์˜ต์…˜์— ๋”ฐ๋ผ ๋ฐ”์ด๋„ˆ๋ฆฌ๊ฐ€ ๋‹ค๋ฅด๊ฒŒ ์ƒ์„ฑ๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

Universal Dynamic Framework

Universal binary (library) + Resources

์ด์ „์— apple์—์„œ์˜ Framework๋Š” library์— resource๊ฐ€ ํ•ฉ์ณ์ง„ ํ˜•ํƒœ๋ผ ํ–ˆ๋‹ค. ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ Universal Dynamic Framework ๊ทธ๋ ‡๊ฒŒ ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋Ÿผ Framework ๋ฐฐํฌ๋Š” ์–ด๋–ค์‹์œผ๋กœ ํ•˜๋Š” ๊ฑธ๊นŒ? ๋ชจ๋“  ๊ธฐ๊ธฐ์—์„œ ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•ด์•ผ ํ• ํ…๋ฐ, ๋ชจ๋“  ์‹คํ–‰ํŒŒ์ผ์„ Universal binary๋กœ ๋งŒ๋“ค์–ด ๋ฐฐํฌํ•˜๋Š” ๊ฑธ๊นŒ? ๊ทธ๋ ‡๋‹ค.

$ cd RxSwift.framework
$ file RxSwift
RxSwift: Mach-O universal binary with 4 architectures: [i386:Mach-O dynamically linked shared library i386] [x86_64] [arm_v7] [arm64]
RxSwift (for architecture i386):        Mach-O dynamically linked shared library i386
RxSwift (for architecture x86_64):      Mach-O 64-bit dynamically linked shared library x86_64
RxSwift (for architecture armv7):       Mach-O dynamically linked shared library arm_v7
RxSwift (for architecture arm64):       Mach-O 64-bit dynamically linked shared library arm64

์„œ๋“œํŒŒํ‹ฐ ์ค‘ ์œ ๋ช…ํ•œ RxSwift๋ฅผ ๊ฐ€์ ธ์™€์„œ ํ™•์ธํ•ด๋ณด๋ฉด, Simulator๋ฅผ ์œ„ํ•œ architecture์™€ iOS Device๋ฅผ ์œ„ํ•œ architecture๊ฐ€ ๋ชจ๋‘ ํฌํ•จ๋˜์–ด ์žˆ์Œ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

App Store Connect Upload Error

๊ทธ๋Ÿผ ์ € ์ƒํƒœ๋กœ app store์— ์˜ฌ๋ฆฌ๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ?

โ€œUnsupported Architecture. Your executable contains unsupported architecture โ€˜[x86_64, i386]โ€™.โ€

ใ… ใ…  ์ € ์•„ํ‚คํ…์ณ์— ๋Œ€ํ•œ ๊ฒƒ์„ ์ œ๊ฑฐํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค. ์ด๋Ÿฐ ๊ฒƒ์€ Strip์ด๋ผ ํ•œ๋‹ค. Framework์—์„œ ํ•„์š”์—†๋Š” ์•„ํ‚คํ…์ณ๋ฅผ ์ง€์šฐ๊ณ  ๋‹ค์‹œ ํ•ฉ์น˜๋Š” ๊ณผ์ •์„ ๋งํ•œ๋‹ค.

lipo command

$ man lipo
---
NAME
       lipo - create or operate on universal files

SYNOPSIS
       lipo input_file command [option...]

DESCRIPTION
       The  lipo  tool  creates or operates on ``universal'' (multi-architecture) files. Generally, lipo reads a single input file and writes to a single output file,
       although some commands and options accept multiple input files.  lipo will only ever write to a single output file, and  input  files  are  never  modified  in
       place.
# ํ•„์š”ํ•œ architecture๋“ค๋งŒ ์ถ”์ถœ
$ lipo -extract armv7 RxSwift -o RxSwift_armv7
$ lipo -extract arm64 RxSwift -o RxSwift_arm64
# ๋ถ„๋ฆฌํ•œ binary ํ•ฉ์น˜๊ธฐ
$ lipo -o RxSwift-merged -create RxSwift_armv7 RxSwift_arm64
# ์ž˜ strip๋˜์—ˆ๋Š”์ง€ ํ™•์ธ
$ lipo -info RxSwift-merged
Architectures in the fat file: RxSwift-merged are: armv7 arm64
# ์ •๋ฆฌ
$ rm RxSwift_arm* 
$ mv RxSwift-merged RxSwift

Reference