Swift Digest
SE-0190 | Swift Evolution

Target environment platform condition

Proposal
SE-0190
Authors
Erica Sadun, Graydon Hoare
Review Manager
Ted Kremenek
Status
Implemented (Swift 4.1)

01 何が問題だったのか

ビルドするターゲットがシミュレータなのか実機なのかによってコードを切り替えたい場面は、Metal、Keychain、AVFoundation のカメラなどを扱うときに頻繁に現れます。しかし、Swift にはシミュレータかどうかを直接問い合わせるコンパイル条件がありませんでした。

アーキテクチャとOSの組み合わせで代用するしかなかった

そのため、これまでは「シミュレータでしか使われないアーキテクチャ」と「OS」の組み合わせでシミュレータかどうかを判定する、という回りくどい書き方をする必要がありました。

// シミュレータかどうかを判定する
#if (arch(i386) || arch(x86_64)) && (!os(macOS))
    print("Simulator")
#else
    print("Device")
#endif

// iOS シミュレータに限定した判定
// watchOS や tvOS では os の部分を差し替える必要がある
#if (arch(i386) || arch(x86_64)) && os(iOS)
    // iOS シミュレータ向けのコード
#endif

この書き方には次のような問題があります。

  • 条件の意図(「シミュレータかどうか」)がコードから読み取りにくい
  • アーキテクチャとOSの対応関係という実装詳細に依存しているため脆く、新しいアーキテクチャのシミュレータが登場すると破綻する
  • プラットフォームごとに条件式を書き分けなければならない

要するに、やりたいことは「シミュレータかどうかを知る」というシンプルな話なのに、それを表現する直接的な手段が言語側に用意されていなかったのです。

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

新しいプラットフォーム条件 targetEnvironment が追加され、引数 simulator を指定することで「現在のコンパイルターゲットがシミュレータ環境かどうか」を直接問い合わせられるようになります。

基本的な使い方

#if targetEnvironment(simulator) と書くだけで、シミュレータ向けビルドかどうかで分岐できます。

#if targetEnvironment(simulator)
    print("Simulator")
#else
    print("Device")
#endif

特定のOSのシミュレータに限定したい場合は、既存の os() と組み合わせます。

#if targetEnvironment(simulator) && os(iOS)
    // iOS シミュレータ向けのコード
#endif

アーキテクチャとOSの組み合わせを推測する必要がなくなり、意図がそのままコードに現れます。

どのように判定されるか

この条件は、コンパイラに渡される target triple の第4フィールド(environment)を見て判定されます。たとえば target triple が arm64-apple-tvos-simulator のように simulator を environment に含んでいれば、targetEnvironment(simulator) は真となります。

移行期間中の互換性のため、environment フィールドが明示されていない target triple であっても、残りのフィールドからシミュレータ環境であることが推測できる場合には targetEnvironment(simulator) が真として扱われます。したがって、既存のビルド設定をそのまま使っていても期待どおりに動作します。

なお、既存の (arch(...) || ...) && !os(macOS) のような書き方も引き続き動作します。ただし可能であれば、可読性と将来の拡張性の両面から targetEnvironment(simulator) への書き換えが推奨されます。

Future Directions

targetEnvironment は、target triple の environment フィールドに対応する汎用的な拡張点として設計されています。今後、シミュレータ以外にも区別したいターゲット環境が出てきた場合には、targetEnvironment(...) に新しい引数を追加していく形で表現される見通しです(実現を約束するものではありません)。