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 <dawagner@gmail.com>
Co-authored-by: Daniel Wagner-Hall <dawagner@gmail.com>
diff --git a/rust/private/rust_analyzer.bzl b/rust/private/rust_analyzer.bzl
index a73e3aa..8408197 100644
--- a/rust/private/rust_analyzer.bzl
+++ b/rust/private/rust_analyzer.bzl
@@ -122,7 +122,8 @@
doc = "Annotates rust rules with RustAnalyzerInfo later used to build a rust-project.json",
)
-_exec_root_tmpl = "__EXEC_ROOT__/"
+_EXEC_ROOT_TEMPLATE = "__EXEC_ROOT__/"
+_OUTPUT_BASE_TEMPLATE = "__OUTPUT_BASE__/"
def _crate_id(crate_info):
"""Returns a unique stable identifier for a crate
@@ -155,18 +156,18 @@
# TODO: Some folks may want to override this for vendored dependencies.
is_external = info.crate.root.path.startswith("external/")
is_generated = not info.crate.root.is_source
- path_prefix = _exec_root_tmpl if is_external or is_generated else ""
+ path_prefix = _EXEC_ROOT_TEMPLATE if is_external or is_generated else ""
crate["is_workspace_member"] = not is_external
crate["root_module"] = path_prefix + info.crate.root.path
crate_root = path_prefix + info.crate.root.dirname
if info.build_info != None:
out_dir_path = info.build_info.out_dir.path
- crate["env"].update({"OUT_DIR": _exec_root_tmpl + out_dir_path})
+ crate["env"].update({"OUT_DIR": _EXEC_ROOT_TEMPLATE + out_dir_path})
crate["source"] = {
# We have to tell rust-analyzer about our out_dir since it's not under the crate root.
"exclude_dirs": [],
- "include_dirs": [crate_root, _exec_root_tmpl + out_dir_path],
+ "include_dirs": [crate_root, _EXEC_ROOT_TEMPLATE + out_dir_path],
}
# TODO: The only imagined use case is an env var holding a filename in the workspace passed to a
@@ -188,7 +189,7 @@
crate["cfg"] = info.cfgs
crate["target"] = find_toolchain(ctx).target_triple
if info.proc_macro_dylib_path != None:
- crate["proc_macro_dylib_path"] = _exec_root_tmpl + info.proc_macro_dylib_path
+ crate["proc_macro_dylib_path"] = _EXEC_ROOT_TEMPLATE + info.proc_macro_dylib_path
return crate
def _rust_analyzer_toolchain_impl(ctx):
@@ -223,7 +224,7 @@
sysroot_src = rustc_srcs.label.package + "/library"
if rustc_srcs.label.workspace_root:
- sysroot_src = _exec_root_tmpl + rustc_srcs.label.workspace_root + "/" + sysroot_src
+ sysroot_src = _OUTPUT_BASE_TEMPLATE + rustc_srcs.label.workspace_root + "/" + sysroot_src
sysroot_src_file = ctx.actions.declare_file(ctx.label.name + ".rust_analyzer_sysroot_src")
ctx.actions.write(
diff --git a/tools/rust_analyzer/lib.rs b/tools/rust_analyzer/lib.rs
index 68db7e0..61f9688 100644
--- a/tools/rust_analyzer/lib.rs
+++ b/tools/rust_analyzer/lib.rs
@@ -45,6 +45,7 @@
rules_rust_name: &impl AsRef<str>,
targets: &[String],
execution_root: impl AsRef<Path>,
+ output_base: impl AsRef<Path>,
rust_project_path: impl AsRef<Path>,
) -> anyhow::Result<()> {
let crate_specs = aquery::get_crate_specs(
@@ -72,6 +73,7 @@
rust_project::write_rust_project(
rust_project_path.as_ref(),
execution_root.as_ref(),
+ output_base.as_ref(),
&rust_project,
)?;
diff --git a/tools/rust_analyzer/main.rs b/tools/rust_analyzer/main.rs
index 38a923c..6f13d91 100644
--- a/tools/rust_analyzer/main.rs
+++ b/tools/rust_analyzer/main.rs
@@ -26,6 +26,11 @@
.as_ref()
.expect("failed to find execution root, is --execution-root set correctly?");
+ let output_base = config
+ .output_base
+ .as_ref()
+ .expect("failed to find output base, is -output-base set correctly?");
+
let rules_rust_name = env!("ASPECT_REPOSITORY");
// Generate the crate specs.
@@ -43,6 +48,7 @@
&rules_rust_name,
&config.targets,
&execution_root,
+ &output_base,
&workspace_root.join("rust-project.json"),
)?;
@@ -53,14 +59,6 @@
fn parse_config() -> anyhow::Result<Config> {
let mut config = Config::parse();
- // Ensure we know the workspace. If we are under `bazel run`, the
- // BUILD_WORKSPACE_DIR environment variable will be present.
- if config.workspace.is_none() {
- if let Some(ws_dir) = env::var_os("BUILD_WORKSPACE_DIRECTORY") {
- config.workspace = Some(PathBuf::from(ws_dir));
- }
- }
-
if config.workspace.is_some() && config.execution_root.is_some() {
return Ok(config);
}
@@ -97,24 +95,32 @@
if config.execution_root.is_none() {
config.execution_root = bazel_info.get("execution_root").map(Into::into);
}
+ if config.output_base.is_none() {
+ config.output_base = bazel_info.get("output_base").map(Into::into);
+ }
Ok(config)
}
#[derive(Debug, Parser)]
struct Config {
- // If not specified, uses the result of `bazel info workspace`.
- #[clap(long)]
+ /// The path to the Bazel workspace directory. If not specified, uses the result of `bazel info workspace`.
+ #[clap(long, env = "BUILD_WORKSPACE_DIRECTORY")]
workspace: Option<PathBuf>,
- // If not specified, uses the result of `bazel info execution_root`.
+ /// The path to the Bazel execution root. If not specified, uses the result of `bazel info execution_root`.
#[clap(long)]
execution_root: Option<PathBuf>,
+ /// The path to the Bazel output user root. If not specified, uses the result of `bazel info output_base`.
+ #[clap(long, env = "OUTPUT_BASE")]
+ output_base: Option<PathBuf>,
+
+ /// The path to a Bazel binary
#[clap(long, default_value = "bazel")]
bazel: PathBuf,
- // Space separated list of target patterns that comes after all other args.
+ /// Space separated list of target patterns that comes after all other args.
#[clap(default_value = "@//...")]
targets: Vec<String>,
}
diff --git a/tools/rust_analyzer/rust_project.rs b/tools/rust_analyzer/rust_project.rs
index 0cc9378..30bb377 100644
--- a/tools/rust_analyzer/rust_project.rs
+++ b/tools/rust_analyzer/rust_project.rs
@@ -177,12 +177,17 @@
pub fn write_rust_project(
rust_project_path: &Path,
execution_root: &Path,
+ output_base: &Path,
rust_project: &RustProject,
) -> anyhow::Result<()> {
let execution_root = execution_root
.to_str()
.ok_or_else(|| anyhow!("execution_root is not valid UTF-8"))?;
+ let output_base = output_base
+ .to_str()
+ .ok_or_else(|| anyhow!("output_base is not valid UTF-8"))?;
+
// Try to remove the existing rust-project.json. It's OK if the file doesn't exist.
match std::fs::remove_file(rust_project_path) {
Ok(_) => {}
@@ -197,8 +202,9 @@
// Render the `rust-project.json` file and replace the exec root
// placeholders with the path to the local exec root.
- let rust_project_content =
- serde_json::to_string(rust_project)?.replace("__EXEC_ROOT__", execution_root);
+ let rust_project_content = serde_json::to_string(rust_project)?
+ .replace("__EXEC_ROOT__", execution_root)
+ .replace("__OUTPUT_BASE__", output_base);
// Write the new rust-project.json file.
std::fs::write(rust_project_path, rust_project_content)?;