사건의 발단
TMapSDK가 M1 맥북에서 시뮬레이터를 돌리려고 하면 x86_64-apple-ios-simulator 를 찾을 수 없다며 에러를 뱉어냅니다.
* 실제 기기로 빌드했을 시에는 정상적으로 동작합니다.
x86_64-apple-ios-simulator
M1에서 ARM기반 맥(애플실리콘)을 지원함에 따라 Xcode12부터 아이폰 시뮬레이터에 ARM용 아키텍쳐 arm64가 추가되었습니다. ARM기반 맥을 지원하기 전인 인텔 CPU(x86 아키텍쳐) 기반일 때는 x86_64를 사용해서 프로젝트를 아이폰 시뮬레이터에 빌드했습니다.
현재 제 맥북은 M1 Pro이기 때문에 arm64 방식인데, Xcode 시뮬레이터는 arm64 또는 x86_64 방식을 실행할 수 있습니다. 맥북에서 돌아가는 시뮬레이터는 인텔 CPU를 사용하기 때문에 인텔의 x86_64에서 작동된다고 합니다.
ARM(Acorn RISC Machine)
아이폰 기기별 사용 아키텍쳐
시뮬레이터의 CPU 아키텍쳐에 대한 정보는 아래의 경로를 타고 들어가면, SDKSettings.json 파일에서 해당 내용을 볼 수 있습니다.
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/SDKSettings.json
Plain Text
복사
아키텍쳐 부분에 arm64와 x86_64가 모두 있는 걸 볼 수 있습니다.
TMapSDK.swiftmodule
에러 메시지를 보면 found: armv7-apple-ios, arm64-apple-ios 라는 부분이 보입니다. x86_64-apple-ios 가 module 내부에 없기 때문에 실행할 수 없다는 걸 알 수 있습니다.
근데 arm64와 x86_64가 모두 가능하다고 SDKSettings.json파일에 적혀있었는데, 찾아서 사용할 수 있는 arm64를 쓰지 않고 x86_64를 찾을 수 없다고 뜨는걸까요?
위에서 말했듯 맥북에서 돌아가는 시뮬레이터는 인텔 CPU를 사용하기 때문에 인텔의 x86_64에서 작동되고 x86_64의 아키텍쳐를 포함하지 않는 framework는 x86_64 기반의 시뮬레이터에서 작동할 수 없는겁니다. 그렇다면 진짜 TMapSDK module이 x86_64를 지원하지 않는지 확인해봅시다.
해당 명령어를 입력해서 해당 framework가 지원하는 아키텍쳐를 알 수 있습니다.
lipo -info TMapSDK.framework/TMapSDK
Plain Text
복사
lipo -info [파일명]
혹은 TMapSDK.framework를 finder에서 찾아서 TMapSDK.framework > Modules > TMapSDK.swiftmodule 내부로 들어가면 됩니다.
x86_64 는 지원하지 않는걸 확인할 수 있습니다.
[첫번째 도전] x86_64를 아키텍쳐에서 제외시키기
Build Settings에 있는 Excluded Architectures 부분에 제외시키고 싶었던 x86_64 아키텍쳐를 추가해줬습니다.
하지만 다른 문제가 발생했습니다. arm64 가 모듈로 포함되지 않은 라이브러리에서 에러가 발생하는 겁니다.
arm64와 x86_64 중 하나의 아키텍쳐는 사용해야 하기에 다른 방법을 찾아봐야겠습니다.
[두번째 도전] Rosetta 사용하기
응용 프로그램에서 Xcode.app를 클릭하고 정보 가져오기를 클릭하면 이런 창을 볼 수 있습니다.
그 중에 Rosetta를 사용하여 열기 부분을 클릭해서 활성화 시켜줍니다. 그리고 Xcode.app를 완전히 종료했다가 켜주세요.
Rosetta 가 뭔가요?
Rosetta는 인텔 프로그램에서 OS X와의 호환성을 연결해주는 백그라운드 프로그램이라고 합니다.
응용 프로그램중에 응용 프로그램(Intel)로 표시되어 있는 프로그램들은 M1같이 Apple 실리콘이 탑재된 맥북에서 작동하기 위해서는 Rosetta가 필요합니다. Xcode는 응용 프로그램(Universal)로 되어 있기 때문에 Apple 실리콘과 인텔을 모두 지원하는 걸 알 수 있고, 범용 앱이기에 Rosetta가 필요하지 않습니다.
굳이 사용하지 않아도 arm과 x86_64 를 모두 지원하는데 굳이 Rosetta를 누르는 이유는 뭘까요?
해당 설정을 누르게 되면 Universal 앱에서 Apple Silicon을 지원하도록 업데이트되지 않은 플러그인, 확장 프로그램 또는 기타 추가 기능을 사용할 수 있기 때문입니다. Universal 앱에서 사용하기 위해 설치한 추가 기능을 Universal 앱이 인식하지 못하는 경우에 해당 추가 기능이 Universal 앱을 인식할 수 있도록 도와줍니다.
SnapKit에서 동일한 문제가 발생했습니다. 혹시나 SnapKit에서 이를 해결할 방법이 있는지 확인해봤습니다.
Cocoapod를 사용해서 해결하는 방법은 있는 거 같은데, SPM으로 해결하는 건 못 찾겠군요..
[세번째 도전] swiftmodule에 해당 아키텍쳐 넣어주기
swiftmodule에 x86_64를 위한 swiftdoc 파일이 없는거라면 추가해주면 해결되지 않을까 하는 생각이 들었습니다. 해결을 위해서 TMap API 공식 문서에 접근해봤습니다.
제목에 어그로가 끌려서 뭔가 해당 파일이 해결해줄 수 있지 않을까 하는 생각이 들어서 다운 받아봤습니다.
해당 파일 내부에 있는 Sample 프로젝트를 열어보니 TMapSDK가 잘 돌아갑니다.
swiftmodule 파일 내부를 보니 x86_64-ios-simulator가 잘 들어 있더라구요.
하지만 2020.09.21에 배포된 SDK이기에 Swift version이 달라서 문제가 일어납니다.
따라서 최신 버전으로 다운을 받았습니다.
그리고 해당 버전 내부의 swiftmodule 파일을 열어봤더니, x86_64 가 없더라구요. 애초에 배포될 때부터 포함이 안되어서 문제를 일으킨겁니다.^_ㅠ
하지만 개발 버전에는 x86_64 가 있길래 해당 파일을 프로젝트에 있는 swiftmodule로 옮겨보았습니다.
그리고 단단히 혼이 났습니다.
[네번째 도전] SnapKit를 수정하기
도저히 방법을 모르겠기에, SnapKit를 Cocoapod으로 옮기기로 결정했습니다. 일단 TMapSDK를 인식하기 위해서 제외할 아키텍쳐에 x86_64를 추가하겠습니다.
그리고 SPM에 추가되어 있던 SnapKit를 삭제하고 Cocoapod에 추가해주겠습니다.
pod update도 진행해주었습니다.
동일한 에러가 발생합니다.
해당 부분을 Podfile에 추가해줍니다.
post_install do |installer|
installer.pods_project.build_configurations.each do |config|
config.build_settings["EXCLUDED_ARCHS[sdk=iphonesimulator*]"] = "arm64"
end
end
Plain Text
복사
그리고 build folder를 클린시켜주고 Podfile.lock를 삭제 시킵니다. 그리고 재 install 시켜줍니다.
config.build_settings["EXCLUDED_ARCHS[sdk=iphonesimulator*]"] = "arm64" 이 부분에서 install될 때 제외되었나봅니다.
이렇게 하면 되지 않을까 싶었습니다.
하고자 하는 것
•
Podfile에 있는 라이브러리는 x86_64 아키텍쳐로 빌드
•
나머지는 arm64아키텍쳐로 빌드
[다섯번째 도전] 개발용 SDK 넣기
SnapKit를 x86_64 로 돌리도록 하는 건 어렵다고 판단했습니다. 따라서 TMapSDK를 arm64 아키텍쳐로 빌드하는 방식을 생각해봤습니다.
[세번째 도전] 부분에 있는 파일에는 개발, 배포 버전의 framework가 따로 존재했는데, 거기에 해답이 있는 거 같았습니다.
전에 같은 팀원이 release와 development의 차이가 존재한다고 했는데, 그게 이건가 싶었습니다.
개발 버전으로 새로운 SDK를 넣어주었습니다.
이거 였다니^^ 이거 였다니^^ 이거라니^^ 그래서 release 버전과 차이가 있다는거였군아..^^ TMapSDK에 한정된 해결 방식이라서 대부분의 경우에는 위의 방식으로 해결이 될 거 같습니다.
마치며
과거의 나때문에 혼쭐이 났습니다. TMapSDK를 사용하시는 분들은 해당 framework module 문제로 혼쭐나지 않길 바라며…
Configuration를 사용해서 DEBUG, RELEASE를 구분해서 framework를 실행시키게 한다면 더 좋지 않을까 싶더라구요. 이 부분을 구현한다면 포스팅을 꼭 해봐야 겠습니다.