Skip to content

Commit 2d7f945

Browse files
Fix rust-analyzer being unable to find rust sysroot sources. (#1483)
* Fix rust-analyzer being unable to find rust sysroot sources. * Update tools/rust_analyzer/main.rs Co-authored-by: Daniel Wagner-Hall <[email protected]> Co-authored-by: Daniel Wagner-Hall <[email protected]>
1 parent 81a77ac commit 2d7f945

File tree

4 files changed

+35
-20
lines changed

4 files changed

+35
-20
lines changed

rust/private/rust_analyzer.bzl

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,8 @@ rust_analyzer_aspect = aspect(
122122
doc = "Annotates rust rules with RustAnalyzerInfo later used to build a rust-project.json",
123123
)
124124

125-
_exec_root_tmpl = "__EXEC_ROOT__/"
125+
_EXEC_ROOT_TEMPLATE = "__EXEC_ROOT__/"
126+
_OUTPUT_BASE_TEMPLATE = "__OUTPUT_BASE__/"
126127

127128
def _crate_id(crate_info):
128129
"""Returns a unique stable identifier for a crate
@@ -155,18 +156,18 @@ def _create_single_crate(ctx, info):
155156
# TODO: Some folks may want to override this for vendored dependencies.
156157
is_external = info.crate.root.path.startswith("external/")
157158
is_generated = not info.crate.root.is_source
158-
path_prefix = _exec_root_tmpl if is_external or is_generated else ""
159+
path_prefix = _EXEC_ROOT_TEMPLATE if is_external or is_generated else ""
159160
crate["is_workspace_member"] = not is_external
160161
crate["root_module"] = path_prefix + info.crate.root.path
161162
crate_root = path_prefix + info.crate.root.dirname
162163

163164
if info.build_info != None:
164165
out_dir_path = info.build_info.out_dir.path
165-
crate["env"].update({"OUT_DIR": _exec_root_tmpl + out_dir_path})
166+
crate["env"].update({"OUT_DIR": _EXEC_ROOT_TEMPLATE + out_dir_path})
166167
crate["source"] = {
167168
# We have to tell rust-analyzer about our out_dir since it's not under the crate root.
168169
"exclude_dirs": [],
169-
"include_dirs": [crate_root, _exec_root_tmpl + out_dir_path],
170+
"include_dirs": [crate_root, _EXEC_ROOT_TEMPLATE + out_dir_path],
170171
}
171172

172173
# TODO: The only imagined use case is an env var holding a filename in the workspace passed to a
@@ -188,7 +189,7 @@ def _create_single_crate(ctx, info):
188189
crate["cfg"] = info.cfgs
189190
crate["target"] = find_toolchain(ctx).target_triple
190191
if info.proc_macro_dylib_path != None:
191-
crate["proc_macro_dylib_path"] = _exec_root_tmpl + info.proc_macro_dylib_path
192+
crate["proc_macro_dylib_path"] = _EXEC_ROOT_TEMPLATE + info.proc_macro_dylib_path
192193
return crate
193194

194195
def _rust_analyzer_toolchain_impl(ctx):
@@ -223,7 +224,7 @@ def _rust_analyzer_detect_sysroot_impl(ctx):
223224

224225
sysroot_src = rustc_srcs.label.package + "/library"
225226
if rustc_srcs.label.workspace_root:
226-
sysroot_src = _exec_root_tmpl + rustc_srcs.label.workspace_root + "/" + sysroot_src
227+
sysroot_src = _OUTPUT_BASE_TEMPLATE + rustc_srcs.label.workspace_root + "/" + sysroot_src
227228

228229
sysroot_src_file = ctx.actions.declare_file(ctx.label.name + ".rust_analyzer_sysroot_src")
229230
ctx.actions.write(

tools/rust_analyzer/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ pub fn write_rust_project(
4545
rules_rust_name: &impl AsRef<str>,
4646
targets: &[String],
4747
execution_root: impl AsRef<Path>,
48+
output_base: impl AsRef<Path>,
4849
rust_project_path: impl AsRef<Path>,
4950
) -> anyhow::Result<()> {
5051
let crate_specs = aquery::get_crate_specs(
@@ -72,6 +73,7 @@ pub fn write_rust_project(
7273
rust_project::write_rust_project(
7374
rust_project_path.as_ref(),
7475
execution_root.as_ref(),
76+
output_base.as_ref(),
7577
&rust_project,
7678
)?;
7779

tools/rust_analyzer/main.rs

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ fn main() -> anyhow::Result<()> {
2626
.as_ref()
2727
.expect("failed to find execution root, is --execution-root set correctly?");
2828

29+
let output_base = config
30+
.output_base
31+
.as_ref()
32+
.expect("failed to find output base, is -output-base set correctly?");
33+
2934
let rules_rust_name = env!("ASPECT_REPOSITORY");
3035

3136
// Generate the crate specs.
@@ -43,6 +48,7 @@ fn main() -> anyhow::Result<()> {
4348
&rules_rust_name,
4449
&config.targets,
4550
&execution_root,
51+
&output_base,
4652
&workspace_root.join("rust-project.json"),
4753
)?;
4854

@@ -53,14 +59,6 @@ fn main() -> anyhow::Result<()> {
5359
fn parse_config() -> anyhow::Result<Config> {
5460
let mut config = Config::parse();
5561

56-
// Ensure we know the workspace. If we are under `bazel run`, the
57-
// BUILD_WORKSPACE_DIR environment variable will be present.
58-
if config.workspace.is_none() {
59-
if let Some(ws_dir) = env::var_os("BUILD_WORKSPACE_DIRECTORY") {
60-
config.workspace = Some(PathBuf::from(ws_dir));
61-
}
62-
}
63-
6462
if config.workspace.is_some() && config.execution_root.is_some() {
6563
return Ok(config);
6664
}
@@ -97,24 +95,32 @@ fn parse_config() -> anyhow::Result<Config> {
9795
if config.execution_root.is_none() {
9896
config.execution_root = bazel_info.get("execution_root").map(Into::into);
9997
}
98+
if config.output_base.is_none() {
99+
config.output_base = bazel_info.get("output_base").map(Into::into);
100+
}
100101

101102
Ok(config)
102103
}
103104

104105
#[derive(Debug, Parser)]
105106
struct Config {
106-
// If not specified, uses the result of `bazel info workspace`.
107-
#[clap(long)]
107+
/// The path to the Bazel workspace directory. If not specified, uses the result of `bazel info workspace`.
108+
#[clap(long, env = "BUILD_WORKSPACE_DIRECTORY")]
108109
workspace: Option<PathBuf>,
109110

110-
// If not specified, uses the result of `bazel info execution_root`.
111+
/// The path to the Bazel execution root. If not specified, uses the result of `bazel info execution_root`.
111112
#[clap(long)]
112113
execution_root: Option<PathBuf>,
113114

115+
/// The path to the Bazel output user root. If not specified, uses the result of `bazel info output_base`.
116+
#[clap(long, env = "OUTPUT_BASE")]
117+
output_base: Option<PathBuf>,
118+
119+
/// The path to a Bazel binary
114120
#[clap(long, default_value = "bazel")]
115121
bazel: PathBuf,
116122

117-
// Space separated list of target patterns that comes after all other args.
123+
/// Space separated list of target patterns that comes after all other args.
118124
#[clap(default_value = "@//...")]
119125
targets: Vec<String>,
120126
}

tools/rust_analyzer/rust_project.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,12 +177,17 @@ pub fn generate_rust_project(
177177
pub fn write_rust_project(
178178
rust_project_path: &Path,
179179
execution_root: &Path,
180+
output_base: &Path,
180181
rust_project: &RustProject,
181182
) -> anyhow::Result<()> {
182183
let execution_root = execution_root
183184
.to_str()
184185
.ok_or_else(|| anyhow!("execution_root is not valid UTF-8"))?;
185186

187+
let output_base = output_base
188+
.to_str()
189+
.ok_or_else(|| anyhow!("output_base is not valid UTF-8"))?;
190+
186191
// Try to remove the existing rust-project.json. It's OK if the file doesn't exist.
187192
match std::fs::remove_file(rust_project_path) {
188193
Ok(_) => {}
@@ -197,8 +202,9 @@ pub fn write_rust_project(
197202

198203
// Render the `rust-project.json` file and replace the exec root
199204
// placeholders with the path to the local exec root.
200-
let rust_project_content =
201-
serde_json::to_string(rust_project)?.replace("__EXEC_ROOT__", execution_root);
205+
let rust_project_content = serde_json::to_string(rust_project)?
206+
.replace("__EXEC_ROOT__", execution_root)
207+
.replace("__OUTPUT_BASE__", output_base);
202208

203209
// Write the new rust-project.json file.
204210
std::fs::write(rust_project_path, rust_project_content)?;

0 commit comments

Comments
 (0)