Skip to content

Commit

Permalink
Fix rust-analyzer being unable to find rust sysroot sources. (#1483)
Browse files Browse the repository at this point in the history
* 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]>
  • Loading branch information
UebelAndre and illicitonion authored Jul 26, 2022
1 parent 81a77ac commit 2d7f945
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 20 deletions.
13 changes: 7 additions & 6 deletions rust/private/rust_analyzer.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,8 @@ rust_analyzer_aspect = aspect(
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
Expand Down Expand Up @@ -155,18 +156,18 @@ def _create_single_crate(ctx, info):
# 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
Expand All @@ -188,7 +189,7 @@ def _create_single_crate(ctx, info):
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):
Expand Down Expand Up @@ -223,7 +224,7 @@ def _rust_analyzer_detect_sysroot_impl(ctx):

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(
Expand Down
2 changes: 2 additions & 0 deletions tools/rust_analyzer/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ pub fn write_rust_project(
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(
Expand Down Expand Up @@ -72,6 +73,7 @@ pub fn write_rust_project(
rust_project::write_rust_project(
rust_project_path.as_ref(),
execution_root.as_ref(),
output_base.as_ref(),
&rust_project,
)?;

Expand Down
30 changes: 18 additions & 12 deletions tools/rust_analyzer/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ fn main() -> anyhow::Result<()> {
.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.
Expand All @@ -43,6 +48,7 @@ fn main() -> anyhow::Result<()> {
&rules_rust_name,
&config.targets,
&execution_root,
&output_base,
&workspace_root.join("rust-project.json"),
)?;

Expand All @@ -53,14 +59,6 @@ fn main() -> anyhow::Result<()> {
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);
}
Expand Down Expand Up @@ -97,24 +95,32 @@ fn parse_config() -> anyhow::Result<Config> {
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>,
}
10 changes: 8 additions & 2 deletions tools/rust_analyzer/rust_project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,12 +177,17 @@ pub fn generate_rust_project(
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(_) => {}
Expand All @@ -197,8 +202,9 @@ pub fn write_rust_project(

// 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)?;
Expand Down

0 comments on commit 2d7f945

Please sign in to comment.