Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow the Swift driver to be overridden by a command line flag. #353

Merged
merged 1 commit into from
Nov 22, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions swift/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,17 @@ bool_setting(
name = "emit_swiftinterface",
build_setting_default = False,
)

# Allows a user to override the default Swift driver during a build, if the
# toolchain is using the default.
label_flag(
name = "default_swift_executable",
build_setting_default = ":empty",
)

# Empty filegroup used as the default value for `:default_swift_executable`
# since the `build_setting_default` value is required.
filegroup(
name = "empty",
visibility = ["//visibility:private"],
)
34 changes: 34 additions & 0 deletions swift/internal/attrs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,37 @@ Linux), those dependencies will be **ignored.**
],
**kwargs
)

def swift_toolchain_driver_attrs():
"""Returns attributes used to attach custom drivers to toolchains.
These attributes are useful for compiler development alongside Bazel. The
public attribute (`swift_executable`) lets a custom driver be permanently
associated with a particular toolchain instance. If not specified, the
private default is associated with a command-line option that can be used to
provide a custom driver at build time.
Returns:
A dictionary of attributes that should be added to a toolchain rule.
"""
return {
"swift_executable": attr.label(
allow_single_file = True,
cfg = "host",
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.).
""",
),
"_default_swift_executable": attr.label(
allow_files = True,
cfg = "host",
default = Label(
"@build_bazel_rules_swift//swift:default_swift_executable",
),
),
}
73 changes: 33 additions & 40 deletions swift/internal/swift_toolchain.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,15 @@ toolchain, see `swift.bzl`.
load("@bazel_skylib//lib:dicts.bzl", "dicts")
load("@bazel_skylib//lib:partial.bzl", "partial")
load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain")
load(":attrs.bzl", "swift_toolchain_driver_attrs")
load(
":features.bzl",
"SWIFT_FEATURE_AUTOLINK_EXTRACT",
"SWIFT_FEATURE_MODULE_MAP_HOME_IS_CWD",
"features_for_build_modes",
)
load(":providers.bzl", "SwiftToolchainInfo")
load(":utils.bzl", "get_swift_executable_for_toolchain")

def _default_linker_opts(
cc_toolchain,
Expand Down Expand Up @@ -106,8 +108,11 @@ def _swift_toolchain_impl(ctx):
requested_features.extend(ctx.features)
requested_features.append(SWIFT_FEATURE_AUTOLINK_EXTRACT)

# Swift.org toolchains assume everything is just available on the PATH so we
# we don't pass any files unless we have a custom driver executable in the
# workspace.
all_files = []
swift_executable = ctx.file.swift_executable
swift_executable = get_swift_executable_for_toolchain(ctx)
if swift_executable:
all_files.append(swift_executable)

Expand All @@ -117,8 +122,6 @@ def _swift_toolchain_impl(ctx):
return [
SwiftToolchainInfo(
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),
cc_toolchain_info = cc_toolchain,
command_line_copts = ctx.fragments.swift.copts(),
Expand All @@ -143,59 +146,49 @@ def _swift_toolchain_impl(ctx):
]

swift_toolchain = rule(
attrs = dicts.add({
"arch": attr.string(
doc = """\
attrs = dicts.add(
swift_toolchain_driver_attrs(),
{
"arch": attr.string(
doc = """\
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,
),
"os": attr.string(
doc = """\
mandatory = True,
),
"os": attr.string(
doc = """\
The name of the operating system that this toolchain targets.
This name should match the name used in the toolchain's directory layout for
platform-specific content, such as "linux" in "lib/swift/linux".
""",
mandatory = True,
),
"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 = """\
mandatory = True,
),
"root": attr.string(
mandatory = True,
),
"_cc_toolchain": attr.label(
default = Label("@bazel_tools//tools/cpp:current_cc_toolchain"),
doc = """\
The C++ toolchain from which other tools needed by the Swift toolchain (such as
`clang` and `ar`) will be retrieved.
""",
),
"_worker": attr.label(
cfg = "host",
allow_files = True,
default = Label("//tools/worker"),
doc = """\
),
"_worker": attr.label(
cfg = "host",
allow_files = True,
default = Label("//tools/worker"),
doc = """\
An executable that wraps Swift compiler invocations and also provides support
for incremental compilation using a persistent mode.
""",
executable = True,
),
}),
executable = True,
),
},
),
doc = "Represents a Swift compiler toolchain.",
fragments = ["swift"],
toolchains = ["@bazel_tools//tools/cpp:toolchain_type"],
Expand Down
38 changes: 38 additions & 0 deletions swift/internal/utils.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,44 @@ def expand_locations(ctx, values, targets = []):
"""
return [ctx.expand_location(value, targets) for value in values]

def get_swift_executable_for_toolchain(ctx):
"""Returns the Swift driver executable that the toolchain should use.
Args:
ctx: The toolchain's rule context.
Returns:
A `File` representing a custom Swift driver executable that the
toolchain should use if provided by the toolchain target or by a command
line option, or `None` if the default driver bundled with the toolchain
should be used.
"""

# If the toolchain target itself specifies a custom driver, use that.
swift_executable = getattr(ctx.file, "swift_executable", None)

# If no custom driver was provided by the target, check the value of the
# command-line option and use that if it was provided.
if not swift_executable:
default_swift_executable_files = getattr(
ctx.files,
"_default_swift_executable",
None,
)

if default_swift_executable_files:
if len(default_swift_executable_files) > 1:
fail(
"The 'default_swift_executable' option must point to a " +
"single file, but we found {}".format(
str(default_swift_executable_files),
),
)

swift_executable = default_swift_executable_files[0]

return swift_executable

def get_output_groups(targets, group_name):
"""Returns files in an output group from each target in a list.
Expand Down
59 changes: 26 additions & 33 deletions swift/internal/xcode_swift_toolchain.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ load("@bazel_skylib//lib:dicts.bzl", "dicts")
load("@bazel_skylib//lib:partial.bzl", "partial")
load("@bazel_skylib//lib:paths.bzl", "paths")
load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain")
load(":attrs.bzl", "swift_toolchain_driver_attrs")
load(
":features.bzl",
"SWIFT_FEATURE_AUTOLINK_EXTRACT",
Expand All @@ -37,6 +38,7 @@ load(
"features_for_build_modes",
)
load(":providers.bzl", "SwiftToolchainInfo")
load(":utils.bzl", "get_swift_executable_for_toolchain")

def _swift_developer_lib_dir(platform_framework_dir):
"""Returns the directory containing extra Swift developer libraries.
Expand Down Expand Up @@ -351,7 +353,8 @@ def _xcode_swift_toolchain_impl(ctx):
#
# To use a "standard" custom toolchain built using the full Swift build
# script, use `--define=SWIFT_CUSTOM_TOOLCHAIN=<id>` as shown below.
swift_executable = ctx.file.swift_executable
swift_executable = get_swift_executable_for_toolchain(ctx)

toolchain_root = ctx.var.get("SWIFT_USE_TOOLCHAIN_ROOT")
custom_toolchain = ctx.var.get("SWIFT_CUSTOM_TOOLCHAIN")

Expand Down Expand Up @@ -440,46 +443,36 @@ def _xcode_swift_toolchain_impl(ctx):
]

xcode_swift_toolchain = rule(
attrs = dicts.add({
"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 = """\
attrs = dicts.add(
swift_toolchain_driver_attrs(),
{
"_cc_toolchain": attr.label(
default = Label("@bazel_tools//tools/cpp:current_cc_toolchain"),
doc = """\
The C++ toolchain from which linking flags and other tools needed by the Swift
toolchain (such as `clang`) will be retrieved.
""",
),
"_worker": attr.label(
cfg = "host",
allow_files = True,
default = Label(
"@build_bazel_rules_swift//tools/worker",
),
doc = """\
"_worker": attr.label(
cfg = "host",
allow_files = True,
default = Label(
"@build_bazel_rules_swift//tools/worker",
),
doc = """\
An executable that wraps Swift compiler invocations and also provides support
for incremental compilation using a persistent mode.
""",
executable = True,
),
"_xcode_config": attr.label(
default = configuration_field(
name = "xcode_config_label",
fragment = "apple",
executable = True,
),
),
}),
"_xcode_config": attr.label(
default = configuration_field(
name = "xcode_config_label",
fragment = "apple",
),
),
},
),
doc = "Represents a Swift compiler toolchain provided by Xcode.",
fragments = [
"apple",
Expand Down