Swift Digest
SE-0455 | Swift Evolution

SwiftPM @testable build setting

Proposal
SE-0455
Authors
Jake Petroules
Review Manager
Tony Allevato
Status
Accepted

01 何が問題だったのか

Swift Package Manager(SwiftPM)は、debug ビルドの際にすべてのターゲットへ一律に -enable-testing フラグを渡しており、@testable import を有効化するためのコード生成が常に行われる実装になっていました。この挙動はパッケージ作者側からコントロールする手段がなく、@testable import を一切使わないターゲットでも無条件に有効化されてしまいます。

@testable import を有効にすると、internal な宣言まで外部に露出する形でシンボルが出力されるため、次のようなコストが生じます。

  • バイナリから export されるシンボルが増える。Windows の shared library では一つの DLL あたり 65,000 シンボルという上限があり、大きなライブラリではこの制限に抵触しやすくなります。
  • 余計なシンボルはリンク時間を押し上げ、debug ビルドのビルド時間悪化にもつながります。

Xcode のビルドシステムではターゲットごとに testability を切り替えられるのに対し、SwiftPM にはそれに相当する設定がなく、この機能差が問題視されていました。

02 どのように解決されるのか

SwiftSetting にターゲットごとの testability を制御するための API enableTestableImport(_:_:) を追加します。Package manifest のツール版数が 6.1 以上の場合に利用できます。

// swift-tools-version: 6.1
import PackageDescription

let package = Package(
    name: "MyPackage",
    targets: [
        .target(
            name: "MyLibrary",
            swiftSettings: [
                // このターゲットでは @testable import を無効化する
                .enableTestableImport(false),
            ]
        ),
        .target(
            name: "MyOtherLibrary",
            swiftSettings: [
                // debug ビルドでだけ有効化したい場合は condition で絞り込める
                .enableTestableImport(true, .when(configuration: .debug)),
            ]
        ),
    ]
)

この設定を指定しない既存のターゲットは、これまで通りの挙動になります。つまり、debug 構成では @testable import が有効、release 構成では無効です。明示的に enableTestableImport(true) を release ビルドに対して指定した場合は、ビルド時に警告が出ます。

swift test のフラグの扱いの変更

swift test が持っている --enable-testable-imports / --disable-testable-imports フラグは、従来は前者がデフォルトで有効という扱いでしたが、本 Proposal では次のように変更されます。

  • デフォルトは「unspecified(未指定)」となり、ターゲット側の enableTestableImport 設定がそのまま尊重されます。
  • コマンドラインで --enable-testable-imports または --disable-testable-imports を明示した場合は、ターゲット側の設定に関わらず、すべてのターゲットに対して testability が一律に有効化/無効化されます。

これにより、個別ターゲットの設定を通常は尊重しつつ、必要に応じて CLI から全体を上書きできる挙動になります。

今後の見通し

将来の manifest バージョンでは、debug 構成でも @testable import をデフォルト無効にする変更が検討される可能性があります。現時点ではあくまで speculative な方向性で、本 Proposal の範囲には含まれません。