I'm trying to improve distributed build performance of Swift with Bazel, where we often have large dependency graphs with many Swift and Objective-C modules. Since the implicit module cache can't be shared across remote machines, one improvement I'd like to make is to emit precompiled modules for the (Obj-)C dependencies with -Xclang -fmodules-embed-all-files
and propagate those up the graph instead of using the text module maps, so that ClangImporter doesn't have to keep reparsing the transitive closure of the headers imported by a Swift module. (And also so our build farm doesn't have to copy that large number of headers from source control, which is currently also a bottleneck.)
Since .pcm
files are not stable between compiler versions, and since swiftc
and clang
in the same toolchain aren't even guaranteed to be built from the same version, I can't use our existing Obj-C compilation to generate these modules.
Instead, I've hacked together a totally-not-ready-for-review-yet change that adds a driver invocation (swift -generate-pcm
) that uses ClangImporter to emit .pcm
s that should be compatible, since the same compiler and invocation that emits them will consume them. Then, when I compile the Swift code that depends on an Objective-C module, I precompile it and I feed it in with -Xcc -fmodule-file=path/to/module.pcm
.
For very trivial cases, that seems to be working. But when I try to precompile something that does #import <UIKit/UIKit.h>
, I'm seeing errors like this:
While building module 'REDACTED':
While building module 'UIKit' imported from REDACTED:15:
While building module 'CoreImage' imported from /Applications/Xcode-beta.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator13.0.sdk/System/Library/Frameworks/UIKit.framework/Headers/UIColor.h:13:
While building module 'CoreVideo' imported from /Applications/Xcode-beta.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator13.0.sdk/System/Library/Frameworks/CoreImage.framework/Headers/CIImage.h:10:
In file included from <module-includes>:1:
In file included from /Applications/Xcode-beta.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator13.0.sdk/System/Library/Frameworks/CoreVideo.framework/Headers/CoreVideo.h:20:
In file included from /Applications/Xcode-beta.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator13.0.sdk/System/Library/Frameworks/CoreVideo.framework/Headers/CVReturn.h:21:
/Applications/Xcode-beta.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator13.0.sdk/System/Library/Frameworks/CoreVideo.framework/Headers/CVBase.h:175:9:
error: declaration of 'uint64_t' must be imported from module 'Darwin.C.stdint' before it is required
typedef uint64_t CVOptionFlags;
Sure enough, if I look in CoreVideo/CVBase.h, there's no direct import of <stdint.h>
to be found; presumably it's coming in from a transitive inclusion. But what I can't figure out is, why wouldn't this error also occur when ClangImporter is building implicit modules for the module cache under a more traditional compilation that uses text module maps? What's different about the precompiled case?
I don't have a lot of expertise in the lower-level details of Clang modules, so if anyone has any insight, I'd love to hear it!