2019년 봄, Swift 5와 함께 iOS 12.2가 배포되자 이상한 일이 벌어졌습니다. 아무것도 안 했는데 앱 용량이 수 MB씩 줄어든 거예요. Swift ABI Stability and More
이전 글 Swift 심화 #8에서 이어지는 내용입니다.
비밀은 릴리스 노트의 건조한 한 줄에 있었습니다. ABI 안정성(ABI stability) 달성.
Swift 시리즈의 마지막 편은 이 사건의 전말입니다. ABI가 뭐고, 왜 5년이나 걸렸고, 무엇을 가능하게 했는지.
언어의 역사와 심층 구조가 만나는 지점이라 시리즈의 마무리로 어울리는 주제입니다.
ABI란 — 바이너리끼리의 약속
API는 다들 압니다. 소스 코드 수준의 약속이죠. 함수 이름이 뭐고 인자가 뭔지.
ABI(Application Binary Interface)는 그 아래층, 컴파일된 바이너리끼리의 약속입니다.
함수를 호출할 때 인자를 어느 레지스터에 싣는지, struct가 메모리에 어떻게 놓이는지(레이아웃 편에서 본 그 치수들) 같은 것들이요. 심벌 이름을 어떻게 짓는지(맹글링), 메타데이터를 어디서 찾는지도 포함됩니다.
이 약속이 왜 중요할까요. 서로 다른 시점에, 서로 다른 컴파일러로 빌드된 두 바이너리가 함께 동작해야 하기 때문입니다.
앱과 OS에 내장된 라이브러리의 관계가 정확히 그렇죠. ABI가 버전마다 흔들리면, Swift 5.0으로 빌드한 앱이 Swift 5.5 런타임과는 대화할 수 없습니다. Swift ABI Stability and More
실제로 Swift 초기가 그랬어요. 매 버전 ABI가 바뀌어서 모든 앱은 자기가 쓴 버전의 Swift 런타임과 표준 라이브러리를 통째로 품고 다녀야 했습니다.
앱마다 몇 MB씩의 중복 짐이었고, OS는 Swift를 자기 프레임워크에 쓸 수 없었습니다. 시스템 프레임워크는 미래의 앱과도 대화해야 하는데 그 보장이 없었으니까요.
Swift 5의 ABI 안정성 선언은 이 약속을 동결한 사건입니다. 호출 규약, 타입 레이아웃, 맹글링이 확정됐고, 이후 버전은 이 약속을 지키며 진화합니다. Swift ABI Stability and More
그 즉시 표준 라이브러리가 OS로 이사했습니다(앱에서 빠지니 용량 감소). 애플이 SwiftUI 같은 시스템 프레임워크를 Swift로 만들 수 있는 길도 열렸고요.
2019년의 그 용량 감소는 언어가 성인이 됐다는 신호였던 거예요. Swift ABI Stability and More
왜 5년이나 — 동결의 무게
“그냥 일찍 동결하지”라는 의문에는 동결의 비용을 봐야 합니다. ABI를 확정한다는 건 그 시점의 설계 실수까지 영원히 짊어진다는 뜻이거든요.
한번 약속한 레이아웃과 규약은 기존 바이너리가 세상에 존재하는 한 못 바꿔요.
Swift 1~4 시절이 얼마나 격동이었는지 떠올려보세요. 문법이 버전마다 갈아엎어졌죠. 그 시기에 동결했다면 지금의 Swift는 초기 설계의 감옥에 갇혔을 겁니다. Swift ABI Stability and More
제네릭 구현이 안정화되고 값 타입 레이아웃 전략이 검증될 때까지 기다렸습니다. Evolution 절차(철학 4편)로 큰 설계 논쟁들이 정리되기까지 걸린 5년이에요.
C++가 수십 년 된 ABI 관성 때문에 개선안을 반려하는 사례들을 보면, 이 신중함의 값어치가 보입니다.
두 번째 약속 — 모듈 안정성과 라이브러리 진화
그런데 ABI 안정성만으로는 부족한 그림이 하나 남습니다. 바이너리 프레임워크 배포입니다.
Swift 5.0 이전의 컴파일러는 모듈 인터페이스를 swiftmodule이라는 바이너리 포맷으로 주고받았는데, 이게 컴파일러 버전에 묶여 있었습니다. Swift ABI Stability and More
Xcode가 하나 올라가면 배포된 SDK가 전부 무용지물이 되는 구조였죠.
Swift 5.1의 모듈 안정성(module stability)이 이 문제를 풉니다. 텍스트 기반의 안정적 인터페이스 파일(.swiftinterface)이 도입되어, 다른 버전의 컴파일러로 빌드한 프레임워크를 읽을 수 있게 됐어요. Swift ABI Stability and More
XCFramework로 SDK를 배포하는 생태계(결제·분석·지도 SDK들)가 이 위에 서 있습니다.
여기에 짝으로 붙는 개념이 라이브러리 진화(library evolution) 모드입니다. 프레임워크가 “나중에 저장 프로퍼티를 추가해도 기존 앱이 안 깨지게” 빌드하는 옵션인데, 대가가 흥미롭습니다.
이 모드의 public struct는 레이아웃이 확정되지 않은 타입(resilient type)이 됩니다. 클라이언트가 크기를 컴파일 타임에 알 수 없고 간접 접근 비용을 내는 거죠.
레이아웃 편에서 본 “크기를 알면 빠르다”의 정확한 역명제예요.
그래서 진화 모드에는 @frozen이라는 탈출구가 있습니다. “이 타입 레이아웃은 동결한다, 대신 직접 접근을 허용한다”는 선언이죠. 표준 라이브러리의 Int나 Optional이 @frozen인 이유입니다.
앱 개발자에게 실질 의미를 정리하면 이렇습니다. 앱 타깃과 소스 배포 패키지(SwiftPM 대부분)는 이 모드가 필요 없고 켜면 손해입니다.
바이너리로 SDK를 배포하는 쪽만 켜는 옵션이에요. “BUILD_LIBRARY_FOR_DISTRIBUTION이 뭐죠?“라는 질문의 답이 이 문단입니다.
마무리 — 시리즈를 관통한 하나의 이야기
ABI 이야기가 Swift 시리즈의 마지막인 데는 이유가 있습니다. 여기까지 온 개념들이 전부 이 지점에서 합류하거든요.
값 타입의 레이아웃(값 편, 레이아웃 편)이 동결됐기에 struct가 바이너리 경계를 넘습니다. witness table(디스패치 편)의 형식이 확정됐기에 프로토콜이 프레임워크 API가 됐고요.
그리고 Evolution 절차(철학 4편)가 성숙시킨 설계이기에 동결할 자신이 있었습니다.
안전을 타입으로(옵셔널·ARC·Sendable), 비용을 명시로(unsafe·any·@unchecked). 그리고 복잡성을 계단으로(Progressive Disclosure).
이 원칙들이 문법 층에서 바이너리 층까지 일관되게 관통한다는 것, 그게 시리즈 전체가 하고 싶었던 이야기입니다.
Swift는 지금도 Evolution 게시판에서 다음 계단을 만들고 있습니다. 이 시리즈가 그 변화들을 스스로 읽어낼 지도가 되었기를 바라며, 여기서 마칩니다.
정리
- ABI는 바이너리끼리의 약속(호출 규약·레이아웃·맹글링)이고, Swift 5(2019)에서 동결됐습니다. 그 덕에 표준 라이브러리가 OS로 이사해 앱 용량이 줄고, 애플이 SwiftUI를 Swift로 만들 수 있게 됐습니다.
- 동결이 5년 걸린 건 실수까지 영원히 짊어지는 결정이었기 때문입니다. 제네릭·레이아웃·Evolution 절차의 성숙을 기다린 시간이었습니다.
- Swift 5.1의 모듈 안정성(.swiftinterface)이 바이너리 프레임워크 생태계(XCFramework)를 열었습니다.
- 라이브러리 진화 모드는 “프레임워크가 진화해도 앱이 안 깨지는” 대신 간접 접근 비용을 내는 거래이고, @frozen이 그 탈출구입니다. 앱 타깃에는 불필요한 옵션입니다.
- 시리즈의 결론: 안전의 타입화, 비용의 명시화, 복잡성의 계단화라는 Swift의 원칙은 문법에서 바이너리까지 일관됩니다. Swift ABI Stability and More
출처 및 확인 기준
- Swift ABI Stability and More — Swift.org · 공식 발표 · 확인 2026-08-17 · 근거: Swift 5 ABI 안정성, OS 런타임 탑재와 앱 용량 변화

![[Swift 심화 #9] Swift ABI 안정성, 2019년에 앱 용량이 줄어든 이유 대표 이미지](/assets/images/posts/150f67d8-49bc-4461-8f04-26b5e8fc56e3/swift-abi-stability-app-size.jpg)