Tag Archives: XCode

iOS Framework의 duplicate symbol 에러 해결하기

Xcode 프로젝트를 개발하다 보면 다양한 Framework를 사용하게 됩니다. 애플에서 기본적으로 제공하는 Framework부터 외부의 개발사가 제공하는 Dynamic 혹은 Static 형태의 Framework를 접하게 되는데요. 프로젝트의 Build Settings – Other Linker Flags-ObjC 또는 -all_load 설정이 존재하게 되면 이 프레임워크들 사이에 사용하고 있는 라이브러리들이 충돌을 일으키게 됩니다.

이때에 접하게 되는 에러가 다음과 같은 duplicate symbol 오류입니다.

스크린샷 2015-08-23 오후 1.01.16

만약의 위의 충돌이 나고 있는 한쪽이 내 프로젝트라면 해당 Class/Library를 제거하면 간단히 해결될 문제이지만 차용하고 있는 두개의 Framework들 사이에 발생하고 있다면 굉장히 난감한 상황이 됩니다. 이경우 한쪽을 분해하여 해당 라이브러리를 제거한 뒤에 사용하는 방법이 있습니다.

위의 경우에는 Unity 프로젝트에서 기본이 되는 라이브러리 libiPhone-lib.aPPAppPlatformKit.framework간에 ioapi.o 라는 라이브러리가 충돌이 나는 경우이며 PPAppPlatformKit.framework에서 ioapi.o를 제거하는 방향으로 해결해 보도록 하겠습니다.

요즘의 프레임워크는 일명 Universal Framework 혹은 Fat Framework라는 이름으로 다양한 아키텍쳐를 동시에 지원하도록 Archiving 되어 제공됩니다. 우선 위의 충돌이 나고 있는 프레임워크로 접근하여 어떤 아키텍쳐들을 지원하고 있는지 확인해 보겠습니다.

$ cd ~/LibraryConflictExample/XCodeProject/PPAppPlatformKit.framework/
$ lipo -i PPAppPlatformKit
Architectures in the fat file: PPAppPlatformKit are: armv7 arm64

lipo를 사용하여 해당 Framework는 armv7arm64 두가지 아키텍쳐를 지원하고 있다는것을 확인하였습니다. 이제 묶여있는 현재의 Framework를 아키텍쳐별로 분리해보도록 하겠습니다.

$ lipo PPAppPlatformKit -thin armv7 -output PPAppPlatformKit.armv7
$ lipo PPAppPlatformKit -thin arm64 -output PPAppPlatformKit.arm64
$ ls -l
total 29496
drwxr-xr-x@ 5 dennis  staff   170B  8 23 12:26 Headers/
-rw-r--r--  1 dennis  staff   773B  8 23 12:26 Info.plist
drwxr-xr-x@ 3 dennis  staff   102B  7 11 18:32 Modules/
-rw-r--r--  1 dennis  staff   7.2M  8 23 12:26 PPAppPlatformKit
-rw-r--r--  1 dennis  staff   3.7M  8 23 12:26 PPAppPlatformKit.arm64
-rw-r--r--  1 dennis  staff   3.4M  8 23 12:26 PPAppPlatformKit.armv7
drwxr-xr-x@ 6 dennis  staff   204B  8 23 12:26 _CodeSignature/
-rw-r--r--@ 1 dennis  staff    12K  7 11 18:32 embedded.mobileprovision

lipo의 -thin 명령을 사용하여 PPAppPlatformKit.armv7PPAppPlatformKit.arm64 두개로 분리하는데 성공하였습니다. 이번에는 분리해낸 각각의 바이너리들이 현재 충돌나고 있는 ioapi.o를 포함하고 있는지 확인해보도록 하겠습니다.

$ ar -t PPAppPlatformKit.armv7
...
ioapi.o
...

$ ar -t PPAppPlatformKit.arm64
...
ioapi.o
...

ioapi.o가 포함되어있는것을 확인하였습니다. 이제 바이너리에서 해당 오브젝트를 제거해보겠습니다.

$ ar -d -sv PPAppPlatformKit.armv7 ioapi.o
d - ioapi.o

ar -d -sv PPAppPlatformKit.arm64 ioapi.o
d - ioapi.o

아키텍쳐별 바이너리에서 각각 ioapi.o를 제거하였습니다. 이제 다시 하나로 합쳐보도록 하겠습니다.

$ mv PPAppPlatformKit PPAppPlatformKit.original // 기존 바이너리 백업
$ lipo PPAppPlatformKit.armv7 PPAppPlatformKit.arm64 -create -output PPAppPlatformKit

Framework로부터 중복되어 충돌나고 있는 오브젝트를 정상적으로 제거하였습니다. 이제부턴 해당 오류가 발생하지 않을것입니다.

Xcode No matching provisioning profiles found 해결

xcode_provisioning_profile_error

XCode를 사용하다 보면 인증서가 꼬이는 문제를 종종 겪곤 합니다. 그런데 간혹 보면 XCode만으로는 이 문제를 해결할수가 없는 경우가 많아 해결 과정을 정리해 봅니다. 우선 빌드시에 제가 겪은 오류는 다음과 같습니다. 아마 다른 문제도 이와 같은 방법으로 해결이 가능할 것입니다.

No matching provisioning profiles found

Your build settings specify a provisioning profile with the UUID “8a0b43d9-d75b-4d24-9a12-966256f20cb6”, however, no such provisioning profile was found. Xcode can resolve this issue by downloading a new provisioning profile from the Member Center.

빌드시에 위와 같은 문제가 발생하면 가장 먼저 확인해 보셔야 하는것은 다음과 같습니다.

  • Build Settings > Code Signing Identity에 개발자 선택이 제대로 되어있는가?
  • Build Settings > Provisioning Profile에 현재 프로젝트에 적합한 프로비저닝이 선택되어있는가?
  • Info > Bundle Identifier에 프로비저닝에서 설정한 AppId의 Identifier와 동일한가?

아마 이글을 보고 계시는 분들이라면 위와 같은 부분들은 이미 확인하셨고 굳이 프로비저닝이 잘못된것은 아닐까에 대한 의심은 하지 않아도 될꺼 같습니다. 그렇다면 이제 XCode의 바보짓에 대해서 확인해 봅시다. 빌드 에러를 잠시 확인해 보자면 다음과 같은 메시지를 확인할 수 있습니다.

Code Sign error: No matching provisioning profile found: Your build settings specify a provisioning profile with the UUID “8a0b43d9-d75b-4d24-9a12-966256f20cb6”, however, no such provisioning profile was found.

보면 위와같은 UUID를 가진 프로비저닝 프로필을 찾을 수 없다고 하는군요. 정말로 찾을 수 없는지 확인해 보겠습니다. 터미널에 가서 다음의 경로에 들어가서 이미 설치되어있는 프로비저닝 프로필들을 확인합시다.

$ cd ~/Library/MobileDevice/Provisioning\ Profiles/
$ ls
bef0fef2-6f6c-44af-9c14-1e176b082c93.mobileprovision

제가 테스트 한답시고 설치되어있던 프로필을 모두 삭제해서 하나밖에 없는데요, 저 파일명이 프로비저닝 프로필의 UUID에 해당합니다. 대충 봐도 8a로 시작하는 프로비저닝 프로필은 없다는것을 확인할 수 있습니다. XCode상에서 저 프로비저닝 프로필의 이름이 무엇인지 확인하시려면 다음의 명령을 사용하여 확인할 수 있습니다.

$ openssl smime -in bef0fef2-6f6c-44af-9c14-1e176b082c93.mobileprovision -inform der -verify

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>AppIDName</key>
	<string>TheEye ExampleApp</string>
	<key>ApplicationIdentifierPrefix</key>
	<array>
	<string>2BPAH2RJ5A</string>

...

이쯤되면 저 프로비저닝 프로필은 유효하고 내가 이 프로비저닝 프로필로 빌드를 하려했다는것을 알 수 있습니다. 하지만 XCode는 쌩뚱맞게 8a로 시작하는 프로비저닝 프로필이 없다고 오류를 내고 빌드를 종료시키는군요. 지금부터는 XCode의 도움을 받지 않고 문제를 해결해 보겠습니다. 우선 XCode를 종료합시다.

프로젝트의 디렉토리에 방문하여 {ProjectName}.xcodeproj 디렉토리 안의 project.pbxproj 파일을 한번 조사해 보겠습니다.

$ grep 'PROVISIONING_PROFILE' project.pbxproj 
PROVISIONING_PROFILE = "9d26064d-a782-4349-a97a-c53a9803ee06";
PROVISIONING_PROFILE = "9d26064d-a782-4349-a97a-c53a9803ee06";
PROVISIONING_PROFILE = "8a0b43d9-d75b-4d24-9a12-966256f20cb6";
PROVISIONING_PROFILE = "8a0b43d9-d75b-4d24-9a12-966256f20cb6";

PROVISIONING_PROFILE 이라는 키워드로 프로비저닝 프로필 설정이 되어있습니다. 위에서 보니 8a로 시작하는 프로비저닝 프로필이 설정에 떡하니 있군요. 이제 project.pbxproj 파일을 편하신 텍스트 에디터로 열어서 위의 값을 아까 우리가 사용하려뎐 bef로 시작하는 프로비저닝 프로필로 바꿔줍니다. 그리고 다시 XCode에서 열어서 프로젝트를 빌드해보면 잘 되는것을 확인하실 수 있습니다.