How To Fix 'LLDB: Couldn't IRGen Expression' Without Source Code


Overview

error: virtual filesystem overlay file '/Users/user/Library/Developer/Xcode/DerivedData/SDK-abcdefghijklmnopqrstuvwxyzab/Build/Intermediates.noindex/SDK.build/Release-iphonesimulator/SDK.build/all-product-headers.yaml' not found

error: couldn't IRGen expression. Please check the above error messages for possible root causes.

If you’ve been following Peter Steinberger’s journey on resolving the “LLDB: Couldn’t IRGen Expression” and related issues, you’ve likely already read his blog post explaining why this occurs. Matt Robinson also authored a comprehensive article on dealing with the same issue when building your frameworks with Carthage.

In a rather common scenario, problems arise from a closed-source framework, and if your vendor didn’t build the framework using the same Xcode/Swift compiler version that you’re using, didn’t enable “Build Libraries for Distribution”, or didn’t set SWIFT_SERIALIZE_DEBUGGING_OPTIONS = NO, you may have to wait quite a while for an update of the framework with the fix you’ve requested. In this post, I’ve gathered some workarounds to help you overcome the problem and get the debugger working without needing to wait for a fix.

Case 1: Both swiftmodule and swiftinterface are included, and

swiftinterface files are valid

Solution: Force compilation with swiftinterface.

If your vendor packages their framework correctly, it should only include swiftinterface files, not swiftmodule files. If both are present, Xcode will try to import the swiftmodule file first, which could trigger one of the above errors when using LLDB with po, vo or e. As the swiftinterface files are all we need, we can patch the framework to eliminate all the swiftmodule files:

rm -f FrameworkName.framework/Modules/FrameworkName.swiftmodule/*.swiftmodule

Keep in mind that we need to remove the swiftmodule files located in the .swiftmodule directory in the Modules directory, not the .swiftmodule directory itself.

Case 2: Both swiftmodule and swiftinterface are included, but

swiftinterface files are invalid

Solution: Remove all swiftmodule files and preprocess invalid swiftinterface files before handing them to Xcode.

Unfortunately, not all swiftinterface files are valid, as there is currently no way to automatically validate them. A common error you might encounter is that Xcode can’t import the interface file if the framework has a type with the same name, since the generated interface file always refers to a type using its full namespace.

'FrameworkName' is not a member type of 'FrameworkName'

One potential workaround is to edit the swiftinterface file and remove all instances of the framework name that cause any ambiguity, until you obtain a valid swiftinterface. This is far from ideal, as you would have to monitor all the interface changes with every update. However, if you receive an update, you likely won’t need to do this anymore.

Case 3: Only swiftmodule files are included

Solution: Generate swiftinterface from swiftmodule.

Since “Build Libraries for Distribution” impacts how the module is built in the first place, it currently appears that there’s no way to automatically create a swiftinterface from the swiftmodule without the module’s source code. However, in Xcode, if we select the pre-compiled framework’s module name from an import statement, right-click, and select Jump to Definition (and wait for about ten seconds), Xcode will display a generated interface for that module. We can copy that text and manually create the swiftinterface ourselves. It’s just a text file with some predefined header comments like the following: (If you use this, be sure to update the swift-compiler-version, swift-module-flags and FrameworkName to suit your needs.)

// swift-interface-format-version: 1.0
// swift-compiler-version: Apple Swift version 5.2 (swiftlang-1103.0.32.1 clang-1103.0.32.29)
// swift-module-flags: -target x86_64-apple-ios10.0-simulator -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -O -module-name FrameworkName
@_exported import FrameworkName
// Copy and paste generated interface from Xcode here

To verify the manually created swiftinterface file, try to regenerate a swiftmodule from it with:

swift -frontend \
  -compile-module-from-interface \
  -o <output-swiftmodule> \
  -sdk </path/to/sdk> \
  -target <target-triple> \
  -enable-library-evolution \
  -module-name <module-name> \
  <input-swiftinterface>

For example:

swift -frontend \
  -compile-module-from-interface \
  -o x86_64.swiftmodule \
  -sdk `xcode-select -p`/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator14.3.sdk \
  -target x86_64-apple-ios10.0-simulator \
  -enable-library-evolution \
  -module-name FrameworkName \
  x86_64.swiftinterface