Skip to content

Commit 5bee639

Browse files
authored
bazel: apply Xcode transition to swift_library only, drop Rust wrappers
1 parent a7dcd56 commit 5bee639

2 files changed

Lines changed: 57 additions & 89 deletions

File tree

‎unified/swift-syntax-rs/BUILD.bazel‎

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
load("@rules_rust//rust:defs.bzl", "rust_library")
2-
load("@rules_swift//swift:swift.bzl", "swift_library")
3-
load(":xcode_transition.bzl", "xcode_transition_rust_binary", "xcode_transition_rust_test")
1+
load("@rules_rust//rust:defs.bzl", "rust_binary", "rust_library", "rust_test")
2+
load(":xcode_transition.bzl", "xcode_transition_swift_library")
43

54
package(default_visibility = ["//visibility:public"])
65

@@ -20,16 +19,17 @@ _SWIFT_SUPPORTED_PLATFORMS = select({
2019
# Swift FFI shim: wraps swift-syntax and exposes a small C ABI. The Rust
2120
# targets below link against its `CcInfo`.
2221
#
23-
# Tagged `manual` so it is only built through the `xcode_transition_*`
24-
# wrappers below (which apply the Xcode-config transition on macOS).
25-
# Building it directly on macOS via `bazel build //...` would try to
26-
# analyze `xcode_swift_toolchain` under Bazel's default CC toolchain and
27-
# fail; going via a wrapper avoids that.
28-
swift_library(
22+
# On macOS, `rules_swift` auto-registers `xcode_swift_toolchain`, whose
23+
# analysis fails against Bazel's default `local_config_cc`. To avoid
24+
# forcing every macOS target in the repo onto the Apple CC toolchain, the
25+
# Xcode-config flags are applied only along the incoming edge into this
26+
# `swift_library` via `xcode_transition_swift_library` (see
27+
# `xcode_transition.bzl`). Downstream Rust targets stay in the default
28+
# configuration.
29+
xcode_transition_swift_library(
2930
name = "swift_syntax_ffi",
3031
srcs = ["swift/Sources/SwiftSyntaxFFI/SwiftSyntaxFFI.swift"],
3132
module_name = "SwiftSyntaxFFI",
32-
tags = ["manual"],
3333
target_compatible_with = _SWIFT_SUPPORTED_PLATFORMS,
3434
deps = [
3535
"@swift-syntax//:SwiftParser",
@@ -46,14 +46,13 @@ rust_library(
4646
exclude = ["src/main.rs"],
4747
),
4848
edition = "2024",
49-
tags = ["manual"],
5049
target_compatible_with = _SWIFT_SUPPORTED_PLATFORMS,
5150
deps = [
5251
":swift_syntax_ffi",
5352
],
5453
)
5554

56-
xcode_transition_rust_binary(
55+
rust_binary(
5756
name = "swift-syntax-parse",
5857
srcs = ["src/main.rs"],
5958
# `rust_binary` doesn't copy the Swift runtime into runfiles the way
@@ -69,7 +68,7 @@ xcode_transition_rust_binary(
6968
deps = [":swift_syntax_rs"],
7069
)
7170

72-
xcode_transition_rust_test(
71+
rust_test(
7372
name = "swift_syntax_rs_test",
7473
size = "small",
7574
crate = ":swift_syntax_rs",
Lines changed: 45 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,35 @@
1-
"""Per-target Xcode configuration for `//unified/swift-syntax-rs` on macOS.
1+
"""Per-target Xcode configuration for the `swift_library` under
2+
`//unified/swift-syntax-rs` on macOS.
23
34
On macOS, `rules_swift` auto-registers `xcode_swift_toolchain`, whose
45
analysis reads `cc_toolchain.target_gnu_system_name` and fails on Bazel's
5-
built-in `local_config_cc` (triple is literally "local"). Working around
6-
this needs two flags:
6+
built-in `local_config_cc` (whose triple is literally "local"). Working
7+
around this needs two flags:
78
89
- `--xcode_version_config=@local_config_xcode//:host_xcodes` — selects
910
`apple_support`'s xcode_config, whose version strings match the ones
1011
`rules_swift`'s `system_sdk` selects are keyed on.
1112
- `--extra_toolchains=@local_config_apple_cc_toolchains//:all` — forces
1213
`apple_support`'s CC toolchain ahead of `local_config_cc`.
1314
14-
We apply them via an incoming-edge Starlark transition on the public
15-
`//unified/swift-syntax-rs` binary/test wrappers rather than globally in
16-
`.bazelrc`. That keeps every other target on macOS on Bazel's default CC
17-
toolchain (`local_config_cc`) and avoids materializing the
18-
`@local_config_xcode` / `@local_config_apple_cc_toolchains` repos unless
19-
something under `//unified/swift-syntax-rs` is actually being built.
15+
We apply them via an incoming-edge Starlark transition on the
16+
`swift_library` target itself (through the `xcode_transition_swift_library`
17+
macro below), rather than globally in `.bazelrc`. That keeps every other
18+
target on macOS on Bazel's default CC toolchain (`local_config_cc`) and
19+
avoids materializing the `@local_config_xcode` /
20+
`@local_config_apple_cc_toolchains` repos unless something under
21+
`//unified/swift-syntax-rs` is actually being built.
22+
23+
The transition is placed on `swift_library` — not on the downstream Rust
24+
targets — so the Apple CC toolchain is only used for analyzing the Swift
25+
side. The Rust compilation and any other transitive C/C++ deps stay on
26+
Bazel's default CC toolchain, matching how they build elsewhere in the
27+
repository.
2028
2129
The transition is a no-op on non-macOS platforms.
2230
"""
2331

24-
load("@rules_rust//rust:defs.bzl", "rust_binary", "rust_test")
32+
load("@rules_swift//swift:swift.bzl", "swift_library")
2533
load("//misc/bazel:os.bzl", "os_select")
2634

2735
_XCODE_VERSION_CONFIG = "//command_line_option:xcode_version_config"
@@ -50,97 +58,58 @@ _xcode_transition = transition(
5058
)
5159

5260
def _wrapper_impl(ctx):
53-
# `ctx.attr.actual` is a list because of the incoming transition.
5461
src = ctx.attr.actual[0]
55-
src_default = src[DefaultInfo]
56-
src_exe = src_default.files_to_run.executable
57-
src_runfiles = src_default.default_runfiles
58-
59-
# Copy (not symlink) the executable so that runfiles lookups via
60-
# `argv[0]` resolve under this wrapper's runfiles tree. This mirrors
61-
# the pattern used by `//swift:rules.bzl` `_cc_transition_impl`.
62-
out = ctx.actions.declare_file(ctx.label.name)
63-
ctx.actions.run_shell(
64-
inputs = [src_exe],
65-
outputs = [out],
66-
command = "cp {src} {dst}".format(src = src_exe.path, dst = out.path),
67-
)
68-
69-
# Rewrite runfiles so the wrapped executable is replaced by the copy.
70-
files = src_runfiles.files.to_list()
71-
if src_exe in files:
72-
files.remove(src_exe)
73-
files.append(out)
74-
runfiles = ctx.runfiles(files = files)
75-
76-
return [DefaultInfo(
77-
executable = out,
78-
files = depset([out]),
79-
runfiles = runfiles,
80-
)]
81-
82-
_xcode_transition_binary_rule = rule(
83-
implementation = _wrapper_impl,
84-
attrs = {
85-
"actual": attr.label(
86-
mandatory = True,
87-
cfg = _xcode_transition,
88-
executable = True,
89-
),
90-
"os": attr.string(mandatory = True),
91-
"_allowlist_function_transition": attr.label(
92-
default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
93-
),
94-
},
95-
executable = True,
96-
)
97-
98-
_xcode_transition_test_rule = rule(
62+
providers = [
63+
# Only forward the providers a downstream `rust_*` target reads
64+
# from a `deps` entry. `CcInfo` carries the linking info; forward
65+
# `OutputGroupInfo` too for `bazel build --output_groups=...`.
66+
src[DefaultInfo],
67+
]
68+
for p in (CcInfo, OutputGroupInfo):
69+
if p in src:
70+
providers.append(src[p])
71+
return providers
72+
73+
_xcode_transition_swift_library_rule = rule(
9974
implementation = _wrapper_impl,
10075
attrs = {
10176
"actual": attr.label(
10277
mandatory = True,
10378
cfg = _xcode_transition,
104-
executable = True,
79+
providers = [CcInfo],
10580
),
10681
"os": attr.string(mandatory = True),
10782
"_allowlist_function_transition": attr.label(
10883
default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
10984
),
11085
},
111-
test = True,
11286
)
11387

114-
def _wrap(inner_rule, wrapper_rule, name, visibility = None, tags = None, target_compatible_with = None, **kwargs):
115-
"""Wrap a Rust target with the Xcode-config transition.
116-
117-
Splits `name` into a private inner target `_impl_<name>` (built with
118-
`inner_rule` and hidden from wildcards via `tags = ["manual"]`) and a
119-
public `name` (built with `wrapper_rule`, which applies the Xcode
120-
transition on macOS). The `_impl_` prefix — rather than an `_impl`
121-
suffix — preserves the caller's original suffix, which Bazel requires
122-
for test rules (target names must end in `_test`)."""
88+
def xcode_transition_swift_library(name, visibility = None, tags = None, target_compatible_with = None, **kwargs):
89+
"""`swift_library` wrapped in the macOS Xcode-config transition.
90+
91+
Splits `name` into a private inner target `_impl_<name>` (a plain
92+
`swift_library`, hidden from wildcards via `tags = ["manual"]`) and a
93+
public `name` that applies the incoming Xcode-config transition on
94+
macOS and forwards the inner target's `CcInfo` (and other relevant
95+
providers) to downstream consumers. Downstream `rust_*` targets can
96+
depend on `name` as an ordinary `deps` entry — they stay in the
97+
default configuration; only the `swift_library` sub-graph flips to
98+
the Apple CC toolchain, and only on macOS.
99+
"""
123100
inner_name = "_impl_%s" % name
124-
inner_rule(
101+
swift_library(
125102
name = inner_name,
126103
visibility = ["//visibility:private"],
127104
tags = (tags or []) + ["manual"],
128105
target_compatible_with = target_compatible_with,
129106
**kwargs
130107
)
131-
wrapper_rule(
108+
_xcode_transition_swift_library_rule(
132109
name = name,
133110
visibility = visibility,
134111
tags = tags,
135112
target_compatible_with = target_compatible_with,
136113
actual = ":" + inner_name,
137114
os = os_select(linux = "linux", macos = "macos", default = "other"),
138115
)
139-
140-
def xcode_transition_rust_binary(name, **kwargs):
141-
"""`rust_binary` wrapped in the macOS Xcode-config transition."""
142-
_wrap(rust_binary, _xcode_transition_binary_rule, name = name, **kwargs)
143-
144-
def xcode_transition_rust_test(name, **kwargs):
145-
"""`rust_test` wrapped in the macOS Xcode-config transition."""
146-
_wrap(rust_test, _xcode_transition_test_rule, name = name, **kwargs)

0 commit comments

Comments
 (0)