Skip to content

Commit 984beaa

Browse files
committed
[lldb-dap] Support finding the lldb-dap binary
Support finding the lldb-dap binary with `xcrun` on Darwin or in PATH on all other platforms. Unfortunately, this PR is larger than I would like because it removes the `lldbDapOptions`. I believe these options are not necessary, and as previously implemented, they caused a spurious warning with this change. The problem was that the options were created before the custom factory. By moving the creation logic into the factory, we make sure it's only called after the factory has been registered. The upside is that this simplifies the code and removes a level of indirection.
1 parent f715124 commit 984beaa

File tree

2 files changed

+112
-81
lines changed

2 files changed

+112
-81
lines changed

lldb/tools/lldb-dap/src-ts/debug-adapter-factory.ts

Lines changed: 102 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
import * as path from "path";
2+
import * as util from "util";
13
import * as vscode from "vscode";
4+
25
import { LLDBDapOptions } from "./types";
36

47
/**
@@ -8,15 +11,7 @@ import { LLDBDapOptions } from "./types";
811
export class LLDBDapDescriptorFactory
912
implements vscode.DebugAdapterDescriptorFactory
1013
{
11-
private lldbDapOptions: LLDBDapOptions;
12-
13-
constructor(lldbDapOptions: LLDBDapOptions) {
14-
this.lldbDapOptions = lldbDapOptions;
15-
}
16-
17-
static async isValidDebugAdapterPath(
18-
pathUri: vscode.Uri,
19-
): Promise<Boolean> {
14+
static async isValidFile(pathUri: vscode.Uri): Promise<Boolean> {
2015
try {
2116
const fileStats = await vscode.workspace.fs.stat(pathUri);
2217
if (!(fileStats.type & vscode.FileType.File)) {
@@ -28,6 +23,70 @@ export class LLDBDapDescriptorFactory
2823
return true;
2924
}
3025

26+
static async findDAPExecutable(): Promise<string | undefined> {
27+
let executable = "lldb-dap";
28+
if (process.platform === "win32") {
29+
executable = "lldb-dap.exe";
30+
}
31+
32+
// Prefer lldb-dap from Xcode on Darwin.
33+
if (process.platform === "darwin") {
34+
try {
35+
const exec = util.promisify(require("child_process").execFile);
36+
let { stdout, stderr } = await exec("/usr/bin/xcrun", [
37+
"-find",
38+
executable,
39+
]);
40+
if (stdout) {
41+
return stdout.toString().trimEnd();
42+
}
43+
} catch (error) {}
44+
}
45+
46+
// Find lldb-dap in the user's path.
47+
let env_path =
48+
process.env["PATH"] ||
49+
(process.platform === "win32" ? process.env["Path"] : null);
50+
if (!env_path) {
51+
return undefined;
52+
}
53+
54+
const paths = env_path.split(path.delimiter);
55+
for (const p of paths) {
56+
const exe_path = path.join(p, executable);
57+
if (
58+
await LLDBDapDescriptorFactory.isValidFile(vscode.Uri.file(exe_path))
59+
) {
60+
return exe_path;
61+
}
62+
}
63+
64+
return undefined;
65+
}
66+
67+
static async getDAPExecutable(
68+
session: vscode.DebugSession,
69+
): Promise<string | undefined> {
70+
const config = vscode.workspace.getConfiguration(
71+
"lldb-dap",
72+
session.workspaceFolder,
73+
);
74+
75+
// Prefer the explicitly specified path in the extension's configuration.
76+
const configPath = config.get<string>("executable-path");
77+
if (configPath && configPath.length !== 0) {
78+
return configPath;
79+
}
80+
81+
// Try finding the lldb-dap binary.
82+
const foundPath = await LLDBDapDescriptorFactory.findDAPExecutable();
83+
if (foundPath) {
84+
return foundPath;
85+
}
86+
87+
return undefined;
88+
}
89+
3190
async createDebugAdapterDescriptor(
3291
session: vscode.DebugSession,
3392
executable: vscode.DebugAdapterExecutable | undefined,
@@ -36,14 +95,42 @@ export class LLDBDapDescriptorFactory
3695
"lldb-dap",
3796
session.workspaceFolder,
3897
);
39-
const customPath = config.get<string>("executable-path");
40-
const path: string = customPath || executable!!.command;
4198

42-
const fileUri = vscode.Uri.file(path);
43-
if (!(await LLDBDapDescriptorFactory.isValidDebugAdapterPath(fileUri))) {
44-
LLDBDapDescriptorFactory.showLLDBDapNotFoundMessage(fileUri.path);
99+
const log_path = config.get<string>("log-path");
100+
let env: { [key: string]: string } = {};
101+
if (log_path) {
102+
env["LLDBDAP_LOG"] = log_path;
103+
}
104+
const configEnvironment =
105+
config.get<{ [key: string]: string }>("environment") || {};
106+
const dapPath = await LLDBDapDescriptorFactory.getDAPExecutable(session);
107+
const dbgOptions = {
108+
env: {
109+
...executable?.options?.env,
110+
...configEnvironment,
111+
...env,
112+
},
113+
};
114+
if (dapPath) {
115+
const fileUri = vscode.Uri.file(dapPath);
116+
if (!(await LLDBDapDescriptorFactory.isValidFile(fileUri))) {
117+
LLDBDapDescriptorFactory.showLLDBDapNotFoundMessage(fileUri.path);
118+
return undefined;
119+
}
120+
return new vscode.DebugAdapterExecutable(dapPath, [], dbgOptions);
121+
} else if (executable) {
122+
const fileUri = vscode.Uri.file(executable.command);
123+
if (!(await LLDBDapDescriptorFactory.isValidFile(fileUri))) {
124+
LLDBDapDescriptorFactory.showLLDBDapNotFoundMessage(fileUri.path);
125+
return undefined;
126+
}
127+
return new vscode.DebugAdapterExecutable(
128+
executable.command,
129+
executable.args,
130+
dbgOptions,
131+
);
45132
}
46-
return this.lldbDapOptions.createDapExecutableCommand(session, executable);
133+
return undefined;
47134
}
48135

49136
/**
Lines changed: 10 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,22 @@
1+
import * as path from "path";
2+
import * as util from "util";
13
import * as vscode from "vscode";
2-
import { LLDBDapOptions } from "./types";
3-
import { DisposableContext } from "./disposable-context";
4-
import { LLDBDapDescriptorFactory } from "./debug-adapter-factory";
5-
6-
/**
7-
* This creates the configurations for this project if used as a standalone
8-
* extension.
9-
*/
10-
function createDefaultLLDBDapOptions(): LLDBDapOptions {
11-
return {
12-
debuggerType: "lldb-dap",
13-
async createDapExecutableCommand(
14-
session: vscode.DebugSession,
15-
packageJSONExecutable: vscode.DebugAdapterExecutable | undefined,
16-
): Promise<vscode.DebugAdapterExecutable | undefined> {
17-
const config = vscode.workspace.getConfiguration(
18-
"lldb-dap",
19-
session.workspaceFolder,
20-
);
21-
const path = config.get<string>("executable-path");
22-
const log_path = config.get<string>("log-path");
234

24-
let env: { [key: string]: string } = {};
25-
if (log_path) {
26-
env["LLDBDAP_LOG"] = log_path;
27-
}
28-
const configEnvironment = config.get<{ [key: string]: string }>("environment") || {};
29-
if (path) {
30-
const dbgOptions = {
31-
env: {
32-
...configEnvironment,
33-
...env,
34-
}
35-
};
36-
return new vscode.DebugAdapterExecutable(path, [], dbgOptions);
37-
} else if (packageJSONExecutable) {
38-
return new vscode.DebugAdapterExecutable(
39-
packageJSONExecutable.command,
40-
packageJSONExecutable.args,
41-
{
42-
...packageJSONExecutable.options,
43-
env: {
44-
...packageJSONExecutable.options?.env,
45-
...configEnvironment,
46-
...env,
47-
},
48-
},
49-
);
50-
} else {
51-
return undefined;
52-
}
53-
},
54-
};
55-
}
5+
import { LLDBDapDescriptorFactory } from "./debug-adapter-factory";
6+
import { DisposableContext } from "./disposable-context";
7+
import { LLDBDapOptions } from "./types";
568

579
/**
5810
* This class represents the extension and manages its life cycle. Other extensions
5911
* using it as as library should use this class as the main entry point.
6012
*/
6113
export class LLDBDapExtension extends DisposableContext {
62-
private lldbDapOptions: LLDBDapOptions;
63-
64-
constructor(lldbDapOptions: LLDBDapOptions) {
14+
constructor() {
6515
super();
66-
this.lldbDapOptions = lldbDapOptions;
67-
6816
this.pushSubscription(
6917
vscode.debug.registerDebugAdapterDescriptorFactory(
70-
this.lldbDapOptions.debuggerType,
71-
new LLDBDapDescriptorFactory(this.lldbDapOptions),
18+
"lldb-dap",
19+
new LLDBDapDescriptorFactory(),
7220
),
7321
);
7422

@@ -81,9 +29,7 @@ export class LLDBDapExtension extends DisposableContext {
8129

8230
if (dapPath) {
8331
const fileUri = vscode.Uri.file(dapPath);
84-
if (
85-
await LLDBDapDescriptorFactory.isValidDebugAdapterPath(fileUri)
86-
) {
32+
if (await LLDBDapDescriptorFactory.isValidFile(fileUri)) {
8733
return;
8834
}
8935
}
@@ -98,7 +44,5 @@ export class LLDBDapExtension extends DisposableContext {
9844
* This is the entry point when initialized by VS Code.
9945
*/
10046
export function activate(context: vscode.ExtensionContext) {
101-
context.subscriptions.push(
102-
new LLDBDapExtension(createDefaultLLDBDapOptions()),
103-
);
47+
context.subscriptions.push(new LLDBDapExtension());
10448
}

0 commit comments

Comments
 (0)