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