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.)
.pcm files are not stable between compiler versions, and since
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
.pcms 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
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!