07 February 2024

Swift 5.9에서 Swift Package에 새로운 접근 제어자 Package가 추가됐습니다. SE-0386

Package 접근 제어자는 특정 도메인이나 역할을 가진 모듈만 접근할 수 있게 해, 유용할 것입니다.

그러나 Swift Package가 아닌 Xcode Project로 구축된 프로젝트라면, 구축된 프로젝트는 새 접근 제어자 Package를 사용할 수 없어 아쉽습니다.

Xcode Project로 구축된 프로젝트에서도 Package 접근 제어자를 사용할 수 있다면 어떨까요?

SE-0386

SE-0386 제안서는 패키지 경계를 정의해 빌드 시스템이 -package-name 플래그로 패키지명을 받도록 합니다.

즉, Swift Package는 이 옵션을 빌드 시스템에 전달해 Package 접근 제어자 사용을 가능하게 합니다.

간단한 Swift Package를 만들어 Package.swift에 packageAccess 옵션을 추가하고, 빌드해 -package-name 플래그를 전달하는지 확인해봅시다.

// Package.swift
import PackageDescription

let package = Package(
    name: "MyLibrary",
    products: [
        .library(
            name: "MyLibrary",
            targets: ["MyLibrary"]),
    ],
    targets: [
        .target(
            name: "MyLibrary",
            packageAccess: true),
    ]
)
$ swift build --verbose
Planning build
Building for debugging...
Write auxiliary file /MyLibrary/.build/arm64-apple-macosx/debug/swift-version-4987FB7F52197B0.txt
/Applications/Xcode-15.3.0-Beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc -module-name MyLibrary -emit-dependencies -emit-module -emit-module-path /MyLibrary/.build/arm64-apple-macosx/debug/MyLibrary.swiftmodule -output-file-map /MyLibrary/.build/arm64-apple-macosx/debug/MyLibrary.build/output-file-map.json -parse-as-library -incremental -c @/MyLibrary/.build/arm64-apple-macosx/debug/MyLibrary.build/sources -I /MyLibrary/.build/arm64-apple-macosx/debug -target arm64-apple-macosx10.13 -swift-version 5 -v -enable-batch-mode -index-store-path /MyLibrary/.build/arm64-apple-macosx/debug/index/store -Onone -enable-testing -j8 -DSWIFT_PACKAGE -DDEBUG -module-cache-path /MyLibrary/.build/arm64-apple-macosx/debug/ModuleCache -parseable-output -parse-as-library -emit-objc-header -emit-objc-header-path /MyLibrary/.build/arm64-apple-macosx/debug/MyLibrary.build/MyLibrary-Swift.h -color-diagnostics -sdk /Applications/Xcode-15.3.0-Beta.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.4.sdk -F /Applications/Xcode-15.3.0-Beta.app/Contents/Developer/Platforms/MacOSX.platform/Developer/Library/Frameworks -I /Applications/Xcode-15.3.0-Beta.app/Contents/Developer/Platforms/MacOSX.platform/Developer/usr/lib -L /Applications/Xcode-15.3.0-Beta.app/Contents/Developer/Platforms/MacOSX.platform/Developer/usr/lib -g -Xcc -isysroot -Xcc /Applications/Xcode-15.3.0-Beta.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.4.sdk -Xcc -F -Xcc /Applications/Xcode-15.3.0-Beta.app/Contents/Developer/Platforms/MacOSX.platform/Developer/Library/Frameworks -Xcc -fPIC -Xcc -g -package-name mylibrary
Apple Swift version 5.10 (swiftlang-5.10.0.10.5 clang-1500.3.7.4)
Target: arm64-apple-macosx10.13
Build complete! (0.20s)

로그를 확인해보니, -package-name mylibrary 옵션을 전달한 것을 알 수 있었습니다.

그렇다면, Xcode Project에서 -package-name 옵션을 추가하면 Package 접근 제어자를 사용할 수 있을까요?

Xcode Project

다음 의존관계를 가진 프로젝트를 구축합니다.

graph LR; Application-->FeatureA-->FeatureB;



FeatureA의 Package Name을 Alpha로, FeatureB의 Package Name을 Beta로 설정할 것입니다.

각 모듈의 Package Name을 설정하려면 Build Settings의 OTHER_SWIFT_FLAGS-package-name 옵션을 추가합니다.


// Module: FeatureA
OTHER_SWIFT_FLAGS = $(inherited) -package-name Alpha

// Module: FeatureB
OTHER_SWIFT_FLAGS = $(inherited) -package-name Beta

FeatureA에는 SampleAlpha 클래스, FeatureB에는 SampleBeta 클래스가 있으며, 두 클래스 모두에 package 접근 제어자를 적용합니다.

// Module: FeatureA
// FileName: SampleAlpha.swift

import Foundation

package class SampleAlpha {
    package init() {
        print("init \(Self.self)")
    }

    package func sampleFunc() {
        print("call \(#function)")
    }
}


// Module: FeatureB
// FileName: SampleBeta.swift

import Foundation

package class SampleBeta {
    package init() {
        print("init \(Self.self)")
    }

    package func sampleFunc() {
        print("call \(#function)")
    }
}

Application이 Package Name을 아직 설정하지 않았으므로, SampleAlphaSampleBeta 클래스에 접근할 수 없습니다.


Application의 Package Name을 Beta로 설정하기 위해 Build Settings의 OTHER_SWIFT_FLAGS-package-name Beta 옵션을 추가합니다.

// Application
OTHER_SWIFT_FLAGS = $(inherited) -package-name Beta


이렇게 하면 Application에서 FeatureB의 SampleBeta 클래스에는 접근할 수 있으나, FeatureA의 SampleAlpha 클래스에는 접근할 수 없습니다.


Application의 Package Name을 Alpha로 설정하면, SampleAlpha 클래스에는 접근할 수 있으나, SampleBeta 클래스에는 접근할 수 없습니다.


Xcode Project의 OTHER_SWIFT_FLAGS-package-name 옵션을 추가해 Swift Package에서 Package 접근 제어자 사용을 가능하게 했습니다.

Xcode 15

Xcode 15에서 Build Settings에 Package Access Identifier - SWIFT_PACKAGE_NAME 옵션이 추가되었습니다. 앞에서 이야기 했던 -package-name 대신 이 옵션을 사용하면 Xcode Project에서 Package Name을 설정할 수 있습니다.



위 코드의 샘플은 여기에서 확인하실 수 있습니다.

정리

  • Package 접근 제어자를 이용하면 동일한 도메인이나 역할을 가진 모듈만 접근 가능합니다.
  • OTHER_SWIFT_FLAGS-package-name 옵션을 추가해 Package Name을 설정할 수 있습니다.
  • SWIFT_PACKAGE_NAME에 Package Name을 쉽게 설정할 수 있습니다.

참고자료