Skip to content

Commit

Permalink
Refactor the Swift compilation APIs to use a style similar to the C++…
Browse files Browse the repository at this point in the history
… APIs.

`swift_common.compile` now returns a tuple with two elements, very similar to `cc_common.compile`:

1. A "module context" (the same kind of value returned by `swift_common.create_module` that has `clang` and `swift` fields)
2. A `CcCompilationOutputs` object containing the object files.

The returned module context is slightly different than those propagated by the rules previously, in that its `clang` field will be present even if the Swift module doesn't propagate a Clang module. This is so that callers can easily retrieve its `compilation_context` and return it in a `CcInfo` provider. Therefore, callers who want to know whether a module context exposes a Clang module should check the `clang.module_map` field rather than just the `clang` field; it will be `None` if there is no Clang module.

A new method, `swift_common.create_linking_context_from_compilation_outputs`, has also been added, which provides similar functionality to the `cc_common` method of the same name. This takes the module context and compilation outputs from the `compile` call and produces a `LinkingContext` that can be returned in a `CcInfo` provider.

Of particular note, any toolchain-specific post-compile actions, such as module-wrapping or autolink extraction, have been moved into `create_linking_context_from_compilation_outputs`; they are no longer outputs of `compile`. This provides a clean API division between what is strictly compilation vs. the other supplemental outputs/flags that are passed to the linker, without making extra work to ensure that those outputs are generated.

PiperOrigin-RevId: 380030635
(cherry picked from commit 0bbf2d3)

 Conflicts:
	swift/internal/compiling.bzl
  • Loading branch information
allevato authored and thii committed Aug 11, 2021
1 parent b0ea825 commit 8cf3635
Show file tree
Hide file tree
Showing 12 changed files with 588 additions and 753 deletions.
393 changes: 152 additions & 241 deletions swift/internal/compiling.bzl

Large diffs are not rendered by default.

111 changes: 80 additions & 31 deletions swift/internal/debugging.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,20 @@

load(":actions.bzl", "run_toolchain_action", "swift_action_names")
load(":derived_files.bzl", "derived_files")
load(
":feature_names.bzl",
"SWIFT_FEATURE_DBG",
"SWIFT_FEATURE_FASTBUILD",
"SWIFT_FEATURE_NO_EMBED_DEBUG_MODULE",
)
load(":features.bzl", "is_feature_enabled")
load(":toolchain_config.bzl", "swift_toolchain_config")

def ensure_swiftmodule_is_embedded(
actions,
feature_configuration,
label,
swiftmodule,
target_name,
swift_toolchain):
"""Ensures that a `.swiftmodule` file is embedded in a library or binary.
Expand All @@ -33,55 +40,51 @@ def ensure_swiftmodule_is_embedded(
Args:
actions: The object used to register actions.
feature_configuration: The Swift feature configuration.
label: The `Label` of the target being built.
swiftmodule: The `.swiftmodule` file to be wrapped.
target_name: The name of the target being built.
swift_toolchain: The `SwiftToolchainInfo` provider of the toolchain.
Returns:
A `struct` containing three fields:
* `linker_flags`: A list of additional flags that should be propagated
to the linker.
* `linker_inputs`: A list of additional inputs that are not necessarily
object files, but which are referenced in `linker_flags` and should
therefore be passed to the linker.
* `objects_to_link`: A list of `.o` files that should be included in the
static archive or binary that represents the module.
A `LinkerInput` containing any flags and/or input files that should be
propagated to the linker to embed the `.swiftmodule` as debugging
information in the binary.
"""
linker_flags = []
linker_inputs = []
objects_to_link = []

if swift_toolchain.object_format == "elf":
# For ELF-format binaries, we need to invoke a Swift modulewrap action
# to wrap the .swiftmodule file in a .o file that gets propagated to the
# linker.
modulewrap_obj = derived_files.modulewrap_object(
actions,
target_name = target_name,
target_name = label.name,
)
objects_to_link.append(modulewrap_obj)

_register_modulewrap_action(
actions = actions,
feature_configuration = feature_configuration,
object = modulewrap_obj,
swiftmodule = swiftmodule,
swift_toolchain = swift_toolchain,
)
elif swift_toolchain.object_format == "macho":
linker_flags.append("-Wl,-add_ast_path,{}".format(swiftmodule.path))
linker_inputs.append(swiftmodule)
else:
fail("Internal error: Unexpected object format '{}'.".format(
swift_toolchain.object_format,
))

return struct(
linker_flags = linker_flags,
linker_inputs = linker_inputs,
objects_to_link = objects_to_link,
)

# Passing the `.o` file directly to the linker ensures that it links to
# the binary even if nothing else references it.
return cc_common.create_linker_input(
additional_inputs = depset([modulewrap_obj]),
owner = label,
user_link_flags = depset([modulewrap_obj.path]),
)

if swift_toolchain.object_format == "macho":
return cc_common.create_linker_input(
owner = label,
user_link_flags = depset([
"-Wl,-add_ast_path,{}".format(swiftmodule.path),
]),
additional_inputs = depset([swiftmodule]),
)

fail("Internal error: Unexpected object format '{}'.".format(
swift_toolchain.object_format,
))

def modulewrap_action_configs():
"""Returns the list of action configs needed to perform module wrapping.
Expand All @@ -102,6 +105,52 @@ def modulewrap_action_configs():
),
]

def should_embed_swiftmodule_for_debugging(
feature_configuration,
module_context):
"""Returns True if the configuration wants modules embedded for debugging.
Args:
feature_configuration: The Swift feature configuration.
module_context: The module context returned by `swift_common.compile`.
Returns:
True if the `.swiftmodule` should be embedded by the linker for
debugging.
"""
return (
module_context.swift and
module_context.swift.swiftmodule and
_is_debugging(feature_configuration = feature_configuration) and
not is_feature_enabled(
feature_configuration = feature_configuration,
feature_name = SWIFT_FEATURE_NO_EMBED_DEBUG_MODULE,
)
)

def _is_debugging(feature_configuration):
"""Returns `True` if the current compilation mode produces debug info.
We replicate the behavior of the C++ build rules for Swift, which are
described here:
https://docs.bazel.build/versions/master/user-manual.html#flag--compilation_mode
Args:
feature_configuration: The feature configuration.
Returns:
`True` if the current compilation mode produces debug info.
"""
return (
is_feature_enabled(
feature_configuration = feature_configuration,
feature_name = SWIFT_FEATURE_DBG,
) or is_feature_enabled(
feature_configuration = feature_configuration,
feature_name = SWIFT_FEATURE_FASTBUILD,
)
)

def _modulewrap_input_configurator(prerequisites, args):
"""Configures the inputs of the modulewrap action."""
swiftmodule_file = prerequisites.swiftmodule_file
Expand Down
Loading

0 comments on commit 8cf3635

Please sign in to comment.