rules_swift icon indicating copy to clipboard operation
rules_swift copied to clipboard

Importing header maps

Open esam091 opened this issue 5 years ago • 2 comments

I have a swift_library depending on an objc_library that has a header map like this

swift_library(
  name = 'Foo'
)

objc_library(
  name = 'Bar',
  hdrs = ['**/*.h'],
  includes = ['.', 'headers.hmap'],
  textual_hdrs = ['headers.hmap']
)

The generated compiler params actually generates the include copts like this

-Ipath/to/Bar
-Ipath/to/Bar/headers.hmap

This doesn't work because the -I flag of swiftc cannot import header maps, so you need to pass this flag to clang

-Xcc
-Ipath/to/Bar
-Xcc
-Ipath/to/Bar/headers.hmap

The quickest way to do this seem to be by modifying all the include flags to use clang instead of swiftc like above. Are there any other suggestions?

esam091 avatar Sep 16 '19 04:09 esam091

That isn't really a supported use of the includes attribute (or textual_hdrs) on objc_library; it just works by accident for Objective-C because header maps use the same command line flag as regular include search paths (-I) and textual_hdrs puts the file into the action inputs without any other processing. But the purpose of the includes attributes is that it is a list of package-relative paths that are propagated up to dependencies via the Objc provider, and swift_library uses that provider to determine which paths it should also add to its own search paths.

So for right now, the easiest thing to do is what you've already suggested; use -Xcc to ensure that the flags get passed to clang instead of to swiftc.

FWIW, we could probably modify the Swift rules to pass header search paths from C rules via -Xcc -I instead of -I, because there's no reason for swiftc to treat them as Swift paths. I can't do that safely until Swift 5.1 is more widely used though, because anything that increases the command line length might break some users until they're on that version of the compiler, which fixes all of the remaining issues around long command lines.

But even if we fixed that, passing a .hmap file in textual_hdrs is dangerous, because objc_library assumes that anything in that attribute is still a "header" rather than "any file", so if that gets propagated in the Objc provider or written into the objc_library's module map under the assumption that it qualifies as a "textual header", it might get treated incorrectly by upstream rules.

allevato avatar Sep 16 '19 15:09 allevato

That isn't really a supported use of the includes attribute (or textual_hdrs) on objc_library

Yeah definitely gonna be changed in the future since this is just a proof of concept.

I can't do that safely until Swift 5.1 is more widely used though

Is there any ETA of this, like a few months after Xcode 11 stable is released? I can create a PR for this to be merged when the time is right. For now, I'll just add this modification in my own fork.

I think I'm gonna make a rule just to append the header map into the Objc provider and process the includes with the said fork.

swift_library(
  name = 'Foo',
  deps = ['Bar']
)

objc_library(
  name = 'Bar',
  hdrs = ['**/*.h'],
  deps = ['hmap']
)

header_map(
  name = 'hmap',
  src = 'headers.hmap'
)

Since I'm gonna be doing this a lot, it would be quite tedious to write this rule. Is it a valid thing in Bazel to wrap two rules into one?

# BUILD
swift_library(
  name = 'Foo',
  deps = ['Bar']
)

wrapped_objc_library(
  name = 'Bar',
  hdrs = ['**/*.h'],
)

# scripts.bzl
def wrapped_objc_library(name, ...other_args):
  objc_library(
    name = name,
    hdrs = ['**/*.h'],
    deps = ['hmap']
  )

  header_map(
    name = 'hmap',
    src = 'headers.hmap'
  )

esam091 avatar Sep 17 '19 02:09 esam091