Flag -import-underlying-module Does Not Work
-import-underlying-module build flag causes implicit imports of Objective-C files into Swift, within the same module. This flag unfortunately doesn’t work with Buck.
When Xcode generates frameworks, it generates
.hmap header map files to indicate header locations. The
swift tool later uses these files to import Objective-C headers. However, since Buck doesn’t generate independent frameworks, it doesn’t generate these files. Thus, the
-import-underlying-module flag doesn’t work in the
This means that we have to explicitly pass in bridging headers to the
swift tool. Doing this, however, results in a few more problems.
Unable to Use Bridging Header
Consider this example:
A.h contains the line
#import “B.h”, but
B.h is put under
folderB/. This works perfectly with Xcode with the help of
.hmap. But in Buck, this doesn’t work since it is not able to locate
In this PR, we updated Buck to allow it to generate header maps for use by the
swift tool, allowing the tool to locate header files and import them.
Unable to Locate Bridging Header Inside *-Swift.h
swift tool generates
*-Swift.h files, it explicitly imports bridging headers for Objective-C definitions. This breaks Buck builds.
According to Apple’s code, when using the
-import-underlying-module flag, the generated
*-Swift.h files import project headers. For example:
When providing bridging headers explicitly however (as we need to do with Buck) the generated
*-Swift.h files end up importing bridging header files directly:
As you can see, the imported path is a relative one. When another file imports this
*-Swift.h file, it won’t be able to locate the bridging header.
In this commit, we updated Buck to pass
-iquote buckRootPath as a compiler argument. That specifically tells the
swift tool to look for the bridging header files at
@import Does Not Work
There are two ways to import header files into Objective-C,
@import doesn’t work in Buck since Buck doesn’t generate
This actually requires us to replace
@import M with
#import <M/M.h> and/or
#import <M/M-Swift.h>. This is simple enough for our own source code. However, it’s a bit trickier for generated code.
*-Swift.h files, for instance, always use
To address this, we used an admittedly hacky solution, introducing this script to perform the replacement on the fly. In this commit, we added to Buck’s
apple_library build rule a new
objc_header_transform_script parameter, which allowed us to invoke the replacement script on all the
This change knocked down our last big blocker for using Buck.