Skip to content

Commit

Permalink
add rust_analyzer_proc_macro_dylibs and rust_analyzer_build_info_out_…
Browse files Browse the repository at this point in the history
…dirs output groups
  • Loading branch information
bobozaur committed Dec 13, 2024
1 parent 4d0b0dd commit 267aa69
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 13 deletions.
6 changes: 5 additions & 1 deletion extensions/prost/private/prost.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,9 @@ def _rust_prost_aspect_impl(target, ctx):
env = dep_variant_info.crate_info.rustc_env,
deps = depset([dep.id for dep in rust_analyzer_deps]).to_list(),
crate_specs = depset(transitive = [dep.crate_specs for dep in rust_analyzer_deps]),
proc_macro_dylib_path = None,
proc_macro_dylibs = depset(transitive = [dep.proc_macro_dylibs for dep in rust_analyzer_deps]),
build_info_out_dirs = depset(transitive = [dep.build_info_out_dirs for dep in rust_analyzer_deps]),
proc_macro_dylib = None,
build_info = dep_variant_info.build_info,
))

Expand Down Expand Up @@ -337,6 +339,8 @@ def _rust_prost_library_impl(ctx):
),
RustAnalyzerGroupInfo(
crate_specs = proto_dep[RustAnalyzerInfo].crate_specs,
proc_macro_dylibs = proto_dep[RustAnalyzerInfo].proc_macro_dylibs,
build_script_out_dirs = proto_dep[RustAnalyzerInfo].build_script_out_dirs,
deps = proto_dep[RustAnalyzerInfo].deps,
),
]
Expand Down
6 changes: 5 additions & 1 deletion rust/private/providers.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -162,17 +162,21 @@ RustAnalyzerInfo = provider(
"cfgs": "List[String]: features or other compilation `--cfg` settings",
"crate": "CrateInfo: Crate information.",
"crate_specs": "Depset[File]: transitive closure of OutputGroupInfo files",
"proc_macro_dylibs": "Depset[File]: transitive closure of OutputGroupInfo files",
"build_info_out_dirs": "Depset[File]: transitive closure of OutputGroupInfo files",
"deps": "List[String]: IDs of direct dependency crates",
"env": "Dict[String: String]: Environment variables, used for the `env!` macro",
"id": "String: Arbitrary unique ID for this crate",
"proc_macro_dylib_path": "File: compiled shared library output of proc-macro rule",
"proc_macro_dylib": "File: compiled shared library output of proc-macro rule",
},
)

RustAnalyzerGroupInfo = provider(
doc = "RustAnalyzerGroupInfo holds multiple RustAnalyzerInfos",
fields = {
"crate_specs": "Depset[File]: transitive closure of OutputGroupInfo files",
"proc_macro_dylibs": "Depset[File]: transitive closure of OutputGroupInfo files",
"build_info_out_dirs": "Depset[File]: transitive closure of OutputGroupInfo files",
"deps": "List[String]: crate IDs of direct dependencies",
},
)
45 changes: 35 additions & 10 deletions rust/private/rust_analyzer.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ def write_rust_analyzer_spec_file(ctx, attrs, owner, base_info):
RustAnalyzerInfo: Info with the embedded spec file.
"""
crate_spec = ctx.actions.declare_file("{}.rust_analyzer_crate_spec.json".format(owner.name))
proc_macro_dylibs = [base_info.proc_macro_dylib] if base_info.proc_macro_dylib else None
build_info_out_dirs = [base_info.build_info.out_dir] if base_info.build_info != None and base_info.build_info.out_dir != None else None

# Recreate the provider with the spec file embedded in it.
rust_analyzer_info = RustAnalyzerInfo(
Expand All @@ -55,7 +57,9 @@ def write_rust_analyzer_spec_file(ctx, attrs, owner, base_info):
deps = base_info.deps,
id = base_info.id,
crate_specs = depset(direct = [crate_spec], transitive = [base_info.crate_specs]),
proc_macro_dylib_path = base_info.proc_macro_dylib_path,
proc_macro_dylibs = depset(direct = proc_macro_dylibs, transitive = [base_info.proc_macro_dylibs]),
build_info_out_dirs = depset(direct = build_info_out_dirs, transitive = [base_info.build_info_out_dirs]),
proc_macro_dylib = base_info.proc_macro_dylib,
build_info = base_info.build_info,
)

Expand Down Expand Up @@ -101,23 +105,36 @@ def _rust_analyzer_aspect_impl(target, ctx):
# Gather required info from dependencies.
label_to_id = {} # {Label of dependency => crate_id}
crate_specs = [] # [depset of File - transitive crate_spec.json files]
proc_macro_dylibs = [] # [depset of File - transitive crate_spec.json files]
build_script_out_dirs = [] # [depset of File - transitive crate_spec.json files]
attrs = ctx.rule.attr
all_deps = getattr(attrs, "deps", []) + getattr(attrs, "proc_macro_deps", []) + \
[dep for dep in [getattr(attrs, "crate", None), getattr(attrs, "actual", None)] if dep != None]
for dep in all_deps:
if RustAnalyzerInfo in dep:
label_to_id[dep.label] = dep[RustAnalyzerInfo].id
crate_specs.append(dep[RustAnalyzerInfo].crate_specs)
proc_macro_dylibs.append(dep[RustAnalyzerInfo].proc_macro_dylibs)
build_script_out_dirs.append(dep[RustAnalyzerInfo].build_info_out_dirs)
if RustAnalyzerGroupInfo in dep:
for expanded_dep in dep[RustAnalyzerGroupInfo].deps:
label_to_id[expanded_dep] = expanded_dep
crate_specs.append(dep[RustAnalyzerGroupInfo].crate_specs)
proc_macro_dylibs.append(dep[RustAnalyzerGroupInfo].proc_macro_dylibs)
build_script_out_dirs.append(dep[RustAnalyzerGroupInfo].build_info_out_dirs)

deps = label_to_id.values()
crate_specs = depset(transitive = crate_specs)
proc_macro_dylibs = depset(transitive = proc_macro_dylibs)
build_script_out_dirs = depset(transitive = build_script_out_dirs)

if rust_common.crate_group_info in target:
return [RustAnalyzerGroupInfo(deps = deps, crate_specs = crate_specs)]
return [RustAnalyzerGroupInfo(
deps = deps,
crate_specs = crate_specs,
proc_macro_dylibs = proc_macro_dylibs,
build_info_out_dirs = build_script_out_dirs,
)]
elif rust_common.crate_info in target:
crate_info = target[rust_common.crate_info]
elif rust_common.test_crate_info in target:
Expand All @@ -134,6 +151,8 @@ def _rust_analyzer_aspect_impl(target, ctx):
# An arbitrary unique and stable identifier.
crate_id = "ID-" + crate_info.root.path

proc_macro_dylib = find_proc_macro_dylib(toolchain, target)

rust_analyzer_info = write_rust_analyzer_spec_file(ctx, ctx.rule.attr, ctx.label, RustAnalyzerInfo(
id = crate_id,
aliases = aliases,
Expand All @@ -142,23 +161,29 @@ def _rust_analyzer_aspect_impl(target, ctx):
env = crate_info.rustc_env,
deps = deps,
crate_specs = crate_specs,
proc_macro_dylib_path = find_proc_macro_dylib_path(toolchain, target),
proc_macro_dylibs = proc_macro_dylibs,
build_info_out_dirs = build_script_out_dirs,
proc_macro_dylib = proc_macro_dylib,
build_info = build_info,
))

return [
rust_analyzer_info,
OutputGroupInfo(rust_analyzer_crate_spec = rust_analyzer_info.crate_specs),
OutputGroupInfo(
rust_analyzer_crate_spec = rust_analyzer_info.crate_specs,
rust_analyzer_proc_macro_dylibs = rust_analyzer_info.proc_macro_dylibs,
rust_analyzer_build_info_out_dirs = rust_analyzer_info.build_info_out_dirs,
),
]

def find_proc_macro_dylib_path(toolchain, target):
"""Find the proc_macro_dylib_path of target. Returns None if target crate is not type proc-macro.
def find_proc_macro_dylib(toolchain, target):
"""Find the proc_macro_dylib of target. Returns None if target crate is not type proc-macro.
Args:
toolchain: The current rust toolchain.
target: The current target.
Returns:
(path): The path to the proc macro dylib, or None if this crate is not a proc-macro.
(File): The path to the proc macro dylib, or None if this crate is not a proc-macro.
"""
if rust_common.crate_info in target:
crate_info = target[rust_common.crate_info]
Expand All @@ -174,7 +199,7 @@ def find_proc_macro_dylib_path(toolchain, target):
for action in target.actions:
for output in action.outputs.to_list():
if output.extension == dylib_ext[1:]:
return output.path
return output

# Failed to find the dylib path inside a proc-macro crate.
# TODO: Should this be an error?
Expand Down Expand Up @@ -266,8 +291,8 @@ def _create_single_crate(ctx, attrs, info):
crate["cfg"] = info.cfgs
toolchain = find_toolchain(ctx)
crate["target"] = (_EXEC_ROOT_TEMPLATE + toolchain.target_json.path) if toolchain.target_json else toolchain.target_flag_value
if info.proc_macro_dylib_path != None:
crate["proc_macro_dylib_path"] = _EXEC_ROOT_TEMPLATE + info.proc_macro_dylib_path
if info.proc_macro_dylib != None:
crate["proc_macro_dylib_path"] = _EXEC_ROOT_TEMPLATE + info.proc_macro_dylib.path
return crate

def _rust_analyzer_toolchain_impl(ctx):
Expand Down
2 changes: 1 addition & 1 deletion tools/rust_analyzer/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ pub fn generate_crate_info(
.arg(format!(
"--aspects={rules_rust}//rust:defs.bzl%rust_analyzer_aspect"
))
.arg("--output_groups=rust_analyzer_crate_spec,rust_generated_srcs")
.arg("--output_groups=rust_analyzer_crate_spec,rust_generated_srcs,rust_analyzer_proc_macro_dylibs,rust_analyzer_build_info_out_dirs")
.args(targets)
.output()?;

Expand Down

0 comments on commit 267aa69

Please sign in to comment.