Assertions in Swift packages

TL;DR

I recently converted all the Objective-C libraries I am working on to SPM (using mostly SPM 5.3), but I just discovered that NSAsserts are not stripped out from release builds. This can lead to crashes in production code.

The situation is different with asserts in Swift package products since these assertions are stripped depending on the code optimization level, thus usually removed from release builds.

Is this desired behavior or was something missed in the case of Objective-C?

Thanks in advance for helping me understand this behavior.

Behavior in good old Xcode projects

If you create a project with Xcode, whether for an app, static lib or framework target, Xcode sets the ENABLE_NS_ASSERTIONS preprocessor flag by default only for debug builds. This means the NS_BLOCK_ASSERTIONS flag is set in release builds, disabling NSAssert macros.

This behavior is of course the default one but you can still change it if you want.

Behavior with Objective-C package products

Looking at an Objective-C package build log you can see that a package built in release mode does not have the NS_BLOCK_ASSERTIONS flag set and thus still contain NSAsserts.

Disabling assertions in a package manifest

It is of course possible to disable assertions in release builds:

.target(
    name: "MyPackage",
    cSettings: [
        .define("NS_BLOCK_ASSERTIONS", to: "1", .when(configuration: .release))
    ]
)

This of course requires you to have access to the package manifest.

2 Likes

Interesting, looks like traditional Xcode targets are getting an explicit ENABLE_NS_ASSERTIONS set to false via the project templates, but the real default value is true. Thanks for reporting this!

2 Likes