Skip to content

Commit

Permalink
Have swift_clang_module_aspect always generate the module map for O…
Browse files Browse the repository at this point in the history
…bjective-C targets, instead of using the one generated by Bazel.

The one exception is when a custom module map is provided using the `module_map` attribute; in that case, that module map is still used. But in all cases, the `direct_module_maps` field of `ObjcProvider` is no longer read by the Swift build rules.

This change includes some very unfortunate workarounds to address J2ObjC's tightly coupled relationship with the Obj-C logic in Bazel; even though the module map is never used, Bazel must still generate it since umbrella header generation is coupled to it. In doing so, however, this change also updates module map generation to support expanding directory artifacts and listing umbrella headers (which we may want to support in `swift_interop_hint` separately in the future).

PiperOrigin-RevId: 395704174
  • Loading branch information
allevato authored and swiple-rules-gardener committed Sep 9, 2021
1 parent 5b66904 commit 868a76b
Show file tree
Hide file tree
Showing 2 changed files with 163 additions and 126 deletions.
64 changes: 28 additions & 36 deletions swift/internal/module_maps.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ def write_module_map(
public_textual_headers = [],
private_headers = [],
private_textual_headers = [],
umbrella_header = None,
workspace_relative = False):
"""Writes the content of the module map to a file.
Expand All @@ -49,6 +50,9 @@ def write_module_map(
headers of the target whose module map is being written.
private_textual_headers: The `list` of `File`s representing the private
textual headers of the target whose module map is being written.
umbrella_header: A `File` representing an umbrella header that, if
present, will be written into the module map instead of the list of
headers in the compilation context.
workspace_relative: A Boolean value indicating whether the header paths
written in the module map file should be relative to the workspace
or relative to the module map file.
Expand All @@ -74,25 +78,35 @@ def write_module_map(
content.add_all(exported_module_ids, format_each = " export %s")
content.add("")

def _relativized_header_paths(file_or_dir, directory_expander):
return [
_header_path(
header_file = file,
relative_to_dir = relative_to_dir,
back_to_root_path = back_to_root_path,
)
for file in directory_expander.expand(file_or_dir)
]

def _add_headers(*, headers, kind):
# Each header is added to the `Args` object as a tuple along with
# `relative_to_dir` and `back_to_root_path`. This gives the mapping
# function the information it needs to relativize the header paths even
# when they're expanded from a tree artifact (and thus not known at
# analysis time).
content.add_all(
[(file, relative_to_dir, back_to_root_path) for file in headers],
headers,
allow_closure = True,
format_each = ' {} "%s"'.format(kind),
map_each = _header_info_mapper,
map_each = _relativized_header_paths,
)

if umbrella_header:
_add_headers(headers = [umbrella_header], kind = "umbrella header")
else:
_add_headers(headers = public_headers, kind = "header")
_add_headers(headers = private_headers, kind = "private header")
_add_headers(headers = public_textual_headers, kind = "textual header")
_add_headers(
headers = private_textual_headers,
kind = "private textual header",
)

_add_headers(headers = public_headers, kind = "header")
_add_headers(headers = private_headers, kind = "private header")
_add_headers(headers = public_textual_headers, kind = "textual header")
_add_headers(
headers = private_textual_headers,
kind = "private textual header",
)
content.add("")

# Write a `use` declaration for each of the module's dependencies.
Expand All @@ -104,28 +118,6 @@ def write_module_map(
output = module_map_file,
)

def _header_info_mapper(header_info, directory_expander):
"""Maps header info passed to the `Args` object to a list of header paths.
Args:
header_info: A tuple containing three elements: a `File` representing a
header (or a directory containing headers), the path to the
directory that should be used to relativize the header paths, and
the path string consisting of repeated `../` segments that should be
used to return from the module map's directory to the workspace
root. The latter two elements will be `None` if the headers should
be written workspace-relative).
directory_expander: The object used to expand tree artifacts into the
list of files in that directory.
Returns:
A list of file paths as they should be written into the module map file.
"""
return [
_header_path(file, header_info[1], header_info[2])
for file in directory_expander.expand(header_info[0])
]

def _header_path(header_file, relative_to_dir, back_to_root_path):
"""Returns the path to a header file to be written in the module map.
Expand Down
Loading

1 comment on commit 868a76b

@thii
Copy link
Member

@thii thii commented on 868a76b Sep 16, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.