"매니페스트는 Swift로 쓰지만, 계약서처럼 읽어. 뭐가 있고, 어느 플랫폼용이고, 뭘로 만드는지."
가족이 Mac 앱을 매니페스트로 빌드하는 이유
이 가족의 Mac 앱은 전부 Swift 패키지야. 데스크톱 쪽엔 .xcodeproj가 하나도 없어. Package.swift는 짧고, diff가 깔끔하고, 코드처럼 리뷰되고, 터미널이든 스크립트든 코딩 에이전트든 똑같이 빌드돼. 명령도 swift build -c release --product Spark 한 줄이야. 대신 번들, 서명, 설치는 네 스크립트 몫이 되는데, 그건 6트랙에서 다뤄. iOS랑 워치 앱에는 XcodeGen을 써. 앱 타깃엔 패키지로 표현할 수 없는 게 필요하거든. 이건 네 번째 레슨에서 볼 거야.
매니페스트의 구성
- 첫 줄이 중요해.
// swift-tools-version: 6.2가 어떤 매니페스트 API를 쓸 수 있는지 정해. 도구가 읽어 들이는 주석이라, 틀리게 적으면 새 설정들이 아예 없는 걸로 취급돼. platforms는 배포 대상이야. 패키지가 돌아간다고 약속하는 가장 오래된 macOS, iOS, watchOS 버전이지.products는 바깥에서 의존할 수 있는 것들이야. 다른 패키지가 import하는 코드는.library, 실행할 도구나 앱 바이너리는.executable.targets가 모듈이야. Swift나 C 코드는.target, 프로그램은.executableTarget, 테스트는.testTarget. 경로를 따로 안 주면 각각Sources/<Name>이나Tests/<Name>에 있어.dependencies로는 다른 패키지를 URL과 버전으로, 아니면 로컬path로 가져와.- 타깃별
swiftSettings/linkerSettings에는 언어 모드 예외, 예정 기능, 링크할 시스템 라이브러리와 프레임워크가 들어가. - 끝에 오는
swiftLanguageModes: [.v6]가 패키지 기본값이야. 6.3 툴체인의swift package init은 이미 이렇게 써줘.
나중에 이득 보는 모듈 나누기
가족 Mac 앱은 크게 두 모듈로 나뉘어. AppKit을 import하지 않는 순수 코어 모듈, 그리고 AppKit과 코어를 조립하는 앱 모듈이야. 가끔은 공유 킷 코드 모듈이 하나 더 붙기도 해. 코어는 Command Line Tools만 깔린 Mac까지 포함해 어느 Mac에서든 빨리 빌드되고 테스트돼. 앱 모듈은 얇아. 나중에 같은 앱에 아이폰 클라이언트가 생기면, 폰이 링크할 게 이미 코어로 준비돼 있어.
발목 잡는 함정 두 가지
path 의존성의 식별자는 디렉터리 이름이야. 가족이 공유 패키지를 swift/라는 폴더에서 CwkKit/으로 옮기기 전에는, package: "CwkKit"을 찾던 사용처는 전부 unknown package 'CwkKit'; valid packages are: 'swift'로 실패했어. 그런데 이름을 바꾸고 나니 이번엔 패키지 자신의 .build 캐시가 옛 절대 경로를 기억하고 있었어. 그래서 달랑 error: fatalError 한 줄만 찍고 실패했지. rm -rf .build로 풀렸어. fatalError는 SwiftPM이 겉에 씌운 말일 뿐, 그 자체로는 아무 정보가 없어. 그러니 그 밑에 찍힌 내용을 읽어.