Skip to content

Commit

Permalink
Refactor slightly how actions are registered in the Swift rules.
Browse files Browse the repository at this point in the history
Swift toolchains now have a `swift_executable` attribute that lets the configurator replace the Swift driver used by the rules with a custom executable in their workspace. This can be useful for testing the build rules alongside compiler development, and since that file is part of the workspace and a proper input of actions, it also works correctly across remote build environments.

Also remove the no-longer-used `SwiftToolchainInfo.clang_executable` field, now that linking has migrated to the `cc_common.link` API.

RELNOTES: None.
PiperOrigin-RevId: 281620086
  • Loading branch information
allevato authored and swiple-rules-gardener committed Nov 21, 2019
1 parent e8b14ed commit f51e689
Show file tree
Hide file tree
Showing 8 changed files with 119 additions and 55 deletions.
71 changes: 53 additions & 18 deletions swift/internal/actions.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -18,27 +18,49 @@ load("@bazel_skylib//lib:dicts.bzl", "dicts")
load("@bazel_skylib//lib:paths.bzl", "paths")
load("@bazel_skylib//lib:types.bzl", "types")

def get_swift_tool(swift_toolchain, tool):
"""Gets the path to the given Swift toolchain tool.
def _get_swift_driver_mode_args(driver_mode, swift_toolchain):
"""Gets the arguments to pass to the worker to invoke the Swift driver.
Args:
driver_mode: The mode in which to invoke the Swift driver. In other
words, this is the name of the executable of symlink that you want
to execute (e.g., `swift`, `swiftc`, `swift-autolink-extract`).
swift_toolchain: The Swift toolchain being used to register actions.
tool: The name of a tool in the Swift toolchain (i.e., in the `bin`
directory).
Returns:
The path to the tool. If the toolchain provides a root directory, then
the path will include the `bin` directory of that toolchain. If the
toolchain does not provide a root, then it is assumed that the tool will
be available by invoking just its name (e.g., found on the system path
or by another delegating tool like `xcrun` from Xcode).
A list of values that can be added to an `Args` object and passed to the
worker to invoke the command.
This method implements three kinds of "dispatch":
1. If the toolchain provides a custom driver executable, it is invoked
with the requested mode passed via the `--driver_mode` argument.
2. If the toolchain provides a root directory, then the returned list
will be the path to the executable with the same name as the driver
mode in the `bin` directory of that toolchain.
3. If the toolchain does not provide a root, then it is assumed that
the tool will be available by invoking just the driver mode by name
(e.g., found on the system path or by another delegating tool like
`xcrun` from Xcode).
"""
if ("/" not in tool and swift_toolchain.root_dir):
return paths.join(swift_toolchain.root_dir, "bin", tool)
return tool
if swift_toolchain.swift_executable:
return [
swift_toolchain.swift_executable,
"--driver-mode={}".format(driver_mode),
]

if swift_toolchain.root_dir:
return [paths.join(swift_toolchain.root_dir, "bin", driver_mode)]

def run_swift_action(actions, swift_toolchain, **kwargs):
"""Executes a Swift toolchain tool using the worker.
return [driver_mode]

def run_swift_action(
actions,
arguments,
driver_mode,
swift_toolchain,
**kwargs):
"""Executes the Swift driver using the worker.
This function applies the toolchain's environment and execution requirements
and wraps the invocation in the worker tool that handles platform-specific
Expand All @@ -48,18 +70,24 @@ def run_swift_action(actions, swift_toolchain, **kwargs):
Since this function uses the worker as the `executable` of the underlying
action, it is an error to pass `executable` into this function. Instead, the
tool to run should be the first item in the `arguments` list (or in the
first `Args` object). This tool should be obtained using `get_swift_tool` in
order to correctly handle toolchains with explicit root directories.
`driver_mode` argument should be used to specify which Swift tool should be
invoked (`swift`, `swiftc`, `swift-autolink-extract`, etc.). This lets the
rules correctly handle the case where a custom driver executable is provided
by passing the `--driver-mode` flag that overrides its internal `argv[0]`
handling.
Args:
actions: The `Actions` object with which to register actions.
arguments: The arguments to pass to the invoked action.
driver_mode: The mode in which to invoke the Swift driver. In other
words, this is the name of the executable of symlink that you want
to execute (e.g., `swift`, `swiftc`, `swift-autolink-extract`).
swift_toolchain: The Swift toolchain being used to register actions.
**kwargs: Additional arguments to `actions.run`.
"""
if "executable" in kwargs:
fail("run_swift_action does not support 'executable'. " +
"The tool to run should be the first item in 'arguments'.")
"Use 'driver_mode' instead.")

remaining_args = dict(kwargs)

Expand All @@ -86,7 +114,14 @@ def run_swift_action(actions, swift_toolchain, **kwargs):
else:
tools = toolchain_files

driver_mode_args = actions.args()
driver_mode_args.add_all(_get_swift_driver_mode_args(
driver_mode = driver_mode,
swift_toolchain = swift_toolchain,
))

actions.run(
arguments = [driver_mode_args] + arguments,
env = env,
executable = swift_toolchain.swift_worker,
execution_requirements = execution_requirements,
Expand Down
13 changes: 3 additions & 10 deletions swift/internal/api.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ load("@bazel_skylib//lib:new_sets.bzl", "sets")
load("@bazel_skylib//lib:partial.bzl", "partial")
load("@bazel_skylib//lib:paths.bzl", "paths")
load("@bazel_skylib//lib:types.bzl", "types")
load(":actions.bzl", "get_swift_tool", "run_swift_action")
load(":actions.bzl", "run_swift_action")
load(":attrs.bzl", "swift_common_rule_attrs")
load(
":compiling.bzl",
Expand Down Expand Up @@ -600,14 +600,6 @@ def _compile(
swiftdoc = derived_files.swiftdoc(actions, module_name = module_name)
additional_outputs = []

# Since all actions go through the worker (whether in persistent mode or
# not), the actual tool we want to run (swiftc) should be the first
# "argument".
tool_args = actions.args()
tool_args.add(
get_swift_tool(swift_toolchain = swift_toolchain, tool = "swiftc"),
)

args = actions.args()
if _is_enabled(
feature_configuration = feature_configuration,
Expand Down Expand Up @@ -758,7 +750,8 @@ def _compile(

run_swift_action(
actions = actions,
arguments = [tool_args, args],
arguments = [args],
driver_mode = "swiftc",
execution_requirements = execution_requirements,
inputs = all_inputs,
mnemonic = "SwiftCompile",
Expand Down
7 changes: 2 additions & 5 deletions swift/internal/compiling.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

load("@bazel_skylib//lib:collections.bzl", "collections")
load("@bazel_skylib//lib:paths.bzl", "paths")
load(":actions.bzl", "get_swift_tool", "run_swift_action")
load(":actions.bzl", "run_swift_action")
load(":derived_files.bzl", "derived_files")
load(":providers.bzl", "SwiftInfo")
load(":utils.bzl", "collect_cc_libraries", "get_providers")
Expand Down Expand Up @@ -525,16 +525,13 @@ def register_autolink_extract_action(
toolchain: The `SwiftToolchainInfo` provider of the toolchain.
"""
args = actions.args()
args.add(get_swift_tool(
swift_toolchain = toolchain,
tool = "swift-autolink-extract",
))
args.add_all(objects)
args.add("-o", output)

run_swift_action(
actions = actions,
arguments = [args],
driver_mode = "swift-autolink-extract",
inputs = objects,
mnemonic = "SwiftAutolinkExtract",
outputs = [output],
Expand Down
4 changes: 2 additions & 2 deletions swift/internal/debugging.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

"""Functions relating to debugging support during compilation and linking."""

load(":actions.bzl", "get_swift_tool", "run_swift_action")
load(":actions.bzl", "run_swift_action")
load(":derived_files.bzl", "derived_files")

def ensure_swiftmodule_is_embedded(
Expand Down Expand Up @@ -97,7 +97,6 @@ def _register_modulewrap_action(
toolchain: The `SwiftToolchainInfo` provider of the toolchain.
"""
args = actions.args()
args.add(get_swift_tool(swift_toolchain = toolchain, tool = "swift"))
args.add("-modulewrap")
args.add(swiftmodule)

Expand All @@ -110,6 +109,7 @@ def _register_modulewrap_action(
run_swift_action(
actions = actions,
arguments = [args],
driver_mode = "swift",
inputs = [swiftmodule],
mnemonic = "SwiftModuleWrap",
outputs = [object],
Expand Down
11 changes: 8 additions & 3 deletions swift/internal/providers.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,6 @@ using this toolchain.
"cc_toolchain_info": """\
The `cc_common.CcToolchainInfo` provider from the Bazel C++ toolchain that this
Swift toolchain depends on.
""",
"clang_executable": """\
`String`. The path to the `clang` executable, which is used to link binaries.
""",
"command_line_copts": """\
`List` of `strings`. Flags that were passed to Bazel using the `--swiftcopt`
Expand Down Expand Up @@ -204,6 +201,14 @@ linked into the binary.
compiling libraries or binaries with this toolchain. These flags will come first
in compilation command lines, allowing them to be overridden by `copts`
attributes and `--swiftcopt` flags.
""",
"swift_executable": """\
A replacement Swift driver executable.
If this is `None`, the default Swift driver in the toolchain will be used.
Otherwise, this binary will be used and `--driver-mode` will be passed to ensure
that it is invoked in the correct mode (i.e., `swift`, `swiftc`,
`swift-autolink-extract`, etc.).
""",
"swift_worker": """\
`File`. The executable representing the worker executable used to invoke the
Expand Down
3 changes: 0 additions & 3 deletions swift/internal/swift_autoconfiguration.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,6 @@ def _create_linux_toolchain(repository_ctx):
"in your environment before invoking Bazel.")

path_to_swiftc = repository_ctx.which("swiftc")
path_to_clang = repository_ctx.which("clang")
root = path_to_swiftc.dirname.dirname
feature_values = _compute_feature_values(repository_ctx, path_to_swiftc)

Expand All @@ -197,7 +196,6 @@ package(default_visibility = ["//visibility:public"])
swift_toolchain(
name = "toolchain",
arch = "x86_64",
clang_executable = "{path_to_clang}",
features = [{feature_list}],
os = "linux",
root = "{root}",
Expand All @@ -207,7 +205,6 @@ swift_toolchain(
'"{}"'.format(feature)
for feature in feature_values
]),
path_to_clang = path_to_clang,
root = root,
),
)
Expand Down
28 changes: 20 additions & 8 deletions swift/internal/swift_toolchain.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,11 @@ def _swift_toolchain_impl(ctx):
requested_features.extend(ctx.features)
requested_features.append(SWIFT_FEATURE_AUTOLINK_EXTRACT)

all_files = []
swift_executable = ctx.file.swift_executable
if swift_executable:
all_files.append(swift_executable)

# TODO(allevato): Move some of the remaining hardcoded values, like object
# format and Obj-C interop support, to attributes so that we can remove the
# assumptions that are only valid on Linux.
Expand All @@ -114,9 +119,8 @@ def _swift_toolchain_impl(ctx):
action_environment = {},
# Swift.org toolchains assume everything is just available on the
# PATH and we don't try to pass the toolchain contents here.
all_files = depset(),
all_files = depset(all_files),
cc_toolchain_info = cc_toolchain,
clang_executable = ctx.attr.clang_executable,
command_line_copts = ctx.fragments.swift.copts(),
cpu = ctx.attr.arch,
execution_requirements = {},
Expand All @@ -129,6 +133,7 @@ def _swift_toolchain_impl(ctx):
stamp_producer = None,
supports_objc_interop = False,
swiftc_copts = [],
swift_executable = swift_executable,
swift_worker = ctx.executable._worker,
system_name = ctx.attr.os,
unsupported_features = ctx.disabled_features + [
Expand All @@ -145,12 +150,6 @@ The name of the architecture that this toolchain targets.
This name should match the name used in the toolchain's directory layout for
architecture-specific content, such as "x86_64" in "lib/swift/linux/x86_64".
""",
mandatory = True,
),
"clang_executable": attr.string(
doc = """\
The path to the `clang` executable, which is used for linking.
""",
mandatory = True,
),
Expand All @@ -166,6 +165,19 @@ platform-specific content, such as "linux" in "lib/swift/linux".
"root": attr.string(
mandatory = True,
),
"swift_executable": attr.label(
# TODO(allevato): Use a label-typed build setting to allow this to
# have a default that is overridden from the command line.
allow_single_file = True,
doc = """\
A replacement Swift driver executable.
If this is empty, the default Swift driver in the toolchain will be used.
Otherwise, this binary will be used and `--driver-mode` will be passed to ensure
that it is invoked in the correct mode (i.e., `swift`, `swiftc`,
`swift-autolink-extract`, etc.).
""",
),
"_cc_toolchain": attr.label(
default = Label("@bazel_tools//tools/cpp:current_cc_toolchain"),
doc = """\
Expand Down
Loading

0 comments on commit f51e689

Please sign in to comment.