모듈화를 하고, 하나의 라이브러리를 여러 모듈에서 사용할때 런타임에 이런 오류를 마주칠 수 있다.
failed to demangle superclass of ‘…’ from mangled name ‘…’
결론부터 말하면 문제가 되는 클래스를 포함하는 서드 파티나 프레임워크의 mach-O type이 static framework인 것을 모두 dynamic framework로 고쳐주면 해결된다. Tuist의 경우에는 해당 라이브러리를 .framework로 빌드하면 mach-O type이 dynamic framework로 빌드 된다.
그럼 해당 문제가 왜 일어나는지 고찰해보자.
Static framework, Dynamic framework
오류에 대해서 정확히 이해하기 앞서 static framework, dynamic framework에 대한 이해가 필요하다.
Static Framework
static framework는 앱을 빌드하면 static linker(라이브러리와 앱의 소스코드 파일을 병합(merge)하는 것을 link라 한다.)를 통해 static library 코드가 앱 바이너리 합쳐져 내로 들어가 Heap 메모리에 저장된다. 이 말은 라이브러리의 코드 자체가 복사되어서 들어간다는 뜻이고, static framework를 여러 framework에서 사용할 경우 코드 중복이 생기게 된다.
Dynamic Framework
dynamic framework는 컴파일된 코드가 앱의 바이너리에 포함되지 않는다. Static linker를 통해 합쳐지는 코드는 dynamic framework의 reference이다. 따라서, link는 됐지만, 라이브러리의 코드 자체는 복사가 되지 않는다. 결과적으로, dynamic framework는 동시에 여러 모듈에서 사용해도, 동일한 코드 사본을 공유하고 사용한다.
Mangled name, demangle
‘mangled name’은 함수나 변수의 이름을 컴파일 타임에 고유한 식별자로 변환하는 것을 말한다. 이를 통해 같은 이름의 함수나 변수가 서로 충돌하지 않도록 보장하고, 함수 오버로딩 같은 기능을 지원한다.
‘demangle’은 mangle된 이름을 읽기 쉬운 형태로 변환하는 과정을 의미한다. swift에서 함수나 변수 이름은 컴파일러에 의해 mangle 되어 저장되는데, 이러한 mangled 이름은 일반적으로 사람이 읽기 어렵기 때문에 디버깅에 문제가 될 수 있다. 따라서, ‘demangle’은 mangeld 한 이름을 원래의 의미있는 이름으로 복원하는 것을 말한다.
Discussion
이것이 static framework에서 문제가 되는 이유는 static framework는 컴파일 타임에 라이브러리의 코드가 실행 파일에 포함되는 방식으로 동작하는데, 이때 여러 모듈에서 같은 라이브러리를 사용는 경우에는 라이브러리 코드가 중복해서 포함될 수 있다. 따라서, static framework을 여러 모듈에서 사용하면, 각 모듈이 static framework을 컴파일하는 과정에서 같은 이름의 함수나 변수를 사용하는 경우, 이름 충돌이 발생할 수 있다. 결과적으로 “failed to demangle superclass of ‘…’ from mangled name ‘…’”란 에러를 를 뱉게 된다. 해당 에러는 특정 모듈들이 사용한 서드파티의 클래스, 함수, 변수의 mangled된 이름이 모듈마다 다르게 해석되기 때문에 발생할 수 있는 것.
// MyFramework.swift
public func foo() {
print("Hello from MyFramework!")
}
// ModuleA.swift
import MyFramework
public func example1() {
foo()
}
// ModuleB.swift
import MyFramework
public func example2() {
foo()
}
위의 코드를 보자, MyFramework는 static framework이고, MyFramework 내부에 foo()라는 함수가 있다. A 모듈과 B 모듈에서 모두 foo() 함수를 사용하는 경우, 각 모듈에서 foo() 함수가 호출되는 코드를 컴파일하면, 같은 이름의 함수를 사용하므로 이름 충돌이 발생할 수 있다. 이 때, 컴파일러는 각 모듈에서 사용되는 foo() 함수의 이름을 고유하게 만들기 위해, 각각 다른 mangled 이름을 사용한다. 결과적으로 A 모듈과 B 모듈에서 사용되는 foo() 함수의 이름은 서로 다른 mangled 이름으로 변환된다.
따라서, 모듈 A에서는 foo() 함수가 _T08MyFramework3fooSiyF로 mangled 될 수 있고, 모듈 B에서는 _T08MyFramework3fooSiyFZ로 mangled 될 수 있다. 이렇게 static framework에서는 mangled 된 이름이 충돌하면 런타임 시에 서드 파티의 함수나 클래스를 사용할때 해당되는 이름을 찾을 수 없는 오류가 발생할 수 있다.
Conclusion
결과적으로, 여러 모듈에서 static framework을 사용하는 경우, 이름 충돌을 피하기 위해 각 모듈에서 사용되는 함수나 변수의 이름을 고유하게 만들거나, static framework을 사용하지 않고 dynamic framework을 사용하는 것이 좋다. 하지만 각 모듈에서 사용되는 서드 파티의 함수나 변수의 이름을 고유하게 만드는 것은 현실적으로 어렵기 때문에 dynamic framework로 서드 파티를 관리하는 것이 속편하다. 구구절절 말했지만 결론은 dynamic framework은 코드 사본을 만들지 않고 모든 모듈이 동일한 코드 사본을 공유하고 사용하기 때문에, 충돌이 발생하지 않는다.
Reference
[Swift]Name Mangling
Name Mangling은 단어 그대로 이름을 조각조각냄으로써 고유한 이름을 가짐 여부 문제를 해결합니다. 컴파일러로부터 만들어진 코드는 링커를 통해 다른 부분과 연결되는데, 링커는 각 프로그램 개
minsone.github.io
Name mangling - Wikipedia
From Wikipedia, the free encyclopedia Technique in compiler construction This article is about name mangling in computer languages. For name mangling in file systems, see filename mangling. For other uses, see Name conflict. In compiler construction, name
en.wikipedia.org
GitHub - apple/swift: The Swift Programming Language
The Swift Programming Language. Contribute to apple/swift development by creating an account on GitHub.
github.com
(Static/Dynamic) Library
안녕하세요 :) Zedd입니다. ~ 애플 문서를 보던 중 ~ Overview of Dynamic Libraries Overview of Dynamic Libraries Two important factors that determine the performance of apps are their launch times and their memory footprints. Reducing the size
zeddios.tistory.com
'iOS > 학습' 카테고리의 다른 글
Error) Tuist 3.x -> 4.x 마이그레이션시 생기는 No such module 문제 해결하기 (0) | 2024.05.04 |
---|---|
[iOS] 푸시, 다이나믹 링크 등으로 실행될 때 디버깅하기 (0) | 2023.08.28 |
SwiftUI) iOS13 부터 지원하는 간단한 커스텀 Attribute Text 만들기 (0) | 2023.02.15 |
TCA) Store vs ViewStore (0) | 2023.02.13 |
Storyboard 에서 Generic Type 의존성 주입하기 2 (0) | 2022.08.29 |