- Proposal: SE-0190
- Authors: Erica Sadun, Graydon Hoare
- Review Manager: Ted Kremenek
- Status: Implemented (Swift 4.1)
- Swift Evolution Review Thread
- Implementation: apple/swift#12964
- Decision Notes: Rationale
This proposal introduces a platform condition to differentiate device and simulator builds. This condition subsumes a common pattern of conditional compilation for Metal, Keychain, and AVFoundation Camera code.
Swift-evolution threads:
- Expanding Build Configuration Tests for Simulator and Device targets
- Target environment platform condition
A common developer requirement is to conditionally compile code based on whether the current compilation target is a simulator or a real device. The current technique for accomplishing this involves testing for particular combinations of presumed mismatch between architecture and operating system. This is fragile and non-obvious, and requires reasoning about complex nested conditions that obscure the user's purpose.
For example, code often looks like this:
// Test for a simulator destination
#if (arch(i386) || arch(x86_64)) && (!os(macOS))
print("Simulator")
#else
print("Device")
#endif
// More restrictive test for iOS simulator
// Adjust the os test for watchOS, tvOS
#if (arch(i386) || arch(x86_64)) && os(iOS)
// iOS simulator code
#endif
This proposal adds a new platform condition targetEnvironment
with a single valid
argument: simulator
.
In other words, the proposal is to enable conditional compilation of the form
#if targetEnvironment(simulator)
.
When the compiler is targeting simulator environments, the targetEnvironment(simulator)
condition will evaluate to true
. Otherwise it will evaluate as false
.
In the future, other target environments may be indicated using different arguments to
the targetEnvironment
condition. It is a general extension point for disambiguating
otherwise-similar target environments.
The name of the condition is motivated by the fact that an unambiguous indication of target environment can be made using the 4th (seldom used, but valid) environment field of the target triple provided to the compiler.
In other words, if the compiler's target triple is specified with an environment
field such as arm64-apple-tvos-simulator
, the targetEnvironment(simulator)
condition
will be set.
As a transitionary measure: until users have migrated to consistent use of target triples
with an explicit simulator
value in the environment field, the Swift compiler
will infer it from the remaining components of the target triple, without requiring the
user to approximate the condition through combinations of os
and arch
platform
conditions.
In other words, while a given target triple may be missing the environment field,
the targetEnvironment(simulator)
condition may still be true
, if it is inferred
that the current target triple denotes a simulator environment.
This is an additive proposal, existing code will continue to work.
A warning and fixit may be provided for migrating recognizable cases in existing code, but this will necessarily be best-effort, as existing conditions may be arbitrarily complex.
None
None
Swift currently supports the following platform conditions:
- The
os()
function that tests formacOS, iOS, watchOS, tvOS, Linux, Windows, FreeBSD, Android, PS4, Cygwin and Haiku
- The
arch()
function that tests forx86_64, arm, arm64, i386, powerpc64, powerpc64le and s390x
- The
swift()
function that tests for specific Swift language releases, e.g.swift(>=2.2)
- Rust's conditional compilation system
includes the
target_env
configuration option, which similarly presents the environment field of the target triple. - In Clang, several environment-based preprocessor symbols can be used to achieve similar
effects (
__CYGWIN__
,__ANDROID__
, etc.) though the mapping is quite ad-hoc and the 4th field of the target triple is officially documented as representing the target ABI. In the implementation, however, the 4th field is treated as environment (subsuming ABI) and a 5th field for object format is supported. - Clang also supports various flags such as
-mtvos-simulator-version-min
which define a simulator-specific preprocessor symbol__APPLE_EMBEDDED_SIMULATOR__
.
Some possible alternatives were considered:
- As in the first round of this proposal,
target(simulator)
. This has the advantage of brevity, but the disadvantage of using a relatively overloaded term, and contradicts the existing design of using a separate condition per-component of the target triple (os()
andarch()
). - A similarly brief
environment(simulator)
condition, which has the disadvantage that users may mistake it for a means of accessing environment variables of the compiler process. - An additional state for the
os
orarch
conditions, such asos(simulator)
. This would complicate both the definition and implementation of platform conditions, while blurring the notion of an operating system. - Avoidance of the target triple altogether, and use of a dedicated
simulator()
platform condition. This is the simplest option, but is less-similar to existing conditions and may introduce more meaningless combinations of flags as the set of target environments grows (rather than mutually exclusive arguments totargetEnvironment
).