이 글은 tuist 3.7.0 버전 기준으로 작성되었습니다. (제목 참 길다)
Tuist에서 일반적으로 외부 라이브러리를 추가하는 방법은 아래와 같다.
- Tuist의 Swift Package Manager
- Tuist의 Carthage
- Xcode에서 사용되는 Swift Package Manager
- XCFramework
CocoaPods
평소에 Tuist의 디펜던시 관리를 1번으로 하게 되는데 Objective-C로 만들어진 라이브러리들을 추가할 때 마다 빌드 오류 또는 런타임 오류가 발생한다… (필자는 FLEX 라이브러리와 SDWebImage를 추가했었음)
FLEX의 경우 빌드 시 아래의 에러가 나타난다.
Undefined symbol: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::~basic_string()
Undefined symbol: ___gxx_personality_v0
SDWebImage의 경우 런타임에서 아래의 에러가 나타난다.
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIImageView sd_setImageWithURL:completed:]: unrecognized selector sent to instance 0x138718130'
*** First throw call stack:
(
0 CoreFoundation 0x000000018040e7c8 __exceptionPreprocess + 172
1 libobjc.A.dylib 0x0000000180051144 objc_exception_throw + 56
2 CoreFoundation 0x000000018041d47c +[NSObject(NSObject) instanceMethodSignatureForSelector:] + 0
3 UIKitCore 0x00000001118ffd74 -[UIResponder doesNotRecognizeSelector:] + 232
4 CoreFoundation 0x00000001804126c8 ___forwarding___ + 1308
5 CoreFoundation 0x0000000180414b4c _CF_forwarding_prep_0 + 92
...
몇 번 삽질을 하다보니.. 해결 방법을 몇 개 알게되었는데 기록차 남긴다.
해결 1: Tuist SPM + Header Search Path 직접 추가
https://github.com/tuist/tuist/issues/3762
https://github.com/tuist/tuist/issues/4180
Tuist 이슈에 적혀있는 해결 방법인데 라이브러리에 직접 Header Search Path를 추가하는 방법이다.
Objective-C로 된 라이브러리 마다 이렇게 하기엔 좀 무리가… 🫠
해결 2: Tuist SPM + Dynamic Framework 로 사용
Tuist의 SPM은 기본적으로 라이브러리들의 Mach-O Type을 Static Framework로 설정한다. 에러가 발생하는 라이브러리들을 Dynamic Framework로 설정하면 오류가 발생하지 않는다.
import ProjectDescription
let swiftPackageManager = SwiftPackageManagerDependencies(
[
.remote(url: "https://github.com/FLEXTool/FLEX", requirement: .upToNextMajor(from: "5.0.0")),
.remote(
url: "https://github.com/SDWebImage/SDWebImage",
requirement: .upToNextMajor(from: "5.0.0")
)
],
productTypes: ["FLEX": .framework, "SDWebImage": .framework]
)
let dependencies = Dependencies(carthage: [],
swiftPackageManager: swiftPackageManager,
platforms: [.iOS])
위와 같이 productTypes를 추가하고 tuist clean > tuist fetch > tuist generate > Xcode Clean Build 후 다시 빌드하면 작동한다.
P.S. 참고로 CocoaLumberjack은 위 방법이 동작하지 않는다. 3번으로 해결하자.
P.S.2 Static framework와 Dynamic framework는 각각의 장단점을 갖고 있으니 상황에 따라 1번이나 3번으로 해결하자
해결 3: Xcode에서 사용하는 SPM을 사용한다.
https://docs.tuist.io/guides/third-party-dependencies/
Tuist에서 Xcode에서 사용하는 SPM를 사용할 수 있다. 기존 TargetDependency.external 로 정의된 것을 TargetDependency.package 로 대신 사용하면 된다.
대신, Tuist의 캐싱 및 패키지 확인과 같은 중요한 기능에 대한 지원을 잃는다고 한다.
본인에게 맞는 해결 방법을 선택하도록 하자… 🤔