#if DEBUG in Swift

Sigh.

The Swift team give an impeccable impression of a group of people who’ve never actually tried to use Swift.

An incredibly basic compiler task is to provide code a way to distinguish between debug & release builds, in order that it can behave accordingly (e.g. change the default logging verbosity, change asserts from fatal to non-fatal, etc).

Long story short there is no way to do this that works correctly with swift build.

You can make it work with Xcode only by way of a simple workaround – you manually define a custom Swift flag in your target’s settings (here’s one of a bajillion explanations of how do this).  You end up with basically identical code to other C-family languages, e.g.:

#if DEBUG
    let logVerbosity = 1
#else
    let logVerbosity = 0
#endif

But there is no way, when using swift build, to specify custom Swift flags in your package config.

You can specify them manually with every single swift build invocation, e.g.:

swift build -c debug -Xswiftc ‘-DDEBUG’

But now you have extra work and the possibility of screwing it up (e.g. omitting the flag, or mismatching it to your actual build style).

The closest you can get is to use some undocumented, hidden Swift internal library functions:

func _isDebugAssertConfiguration() -> Bool
func _isFastAssertConfiguration() -> Bool

These are defined in swift/stdlib/public/core/AssertCommon.swift.

Only the first is likely to be useful.  The second applies in the case where you’re building not just for release but unchecked (-Ounchecked).  If you just want to conditionalise on release builds generally, you have to do !_isDebugAssertConfiguration().

The additional problem with this approach is that these are then, in your code, runtime checks.  And the compiler then thinks it’s being helpful by pointing out that some of your code that uses them is unreachable.

And of course Swift has absolutely no way to silence compiler warnings, or otherwise tell the compiler not to trust its reachability checks.

Sigh.

Leave a Reply