How To Fix 'LLDB: Couldn't IRGen Expression' Without Source Code
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 followed Peter Steinberger’s journey on fixing “LLDB: Couldn’t IRGen Expression” and related issues, you’ve probably already read his blog post that explains why this happens. Matt Robinson also wrote a very detailed article about how to deal with the same issue if you’re building your frameworks using Carthage.
In a not very uncommon scenario, when the issues come from a closed source
framework, and your vendor didn’t build the framework using the same Xcode /
Swift compiler version that you’re using, or didn’t build it with “Build
Libraries for Distribution” enabled, or didn’t build it with
SWIFT_SERIALIZE_DEBUGGING_OPTIONS = NO, there’s a chance it could take a long
time before you can receive an update of the framework with the fix you have
requested. In this post, I’ve collected some hacks that can help you work
around the problem and get the debugger working without having to wait for a
fix.
Case 1: Both swiftmodule and swiftinterface are included; swiftinterface files are valid
Solution: Force compiling with swiftinterface.
If your vendor packages their framework properly, it should only include
swiftinterface files, but not any swiftmodule files. If both are included,
Xcode will try to import the swiftmodule file first, which could lead to one of
the above errors when using LLDB with po, vo or e. Since the
swiftinterface files are all we need, we could patch the framework to remove
all the swiftmodule files:
rm -f FrameworkName.framework/Modules/FrameworkName.swiftmodule/*.swiftmodule
Note that what we need to remove are the swiftmodule files in the
.swiftmodule directory in the Modules directory, but 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 giving them to Xcode.
Unfortunately, not all swiftinterfaces are created validly, as there is currently no way to have them automatically validated. A common error you might get is that Xcode can’t import the interface file if the framework has a type with the same name, as the generated interface file always references a type using its full namespace.
‘FrameworkName’ is not a member type of ‘FrameworkName’
A possible workaround is to process the swiftinterface file and remove all the
occurrences of the framework name that lead to any ambiguity, until it becomes
a valid swiftinterface. This is obviously not great, as you would have to
keep track of all the interface changes at every update; but if you ever get an
update, you probably don’t have to do this anymore.
Case 3: Only swiftmodule files are included
Solution: Construct swiftinterface from swiftmodule.
Since “Build Libraries for Distribution” affects how the module is built in
the first place, there currently seems to
be no way to automatically generate 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 ten seconds :)), Xcode will
display a generated interface for that module. We can copy that piece of text
and manually construct the swiftinterface ourselves. It’s just a text file
with some predefined header comments like the following: (If you use this, be
sure to change the swift-compiler-version, swift-module-flags and
FrameworkName to match 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 validate the manually constructed 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
Probably it’s not long until someone writes a tool that automates all these.