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