반응형

Xcode 27 / Swift 6.3 SPM 동적 라이브러리(Dynamic Framework) 링킹 충돌 원인과 해결 방법

Xcode 27 및 Swift 6.3 환경에서 Swift Package Manager(SPM)를 통해 외부 라이브러리를 추가하거나 멀티 모듈 프로젝트를 구성할 때 duplicate symbol, objc-class-ref, 또는 앱 실행 시 dyld: Library not loaded 링킹 에러가 발생하는 사례가 증가하고 있습니다. 이는 메인 앱 타깃과 확장 타깃(Widget, Notification Service Extension 등)이 동적 라이브러리를 중복 링킹하면서 발생하는 구조적 문제입니다.


 

Static vs Dynamic 링킹 방식 및 Xcode 27 변경점

SPM 패키지의 Package.swift에서 라이브러리 타입을 명시하지 않으면 기본적으로 Static 형태로 빌드됩니다. 그러나 해당 라이브러리를 메인 앱과 앱 익스텐션 타깃 모두에서 참조할 경우 Xcode 27 빌드 시스템에서 링킹 충돌이 발생합니다.

구분 Static Library (.static) Dynamic Framework (.dynamic)

바인딩 시점 컴파일/빌드 타임에 바이너리에 포함 앱 실행 시(Runtime) 동적 로딩
다중 타깃 참조 시 각 타깃 바이너리마다 코드 중복 복사 발생 메인 앱 바이너리에 1회 임베드 후 공유
대표 발생 에러 Duplicate symbol _OBJC_CLASS_$_... dyld: Library not loaded / Image Not Found
Xcode 27 권장 단일 타깃 전용 라이브러리 메인 앱 + Extension 공통 참조 라이브러리

 

1. 문제 상황: 다중 타깃 링킹 충돌 에러 패턴

메인 앱 타깃과 위젯 익스텐션 타깃이 동일한 SPM 라이브러리를 각각 링킹하도록 설정되어 있으면 아래와 같은 빌드 및 런타임 오류가 나타납니다.

// 컴파일 타임 에러 예시 (Static 중복 링킹)
error: duplicate symbol '_OBJC_CLASS_$_SharedUtility' in:
    /Users/.../Build/Products/Debug-iphonesimulator/MainApp.o
    /Users/.../Build/Products/Debug-iphonesimulator/WidgetExtension.o

// 런타임 에러 예시 (Dynamic Embed 설정 오류)
dyld[1234]: Library not loaded: @rpath/SharedFramework.framework/SharedFramework
  Referenced from: <UUID> /var/containers/Bundle/Application/.../WidgetExtension
  Reason: tried: '/usr/lib/swift/SharedFramework.framework' (no such file)

 

2. 해결 방안: SPM 및 Xcode 타깃 링킹 재구성

방안 1: Package.swift 라이브러리 타입 명시적 선언

자체 제작한 모듈이거나 사내 SPM 패키지인 경우 Package.swift 내의 products 정의에서 라이브러리 타입을 .dynamic으로 명시합니다.

// Package.swift
import PackageDescription

let package = Package(
    name: "SharedCore",
    platforms: [.iOS(.v17)],
    products: [
        // type: .dynamic 옵션을 통해 런타임 동적 라이브러리로 빌드 지정
        .library(
            name: "SharedCore",
            type: .dynamic,
            targets: ["SharedCore"]
        ),
    ],
    targets: [
        .target(
            name: "SharedCore",
            dependencies: []
        ),
    ]
)

 

방안 2: Xcode Build Target의 Embed 설정 최적화

서드파티 오픈소스 SPM 라이브러리(Package.swift 수정이 불가능한 경우)는 Xcode 프로젝트의 Frameworks, Libraries, and Embedded Content 설정을 분리해야 합니다.

  1. 메인 앱 타깃 (Main App Target):
    • SPM 라이브러리를 추가하고 Embed & Sign으로 설정합니다.
  2. 익스텐션 타깃 (Widget / Extension Target):
    • 동일한 SPM 라이브러리를 추가하되 Do Not Embed로 지정합니다.
    • 이렇게 설정하면 메인 앱 번들에 동적 프레임워크가 1회 포함되고, 익스텐션은 런타임 시 메인 앱의 @executable_path/Frameworks 또는 @loader_path/Frameworks 경로를 통해 해당 라이브러리를 참조합니다.

 

3. Build Settings 추가 체크리스트

  1. Runpath Search Paths (LD_RUNPATH_SEARCH_PATHS) 확인:
    • 익스텐션 타깃의 Build Settings에서 Runpath Search Paths에 다음 경로가 포함되어 있는지 확인합니다.
    • @executable_path/Frameworks
    • @executable_path/../../Frameworks (App Extension의 메인 프레임워크 탐색 경로)
  2. Other Linker Flags (OTHER_LDFLAGS) 정리:
    • 타깃 빌드 옵션에서 불필요하게 명시된 -all_load 또는 -force_load 플래그가 SPM 라이브러리와 중복 링킹을 유발하지 않는지 점검합니다.

 

핵심 요약

  1. Xcode 27 / Swift 6.3 환경에서 메인 앱과 App Extension이 동일한 SPM 라이브러리를 참조할 때 Static/Dynamic 링킹 설정 미숙으로 충돌이 발생합니다.
  2. 메인 앱과 익스텐션에서 동시 참조하는 라이브러리는 Dynamic 형태로 구성해야 합니다.
  3. 메인 앱 타깃에는 Embed & Sign을 지정하고, 익스텐션 타깃에는 Do Not Embed로 설정하여 런타임 참조 공유 방식을 적용합니다.

#Xcode27 #Swift6_3 #SPM #SwiftPackageManager #DynamicFramework #LinkerError #iOS개발 #Xcode트러블슈팅

반응형
Posted by 까칠코더
,