Paulo Andrade

Keeper of Secrets.

twitter github stackoverflow linkedin email
Swift Build Times and Module Verification…
Aug 26, 2024
3 minutes read

It’s been a while since I’ve written anything here… I guess that’s mainly because I was focusing on building Secrets 4 and did not want to write about it before it launched. Then, I lost the habit of actually writing stuff here. Let’s see if I can change that.

One of the goals I had when I started developing Secrets 4 was to refactor the code into smaller modules. The reasoning behind this was two-fold:

  1. The Swift compiler back then actually fared much better with smaller modules than with larger, unique ones.
  2. I wanted to take advantage of Swift’s access control keywords (public, private, internal) to clearly define module boundaries and internal-only symbols.

The folder structure used before this refactor already had some idea of what each module would look like baked into it. So, it was just a matter of creating some frameworks, moving files around, and fixing import declarations and access control keywords. It was a slow but uneventful process.

Today, Secrets has 36 separate frameworks. The majority (33) are static frameworks that are bundled together in a single dynamic framework.

Along the way, Secrets’ build time must have gotten slower and slower without me really noticing it… until Xcode’s 16 betas, where I felt I really needed to understand what was going on.

Building with Timing Summaries

I finally took some time to investigate this and built the project with timing summaries1. The reasoning behind all this slowness became immediately clear…

Build timeline of Secrets

Build timeline of Secrets

The compiler is clearly spending most of the 3.5 minutes it took to build Secrets on verifying modules…

A quick search under the project’s build settings I see most of the newer modules have the ENABLE_MODULE_VERIFIER setting set to YES. Looking at Xcode’s documentation we can find exactly what this does:

In Xcode version 14.3 or later, enable the module verifier in your Xcode project’s build settings so that you can identify and address problems with your framework module before you distribute it. Some examples of these problems include:

  • Missing header references in your umbrella header
  • Using quoted includes instead of angle-bracketed includes
  • Using @import syntax in your public and private headers
  • Incorrect target conditionals
  • Imports inside of extern “C” language linkage specification
  • Non-modular headers in your umbrella header
  • References to private headers from public headers

When you enable the module verifier, it finds module problems in your code and displays errors for them in Xcode’s Issue navigator, just like compiler errors or warnings.

This all sounds good and dandy, especially if you’re distributing a framework, but I clearly don’t want to be doing this in Secrets on every build!

So I disabled it for debug builds.

Build timeline of Secrets after disabling module verification

Build timeline of Secrets after disabling module verification

This tweak brought down the build time from 3.5 minutes to 52 seconds 😮!

And it took me less than 30 minutes to find the issue and fix it… I have certainly waited for builds to finish for much longer than that in the past two years.

Conclusion

Building with timing summary is your friend. Don’t forget to call it periodically to see what’s up.


  1. In Xcode choose Product > Perform Action > Build with Timing Summary ↩︎



Back to posts