mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-14 14:13:58 +00:00
Auto merge of #17605 - Veykril:runnable-sysroot, r=Veykril
Set `RUSTC_TOOLCHAIN` for runnables With this the client doesn't necessarily need to guess the sysroot anymore
This commit is contained in:
commit
41dcb2d650
8 changed files with 59 additions and 43 deletions
|
@ -579,6 +579,7 @@ impl GlobalStateSnapshot {
|
||||||
target_kind: target_data.kind,
|
target_kind: target_data.kind,
|
||||||
required_features: target_data.required_features.clone(),
|
required_features: target_data.required_features.clone(),
|
||||||
features: package_data.features.keys().cloned().collect(),
|
features: package_data.features.keys().cloned().collect(),
|
||||||
|
sysroot_root: workspace.sysroot.root().map(ToOwned::to_owned),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
ProjectWorkspaceKind::Json(project) => {
|
ProjectWorkspaceKind::Json(project) => {
|
||||||
|
|
|
@ -50,7 +50,7 @@ use crate::{
|
||||||
self, CrateInfoResult, ExternalDocsPair, ExternalDocsResponse, FetchDependencyListParams,
|
self, CrateInfoResult, ExternalDocsPair, ExternalDocsResponse, FetchDependencyListParams,
|
||||||
FetchDependencyListResult, PositionOrRange, ViewCrateGraphParams, WorkspaceSymbolParams,
|
FetchDependencyListResult, PositionOrRange, ViewCrateGraphParams, WorkspaceSymbolParams,
|
||||||
},
|
},
|
||||||
target_spec::TargetSpec,
|
target_spec::{CargoTargetSpec, TargetSpec},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) fn handle_workspace_reload(state: &mut GlobalState, _: ()) -> anyhow::Result<()> {
|
pub(crate) fn handle_workspace_reload(state: &mut GlobalState, _: ()) -> anyhow::Result<()> {
|
||||||
|
@ -848,6 +848,14 @@ pub(crate) fn handle_runnables(
|
||||||
if let lsp_ext::RunnableArgs::Cargo(r) = &mut runnable.args {
|
if let lsp_ext::RunnableArgs::Cargo(r) = &mut runnable.args {
|
||||||
runnable.label = format!("{} + expect", runnable.label);
|
runnable.label = format!("{} + expect", runnable.label);
|
||||||
r.environment.insert("UPDATE_EXPECT".to_owned(), "1".to_owned());
|
r.environment.insert("UPDATE_EXPECT".to_owned(), "1".to_owned());
|
||||||
|
if let Some(TargetSpec::Cargo(CargoTargetSpec {
|
||||||
|
sysroot_root: Some(sysroot_root),
|
||||||
|
..
|
||||||
|
})) = &target_spec
|
||||||
|
{
|
||||||
|
r.environment
|
||||||
|
.insert("RUSTC_TOOLCHAIN".to_owned(), sysroot_root.to_string());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
res.push(runnable);
|
res.push(runnable);
|
||||||
|
@ -889,7 +897,12 @@ pub(crate) fn handle_runnables(
|
||||||
override_cargo: config.override_cargo.clone(),
|
override_cargo: config.override_cargo.clone(),
|
||||||
cargo_args,
|
cargo_args,
|
||||||
executable_args: Vec::new(),
|
executable_args: Vec::new(),
|
||||||
environment: Default::default(),
|
environment: spec
|
||||||
|
.sysroot_root
|
||||||
|
.as_ref()
|
||||||
|
.map(|root| ("RUSTC_TOOLCHAIN".to_owned(), root.to_string()))
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1399,7 +1399,11 @@ pub(crate) fn runnable(
|
||||||
cargo_args,
|
cargo_args,
|
||||||
cwd: cwd.into(),
|
cwd: cwd.into(),
|
||||||
executable_args,
|
executable_args,
|
||||||
environment: Default::default(),
|
environment: spec
|
||||||
|
.sysroot_root
|
||||||
|
.map(|root| ("RUSTC_TOOLCHAIN".to_owned(), root.to_string()))
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
}),
|
}),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,6 +57,7 @@ pub(crate) struct CargoTargetSpec {
|
||||||
pub(crate) crate_id: CrateId,
|
pub(crate) crate_id: CrateId,
|
||||||
pub(crate) required_features: Vec<String>,
|
pub(crate) required_features: Vec<String>,
|
||||||
pub(crate) features: FxHashSet<String>,
|
pub(crate) features: FxHashSet<String>,
|
||||||
|
pub(crate) sysroot_root: Option<vfs::AbsPathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
|
|
@ -3,10 +3,10 @@ import * as vscode from "vscode";
|
||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
import type * as ra from "./lsp_ext";
|
import type * as ra from "./lsp_ext";
|
||||||
|
|
||||||
import { Cargo, getRustcId, getSysroot } from "./toolchain";
|
import { Cargo } from "./toolchain";
|
||||||
import type { Ctx } from "./ctx";
|
import type { Ctx } from "./ctx";
|
||||||
import { prepareEnv } from "./run";
|
import { prepareEnv } from "./run";
|
||||||
import { isCargoRunnableArgs, unwrapUndefinable } from "./util";
|
import { execute, isCargoRunnableArgs, unwrapUndefinable } from "./util";
|
||||||
|
|
||||||
const debugOutput = vscode.window.createOutputChannel("Debug");
|
const debugOutput = vscode.window.createOutputChannel("Debug");
|
||||||
type DebugConfigProvider = (
|
type DebugConfigProvider = (
|
||||||
|
@ -142,18 +142,29 @@ async function getDebugConfiguration(
|
||||||
const executable = await getDebugExecutable(runnableArgs, env);
|
const executable = await getDebugExecutable(runnableArgs, env);
|
||||||
let sourceFileMap = debugOptions.sourceFileMap;
|
let sourceFileMap = debugOptions.sourceFileMap;
|
||||||
if (sourceFileMap === "auto") {
|
if (sourceFileMap === "auto") {
|
||||||
// let's try to use the default toolchain
|
|
||||||
const [commitHash, sysroot] = await Promise.all([
|
|
||||||
getRustcId(wsFolder),
|
|
||||||
getSysroot(wsFolder),
|
|
||||||
]);
|
|
||||||
const rustlib = path.normalize(sysroot + "/lib/rustlib/src/rust");
|
|
||||||
sourceFileMap = {};
|
sourceFileMap = {};
|
||||||
sourceFileMap[`/rustc/${commitHash}/`] = rustlib;
|
const sysroot = env["RUSTC_TOOLCHAIN"];
|
||||||
|
if (sysroot) {
|
||||||
|
// let's try to use the default toolchain
|
||||||
|
const data = await execute(`rustc -V -v`, { cwd: wsFolder, env });
|
||||||
|
const rx = /commit-hash:\s(.*)$/m;
|
||||||
|
|
||||||
|
const commitHash = rx.exec(data)?.[1];
|
||||||
|
if (commitHash) {
|
||||||
|
const rustlib = path.normalize(sysroot + "/lib/rustlib/src/rust");
|
||||||
|
sourceFileMap[`/rustc/${commitHash}/`] = rustlib;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const provider = unwrapUndefinable(knownEngines[debugEngine.id]);
|
const provider = unwrapUndefinable(knownEngines[debugEngine.id]);
|
||||||
const debugConfig = provider(runnable, runnableArgs, simplifyPath(executable), env);
|
const debugConfig = provider(
|
||||||
|
runnable,
|
||||||
|
runnableArgs,
|
||||||
|
simplifyPath(executable),
|
||||||
|
env,
|
||||||
|
sourceFileMap,
|
||||||
|
);
|
||||||
if (debugConfig.type in debugOptions.engineSettings) {
|
if (debugConfig.type in debugOptions.engineSettings) {
|
||||||
const settingsMap = (debugOptions.engineSettings as any)[debugConfig.type];
|
const settingsMap = (debugOptions.engineSettings as any)[debugConfig.type];
|
||||||
for (var key in settingsMap) {
|
for (var key in settingsMap) {
|
||||||
|
|
|
@ -8,7 +8,6 @@ import { makeDebugConfig } from "./debug";
|
||||||
import type { Config, RunnableEnvCfg, RunnableEnvCfgItem } from "./config";
|
import type { Config, RunnableEnvCfg, RunnableEnvCfgItem } from "./config";
|
||||||
import type { LanguageClient } from "vscode-languageclient/node";
|
import type { LanguageClient } from "vscode-languageclient/node";
|
||||||
import { unwrapUndefinable, type RustEditor } from "./util";
|
import { unwrapUndefinable, type RustEditor } from "./util";
|
||||||
import * as toolchain from "./toolchain";
|
|
||||||
|
|
||||||
const quickPickButtons = [
|
const quickPickButtons = [
|
||||||
{ iconPath: new vscode.ThemeIcon("save"), tooltip: "Save as a launch.json configuration." },
|
{ iconPath: new vscode.ThemeIcon("save"), tooltip: "Save as a launch.json configuration." },
|
||||||
|
@ -115,7 +114,7 @@ export async function createTaskFromRunnable(
|
||||||
|
|
||||||
let definition: tasks.TaskDefinition;
|
let definition: tasks.TaskDefinition;
|
||||||
let options;
|
let options;
|
||||||
let cargo;
|
let cargo = "cargo";
|
||||||
if (runnable.kind === "cargo") {
|
if (runnable.kind === "cargo") {
|
||||||
const runnableArgs = runnable.args;
|
const runnableArgs = runnable.args;
|
||||||
let args = createCargoArgs(runnableArgs);
|
let args = createCargoArgs(runnableArgs);
|
||||||
|
@ -126,8 +125,6 @@ export async function createTaskFromRunnable(
|
||||||
|
|
||||||
cargo = unwrapUndefinable(cargoParts[0]);
|
cargo = unwrapUndefinable(cargoParts[0]);
|
||||||
args = [...cargoParts.slice(1), ...args];
|
args = [...cargoParts.slice(1), ...args];
|
||||||
} else {
|
|
||||||
cargo = await toolchain.cargoPath();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
definition = {
|
definition = {
|
||||||
|
@ -200,7 +197,7 @@ async function getRunnables(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (debuggeeOnly && (r.label.startsWith("doctest") || r.label.startsWith("cargo"))) {
|
if (debuggeeOnly && r.label.startsWith("doctest")) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
items.push(new RunnableQuickPick(r));
|
items.push(new RunnableQuickPick(r));
|
||||||
|
|
|
@ -125,7 +125,7 @@ export async function targetToExecution(
|
||||||
let command, args;
|
let command, args;
|
||||||
if (isCargoTask(definition)) {
|
if (isCargoTask(definition)) {
|
||||||
// FIXME: The server should provide cargo
|
// FIXME: The server should provide cargo
|
||||||
command = cargo || (await toolchain.cargoPath());
|
command = cargo || (await toolchain.cargoPath(options?.env));
|
||||||
args = [definition.command].concat(definition.args || []);
|
args = [definition.command].concat(definition.args || []);
|
||||||
} else {
|
} else {
|
||||||
command = definition.command;
|
command = definition.command;
|
||||||
|
|
|
@ -3,7 +3,7 @@ import * as os from "os";
|
||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
import * as readline from "readline";
|
import * as readline from "readline";
|
||||||
import * as vscode from "vscode";
|
import * as vscode from "vscode";
|
||||||
import { execute, log, memoizeAsync, unwrapNullable, unwrapUndefinable } from "./util";
|
import { log, memoizeAsync, unwrapUndefinable } from "./util";
|
||||||
import type { CargoRunnableArgs } from "./lsp_ext";
|
import type { CargoRunnableArgs } from "./lsp_ext";
|
||||||
|
|
||||||
interface CompilationArtifact {
|
interface CompilationArtifact {
|
||||||
|
@ -55,7 +55,10 @@ export class Cargo {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getArtifacts(spec: ArtifactSpec): Promise<CompilationArtifact[]> {
|
private async getArtifacts(
|
||||||
|
spec: ArtifactSpec,
|
||||||
|
env?: Record<string, string>,
|
||||||
|
): Promise<CompilationArtifact[]> {
|
||||||
const artifacts: CompilationArtifact[] = [];
|
const artifacts: CompilationArtifact[] = [];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -78,6 +81,7 @@ export class Cargo {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
(stderr) => this.output.append(stderr),
|
(stderr) => this.output.append(stderr),
|
||||||
|
env,
|
||||||
);
|
);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.output.show(true);
|
this.output.show(true);
|
||||||
|
@ -90,6 +94,7 @@ export class Cargo {
|
||||||
async executableFromArgs(runnableArgs: CargoRunnableArgs): Promise<string> {
|
async executableFromArgs(runnableArgs: CargoRunnableArgs): Promise<string> {
|
||||||
const artifacts = await this.getArtifacts(
|
const artifacts = await this.getArtifacts(
|
||||||
Cargo.artifactSpec(runnableArgs.cargoArgs, runnableArgs.executableArgs),
|
Cargo.artifactSpec(runnableArgs.cargoArgs, runnableArgs.executableArgs),
|
||||||
|
runnableArgs.environment,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (artifacts.length === 0) {
|
if (artifacts.length === 0) {
|
||||||
|
@ -106,8 +111,9 @@ export class Cargo {
|
||||||
cargoArgs: string[],
|
cargoArgs: string[],
|
||||||
onStdoutJson: (obj: any) => void,
|
onStdoutJson: (obj: any) => void,
|
||||||
onStderrString: (data: string) => void,
|
onStderrString: (data: string) => void,
|
||||||
|
env?: Record<string, string>,
|
||||||
): Promise<number> {
|
): Promise<number> {
|
||||||
const path = await cargoPath();
|
const path = await cargoPath(env);
|
||||||
return await new Promise((resolve, reject) => {
|
return await new Promise((resolve, reject) => {
|
||||||
const cargo = cp.spawn(path, cargoArgs, {
|
const cargo = cp.spawn(path, cargoArgs, {
|
||||||
stdio: ["ignore", "pipe", "pipe"],
|
stdio: ["ignore", "pipe", "pipe"],
|
||||||
|
@ -133,29 +139,12 @@ export class Cargo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Mirrors `project_model::sysroot::discover_sysroot_dir()` implementation*/
|
|
||||||
export async function getSysroot(dir: string): Promise<string> {
|
|
||||||
const rustcPath = await getPathForExecutable("rustc");
|
|
||||||
|
|
||||||
// do not memoize the result because the toolchain may change between runs
|
|
||||||
return await execute(`${rustcPath} --print sysroot`, { cwd: dir });
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getRustcId(dir: string): Promise<string> {
|
|
||||||
const rustcPath = await getPathForExecutable("rustc");
|
|
||||||
|
|
||||||
// do not memoize the result because the toolchain may change between runs
|
|
||||||
const data = await execute(`${rustcPath} -V -v`, { cwd: dir });
|
|
||||||
const rx = /commit-hash:\s(.*)$/m;
|
|
||||||
|
|
||||||
const result = unwrapNullable(rx.exec(data));
|
|
||||||
const first = unwrapUndefinable(result[1]);
|
|
||||||
return first;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Mirrors `toolchain::cargo()` implementation */
|
/** Mirrors `toolchain::cargo()` implementation */
|
||||||
// FIXME: The server should provide this
|
// FIXME: The server should provide this
|
||||||
export function cargoPath(): Promise<string> {
|
export function cargoPath(env?: Record<string, string>): Promise<string> {
|
||||||
|
if (env?.["RUSTC_TOOLCHAIN"]) {
|
||||||
|
return Promise.resolve("cargo");
|
||||||
|
}
|
||||||
return getPathForExecutable("cargo");
|
return getPathForExecutable("cargo");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue