Package.swift에 타겟 별로 지정할 수 있는 swiftSettings를 알아보자.
define(_:_:)
컴파일 조건을 정의하는 메서드이다.
Swift Package 테스트
MySPM 패키지를 하나 생성하고 swiftSettings에 .define을 지정했다.
// swift-tools-version: 6.0
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "MySPM",
products: [
.library(
name: "MySPM",
targets: ["MySPM"]),
],
targets: [
.target(
name: "MySPM",
swiftSettings: [
.define("ENABLE_SAY_SOMETHING", .when(platforms: [.iOS], configuration: .debug)) // ✅
]
),
.testTarget(
name: "MySPMTests",
dependencies: ["MySPM"]
),
]
)
이렇게 정의해 두면, 코드에서 조건부 분기를 할 수 있다.
public struct MySPMModel {
public init() { }
public func saySomething() {
#if ENABLE_SAY_SOMETHING
// iOS 플랫폼 & debug 모드에서만 컴파일 된다.
print("Hello World!")
#endif
}
}
In Xcode
Xcode 프로젝트의 타겟 빌드세팅에 Other Swift Flags에 -D 옵션을 전달한 것과 기능이 같다.
(Xcode > Build Settings > Swift Compiler - Custom Flags > Other Swift Flags)
etc
SPM에서는 debug와 release 두 개의 빌드 구성만 지원한다.
(추가적인 Build Config를 인식하도록 할 수 있는 정식 지원 X)
unsafeFlags(_:_:)
SPM은 해당 플래그를 이해하지 못하고 그대로 컴파일러에게 전달만 한다.
일부 빌드 플래그는 지원되지 않거나 악의적인 동작 유발 가능성이 있기에
unsafe flag를 사용한 타겟은 다른 타겟에서 의존성으로 가질 수 없다.
Swift Package 테스트
swiftSettings에 .unsafeFlags를 지정했다.
// swift-tools-version: 6.0
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "MySPM",
products: [
.library(
name: "MySPM",
targets: ["MySPM"]),
],
targets: [
.target(
name: "MySPM",
swiftSettings: [
.unsafeFlags(["-warnings-as-errors"]) // ✅
]
),
.testTarget(
name: "MySPMTests",
dependencies: ["MySPM"]
),
]
)
-warnings-as-errors는 Swift 컴파일 시 발생하는 경고(warning)를 모두 오류(error)로 처리하도록 만드는 컴파일러 플래그다.
잘 적용된다.
In Xcode
Xcode에서는 (Xcode > Build Settings > Swift Compiler - Custom Flags > Other Swift Flags)에 전달하는 것과 유사하다
enableExperimentalFeature(_:_:)
실험적 기능을 활성화 시키는 메서드이다.
실험적 기능이란 Swift 언어에서 아직 공식적으로 제공되지 않는 개발 중인 기능을 의미한다.
하나의 타겟에서만 실험적 기능을 활성화할 수 있다. (Dependencies에는 영향 X)
알 수 없는 실험적 기능이 설정되면 타겟에서 이를 무시한다.
특정 Swift 버전에 어떤 exeprimental feature를 사용할 수 있는지 찾고 싶다면 여기에서 확인해볼 수 있다.
Swift Package 테스트
5.10.1-RELEASE에 EXPERIMENTAL_FEATURE로 포함되어 있는 StrictConcurrency를 테스트하였다.
5.10 swift toolchain을 사용하는 Xcode 15.3에서 확인을 위해,
MySPM 패키지에 Package@swift-5.10.swift 파일을 추가했다.
(계속 헷갈리는데 Swift 언어 버전과 컴파일러를 위한 Swift Toolchain 버전은 별도다)
// swift-tools-version: 5.10
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "MySPM",
products: [
.library(
name: "MySPM",
targets: ["MySPM"]),
],
targets: [
.target(
name: "MySPM",
swiftSettings: [
.enableExperimentalFeature("StrictConcurrency") // ✅
]
),
.testTarget(
name: "MySPMTests",
dependencies: ["MySPM"]
),
]
)
워닝 확인을 위해 간단하게 Concurrency를 위반하는 파일을 추가했다.
import Foundation
public struct Value {
public static var zero: Int = 0
}
Xcode 15에서 빌드를 돌리면 아래 워닝이 잘 노출된다.
In Xcode
StrictConcurrency는
Xcode > Build Settings > Swift Compiler - Language > Strict Concurrency Checking에서
바로 설정해줄 수 있지만
아래처럼
Xcode > Build Settings > Swift Compiler - Custom Flags > Other Swift Flags에
-enable-experimental-feature XXX 로 전달할 수 있다.
etc
현재 상태에서 Xcode 16으로 빌드하면 컴파일 에러가 발생한다.
[Package.swift]
swift-tools-version이 6.0이므로 기본적으로 Swift6로 컴파일된다.
// swift-tools-version: 6.0
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "MySPM",
products: [
.library(
name: "MySPM",
targets: ["MySPM"]),
],
targets: [
.target(
name: "MySPM",
swiftSettings: [
.unsafeFlags(["-warnings-as-errors"])
]
),
.testTarget(
name: "MySPMTests",
dependencies: ["MySPM"]
),
]
)
[아까 추가한 코드]
Package.swift에 swiftLanguageMode를 v5로 설정하여 컴파일 에러를 지웠다.
// swift-tools-version: 6.0
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "MySPM",
products: [
.library(
name: "MySPM",
targets: ["MySPM"]),
],
targets: [
.target(
name: "MySPM"
),
.testTarget(
name: "MySPMTests",
dependencies: ["MySPM"]
),
],
swiftLanguageModes: [.v5] // ✅
)
enableUpcomingFeature(_:,_:)
다가오는 기능(Upcoming Feature)를 활성화하는 메서드이다.
다가오는 기능이란 특정 Swift 언어 버전에서 사용 가능하지만,
소스 코드 호환성에 영향을 미칠 가능성이 있어
이전 버전들에서 기본적으로 활성화되지 않는 기능을 의미한다.
하나의 타겟에서만 다가오는 기능을 활성화할 수 있다. (Dependencies에는 영향 X)
알 수 없는 다가오는 기능이 설정되면 타겟에서 이를 무시한다.
Swift Package 테스트
위에서 실험적 기능으로 살펴봤던 StrictConcurrency는
swift-6.0.3-RELEASE에서 UPCOMING_FEATURE로 변경됐다.
이를 테스트 하기 위하여
enableUpcomgFeature로 StrictConcurrency를 활성화하였다.
(Package@swift5.10.swift 파일이 아님에 유의)
// swift-tools-version: 6.0
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "MySPM",
products: [
.library(
name: "MySPM",
targets: ["MySPM"]),
],
targets: [
.target(
name: "MySPM",
swiftSettings: [
.enableUpcomingFeature("StrictConcurrency") // ✅
]
),
.testTarget(
name: "MySPMTests",
dependencies: ["MySPM"]
),
],
swiftLanguageModes: [.v5]
)
Xcode 16에서 빌드를 돌리면 아래 워닝이 잘 노출된다.
In Xcode
Xcode > Build Settings > Swift Compiler - Custom Flags > Other Swift Flags에
-enable-upcoming-feature XXX 전달할 수 있다.
마찬가지로 StrictConcurrency는
Xcode > Build Settings > Swift Compiler - Language > Strict Concurrency Checking에서
바로 설정 가능
etc
StrictConcurrency는 Swift 5.10에서 EXPERIMENTAL_FEATURE
Swift 6.0.3에서 UPCOMING_FEATURE로 되어 있다.
아래와 같이 생각했었는데,
- Swift 5.10 toolchain을 사용하는 Xcode 15.3에서 StrictConcurrency를 UPCOMING_FEATURE로 전달 -> 무시
- Swift 6.0.3 toolchain을 사용하는 Xcode16.2에서 EXPERIMENTAL_FEATURE로 전달 -> 무시
1번은 예상대로 워닝이 적용되지 않고 해당 플래그가 무시됐으나,
2번 상황에서는 experimental feature가 동작했다. (???)
Features.def를 다시 살펴보니, EXPERIMENTAL_FEATURE에서 AvailableInProd라는 인자 값을 받고 있었다.
이 값이 한번 true로 세팅되면 영구적으로 유지되는 것으로 추정
#ifndef EXPERIMENTAL_FEATURE
// Warning: setting `AvailableInProd` to `true` on a feature means that the flag
// cannot be dropped in the future.
# define EXPERIMENTAL_FEATURE(FeatureName, AvailableInProd) \
LANGUAGE_FEATURE(FeatureName, 0, #FeatureName, \
langOpts.hasFeature(#FeatureName))
#endif
...
// Enable strict concurrency.
EXPERIMENTAL_FEATURE(StrictConcurrency, true)
swiftLanguageMode(_:_:)
타겟 별로 컴파일할 Swift 언어 버전을 정해줄 수 있다.
Swift Package 테스트
타겟에 지정해줄 수 있고, Package에 지정해줄 수도 있다.
(타겟에 직접 적용하는 것이 우선순위 높음)
// swift-tools-version: 6.0
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "MySPM",
products: [
.library(
name: "MySPM",
targets: ["MySPM"]),
],
targets: [
.target(
name: "MySPM",
swiftSettings: [
.swiftLanguageMode(.v5) // ✅ v5로 컴파일
]
),
.testTarget(
name: "MySPMTests",
dependencies: ["MySPM"]
),
],
swiftLanguageModes: [.v6] // ✅ MySPMTest는 v6로 컴파일
)
interoperabilityMode(_:_:)
주어진 언어(현재 C, C++ 가능)와 Swift 상호 운용성을 활성화한다.
이는 Swift와 C++간의 상호 운용성을 특정 타겟에서 활성화할 때 유용하다.
C++ 상호 운용성을 모드를 활성화하면 기존 C 및 Objective-C API가 가져와지는 방식이 변경될 수 있다.