본문 바로가기
프로젝트/Wild Bowl : Zooports

Xcode iOS 빌드 이슈 해결

by argentdarae 2025. 1. 6.
반응형

개요

macOS Sonoma 운영체제와 Xcode 15.0.1 업데이트 이후, Xcode에서 유니티 프로젝트를 빌드할 경우 Undefined symbols: 에러가 발생했다

XCode 빌드 시도시 발생한 에러

 

 

 

내용

원인 분석

Undefined Symbols 오류는 프로젝트에서 사용하는 외부 라이브러리나 프레임워크가 제대로 링크되지 않을 때 발생한다고 한다. 특히 Unity에서 iOS 빌드를 위해 생성된 Xcode 프로젝트의 경우, iOS 네이티브 플러그인이나 SDK가 CocoaPods를 통해 링크된다고 한다

 

이러한 문제를 해결하기 위해, 외부 라이브러리를 관리하고 통합하는 역할을 하는 CocoaPods 설정이 누락되거나 링크 오류가 발생하여 라이브러리가 빌드에서 제외되고, 이로 인해 링커가 심볼을 찾지 못할 가능성을 우선적으로 고려했다

 

이에 따라, CocoaPods가 iOS 프로젝트에서 외부 라이브러리를 빌드에 어떻게 링크하는지 알아보았고, 그 과정은 다음과 같았다

 

Unity와 CocoaPods의 통합 과정

Unity에서 iOS 빌드 버튼을 눌렀을 때, 다음 과정을 통해 CocoaPods가 작동한다

 

1. Xcode 프로젝트 생성

Unity에서 iOS 타겟으로 빌드하면 iOS 네이티브 프로젝트(Xcode 프로젝트)가 생성된다
이 과정에서 Unity는 iOS 네이티브 코드와 SDK를 포함하는 설정을 자동으로 추가한다

 

2. Podfile 생성

Unity는 생성된 Xcode 프로젝트 폴더 안에 Podfile을 자동으로 생성한다
이 Podfile에는 Unity가 사용하는 iOS SDK(예: AdMob, Firebase SDK 등)의 의존성이 나열된다

 

Podfile

 

3. pod install 자동 실행

Xcode 프로젝트 생성 이후, Unity는 터미널 명령어를 호출하여 pod install을 자동으로 실행한다.

이를 통해 Podfile에 명시된 라이브러리를 CocoaPods 저장소에서 다운로드하고, 프로젝트에 필요한 Pods 디렉터리.xcworkspace 파일을 생성한다

 

 

4. .xcworkspace 파일의 역할

CocoaPods는 pod install 실행 결과로 Xcode의 .xcworkspace 파일을 생성한다.
이 파일은 Unity 프로젝트와 CocoaPods 의존성을 통합하여 관리하며, iOS 빌드 시 반드시 이 파일을 사용해 프로젝트를 열어야 한다

 

CocoaPods의 역할: iOS SDK와 네이티브 앱을 연결하는 중간 다리

1. iOS SDK 의존성 다운로드 및 관리

CocoaPods는 Podfile에 정의된 iOS SDK와 그 종속성을 분석하고, CocoaPods 저장소에서 필요한 라이브러리를 다운로드한다.

또한, Podfile.lock 파일을 생성하여 Unity 프로젝트에서 필요한 특정 버전의 SDK를 고정한다. 이를 통해 여러 SDK 간의 의존성 충돌을 방지한다

 

여기서 나오는 종속성이라는 단어가 아직 좀 낯설어 찾아보았다

 

종속성이란, 소프트웨어가 외부에서 제공하는 코드나 기능에 의존하는 상태를 의미한다고 한다

 

예를 들어, Google AdMob SDK를 사용하기 위해서는 AdMob에서 제공하는 라이브러리와 그것이 의존하는 다른 라이브러리(예: Google-Mobile-Ads-SDK, GoogleUtilities 등)가 모두 프로젝트에 포함되어야 한다. 이러한 의존 관계를 종속성이라고 하며, CocoaPods는 이를 관리하여 필요한 모든 라이브러리를 자동으로 다운로드하고 프로젝트에 통합하는 역할을 한다

 

 

2. 라이브러리와 프로젝트 빌드 설정 통합

CocoaPods는 iOS 네이티브 프로젝트와 Unity SDK를 연결하기 위해 Xcode 빌드 설정을 자동으로 수정한다. 그 작업 내역은 다음과 같다고 한다

  • Pods 디렉토리 추가: 프로젝트가 SDK의 헤더 파일과 리소스를 올바르게 참조할 수 있도록 Pods 디렉토리를 검색 경로에 포함한다
  • 링커 플래그 설정: Objective-C와 같은 언어의 카테고리 메서드가 올바르게 링크되도록 -ObjC 플래그를 추가한다
  • 프레임워크 등록: 빌드에 필요한 SDK의 .framework 또는 .a 파일을 Xcode 프로젝트에 자동으로 포함한다

 

이해한 바를 비유로 표현

위의 내용을 내가 이해한 바를 글로 정리하면 다음과 같다

  1. Unity 프로젝트는 iOS 네이티브 기능을 사용하기 위해 중간 번역자가 필요하다
  2. CocoaPods가 이 번역자다. 또한 다음과 같은 역할을 한다
필요한 SDK(라이브러리)를 다운로드.
Xcode 프로젝트와의 통합 설정.
Unity SDK가 iOS 네이티브 기능과 올바르게 소통하도록 모든 링킹 작업을 수행.
앱 실행 시, iOS 네이티브 기능을 Unity에서 사용할 수 있도록 보장.

 

결론

Undefined Symbols 오류를 해결하기 위해 살펴보고 검색해야 할 범위를 다음과 같이 좁혔다:

  1. CocoaPods 설정: Podfile과 Podfile.lock을 확인하여 필요한 SDK 의존성이 제대로 포함되었는지 점검
  2. pod install 실행 상태: 터미널에서 pod install을 실행해 문제가 있는 부분을 파악
  3. Xcode 빌드 설정: 링커 플래그, 헤더 경로, 프레임워크 포함 여부를 확인하여 CocoaPods와 Xcode 통합 문제를 점검

이 과정을 통해 오류 원인을 파악하고 해결 방안을 탐색할 수 있을 것으로 보았다

 

 

해결 과정

검색

Undefined Symbol 오류와 CocoaPods 관련 문제를 해결하기 위해 다양한 자료를 검색하며 원인 파악과 해결 방안을 찾는 데 집중했다

 

'No such module' when I use CocoaPods

 

'No such module' when I use CocoaPods

So here's my procedure. I create a new Podfile in the project directory, then I added the following platform :ios, '9.0' use_frameworks! target 'CPod' do pod 'AFNetworking', '~> 2.5' pod '

stackoverflow.com

 

스택 오버플로우 찾은 이 글은 나에게 가이드라인을 제시해주었고 한 유저가 달아놓은 해결 방안대로 진행해보았었다

 

수행

1. Xcode 완전히 닫기

Xcode가 실행 중일 경우 일부 파일이 잠길 수 있으므로 완전히 종료한다

 

2. DerivedData 폴더 제거

DerivedData 폴더는 Xcode에서 생성한 임시 파일과 빌드 캐시를 저장하는 디렉터리로, 오래된 캐시가 빌드 오류를 유발할 수 있다

(경로: ~/Library/Developer/Xcode/DerivedData)

 

3. Podfile.lock 파일 제거

Podfile.lock 파일은 현재 CocoaPods 프로젝트의 의존성 버전을 고정하는 역할 한다. 이 파일이 손상되거나 오래된 경우, 의존성 충돌이나 빌드 오류가 발생할 수 있다

 

4. pod deintegrate 실행

pod deintegrate는 CocoaPods와 관련된 모든 설정과 파일을 프로젝트에서 완전히 제거한다

 

5. .xcworkspace 파일 제거

.xcworkspace 파일은 CocoaPods 설치 시 Xcode 프로젝트와의 통합을 위해 생성된 파일이다. 이 파일이 손상되었거나 불일치할 경우, 빌드 오류가 발생할 수 있기 때문에 삭제한다

 

6. pod install 실행

Podfile에 명시된 의존성을 다시 설치한다

터미널에서 프로젝트 디렉터리로 이동한 후 pod install 명령어를 실행한다

 

7. pod update 실행

Podfile에 명시된 라이브러리를 최신 버전으로 업데이트한다

 

새로운 오류

 

빌드가 순조롭게 진행되는 듯했지만, 새로운 오류가 발견되었다. 다행히 이 오류는 검색을 통해 바로 해결할 수 있었다

Xcode 15 beat6 Assertion failed: … | Apple Developer Forums

 

Xcode 15 beat6 Assertion failed: … | Apple Developer Forums

Xcode 15 beat6 0 0x102aa3698 __assert_rtn + 72 1 0x102a5e284 ___Z13dispatchApplyIRKmZ15dispatchForEachIKN6mach_o13CompactUnwind11Diff24FixupEZNK2ld16LayoutExecutable18writeCompactUnwindENSt3__14spanIhLm18446744073709551615EEEyRKNS7_13SectionLayoutEE4$_26Ev

developer.apple.com

 

 

Unity-iPhone 및 UnityFramework의 기타 링커 플래그에 -ld64 플래그를 삽입하여 문제를 해결했다

 

이 플래그는 최신 LLVM ld64 링커를 사용하도록 강제하여, 이전 링커 방식과의 호환성 문제를 방지한다고 한다. 하지만 지금 당장 필요한 정보는 아니라고 판단해 추가적인 학습은 진행하지 않았다

 

 

반복

문제는 해결되었지만, 빌드 때마다 이 과정을 반복해야 한다는 점이 불편했다. 프로그래머로서 이를 그대로 둘 수 없어, 과정을 자동화하는 bash 스크립트를 작성했다

#!/bin/bash

# 사용자로부터 빌드 폴더 경로 입력 받기
read -p "빌드 폴더의 절대 경로를 입력해주세요: " build_folder

# 입력받은 빌드 폴더로 이동
cd "$build_folder" || exit

# Xcode 종료
echo "Xcode를 종료합니다."
osascript -e 'tell application "Xcode" to quit'

# DerivedData 폴더 제거
echo "DerivedData 폴더를 제거합니다."
rm -rf ~/Library/Developer/Xcode/DerivedData

# Podfile.lock 파일 제거
echo "Podfile.lock 파일을 제거합니다."
rm -f Podfile.lock

# pod deintegrate 실행
echo "pod deintegrate를 실행합니다."
pod deintegrate

# .xcworkspace 파일 제거
echo ".xcworkspace 파일을 제거합니다."
rm -f *.xcworkspace

# pod install 실행
echo "pod install을 실행합니다."
pod install

# pod update 실행
echo "pod update를 실행합니다."
pod update

echo "스크립트 실행 완료."

 

이후, Xcode에서 링커 플래그 하나만 삽입하면 작업이 간소화되어 훨씬 편리해졌다

 

 

마무리

Xcode 빌드 과정에서의 문제 해결 과정을 통해 오류의 원인을 분석하고 해결 방법을 탐색하는 훈련을 할 수 있었다. 또한, 반복적인 작업을 자동화하는 스크립트를 작성함으로써 총 작업시간을 아끼는 경험도 좋았다

 

앞으로도 문제가 발생하면 원인을 좁히고, 검색과 학습을 통해 해결해 나갈 자신감을 얻었다