[Lldb-commits] [lldb] ff59538 - [lldb-dap] Support finding the lldb-dap binary (#118547)

via lldb-commits lldb-commits at lists.llvm.org
Wed Dec 4 09:43:53 PST 2024


Author: Jonas Devlieghere
Date: 2024-12-04T09:43:49-08:00
New Revision: ff5953804ea5b430710b07f1dae395bfcf6d35d0

URL: https://github.com/llvm/llvm-project/commit/ff5953804ea5b430710b07f1dae395bfcf6d35d0
DIFF: https://github.com/llvm/llvm-project/commit/ff5953804ea5b430710b07f1dae395bfcf6d35d0.diff

LOG: [lldb-dap] Support finding the lldb-dap binary (#118547)

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.

Added: 
    

Modified: 
    lldb/tools/lldb-dap/package.json
    lldb/tools/lldb-dap/src-ts/debug-adapter-factory.ts
    lldb/tools/lldb-dap/src-ts/extension.ts

Removed: 
    lldb/tools/lldb-dap/src-ts/types.ts


################################################################################
diff  --git a/lldb/tools/lldb-dap/package.json b/lldb/tools/lldb-dap/package.json
index 5e9a7de9109ec8..6079edb5a2189a 100644
--- a/lldb/tools/lldb-dap/package.json
+++ b/lldb/tools/lldb-dap/package.json
@@ -1,7 +1,7 @@
 {
   "name": "lldb-dap",
   "displayName": "LLDB DAP",
-  "version": "0.2.6",
+  "version": "0.2.7",
   "publisher": "llvm-vs-code-extensions",
   "homepage": "https://lldb.llvm.org",
   "description": "LLDB debugging from VSCode",

diff  --git a/lldb/tools/lldb-dap/src-ts/debug-adapter-factory.ts b/lldb/tools/lldb-dap/src-ts/debug-adapter-factory.ts
index 2be21bfdf0dd69..55c2f3e9f7deb5 100644
--- a/lldb/tools/lldb-dap/src-ts/debug-adapter-factory.ts
+++ b/lldb/tools/lldb-dap/src-ts/debug-adapter-factory.ts
@@ -1,33 +1,99 @@
+import * as path from "path";
+import * as util from "util";
 import * as vscode from "vscode";
-import { LLDBDapOptions } from "./types";
+import * as child_process from "child_process";
+import * as fs from "node:fs/promises";
 
-/**
- * This class defines a factory used to find the lldb-dap binary to use
- * depending on the session configuration.
- */
-export class LLDBDapDescriptorFactory
-  implements vscode.DebugAdapterDescriptorFactory
-{
-  private lldbDapOptions: LLDBDapOptions;
-
-  constructor(lldbDapOptions: LLDBDapOptions) {
-    this.lldbDapOptions = lldbDapOptions;
+export async function isExecutable(path: string): Promise<Boolean> {
+  try {
+    await fs.access(path, fs.constants.X_OK);
+  } catch {
+    return false;
   }
+  return true;
+}
 
-  static async isValidDebugAdapterPath(
-    pathUri: vscode.Uri,
-  ): Promise<Boolean> {
+async function findWithXcrun(executable: string): Promise<string | undefined> {
+  if (process.platform === "darwin") {
     try {
-      const fileStats = await vscode.workspace.fs.stat(pathUri);
-      if (!(fileStats.type & vscode.FileType.File)) {
-        return false;
+      const exec = util.promisify(child_process.execFile);
+      let { stdout, stderr } = await exec("/usr/bin/xcrun", [
+        "-find",
+        executable,
+      ]);
+      if (stdout) {
+        return stdout.toString().trimEnd();
       }
-    } catch (err) {
-      return false;
+    } catch (error) {}
+  }
+  return undefined;
+}
+
+async function findInPath(executable: string): Promise<string | undefined> {
+  const env_path =
+    process.platform === "win32" ? process.env["Path"] : process.env["PATH"];
+  if (!env_path) {
+    return undefined;
+  }
+
+  const paths = env_path.split(path.delimiter);
+  for (const p of paths) {
+    const exe_path = path.join(p, executable);
+    if (await isExecutable(exe_path)) {
+      return exe_path;
     }
-    return true;
+  }
+  return undefined;
+}
+
+async function findDAPExecutable(): Promise<string | undefined> {
+  const executable = process.platform === "win32" ? "lldb-dap.exe" : "lldb-dap";
+
+  // Prefer lldb-dap from Xcode on Darwin.
+  const xcrun_dap = findWithXcrun(executable);
+  if (xcrun_dap) {
+    return xcrun_dap;
+  }
+
+  // Find lldb-dap in the user's path.
+  const path_dap = findInPath(executable);
+  if (path_dap) {
+    return path_dap;
   }
 
+  return undefined;
+}
+
+async function getDAPExecutable(
+  session: vscode.DebugSession,
+): Promise<string | undefined> {
+  const config = vscode.workspace.getConfiguration(
+    "lldb-dap",
+    session.workspaceFolder,
+  );
+
+  // Prefer the explicitly specified path in the extension's configuration.
+  const configPath = config.get<string>("executable-path");
+  if (configPath && configPath.length !== 0) {
+    return configPath;
+  }
+
+  // Try finding the lldb-dap binary.
+  const foundPath = await findDAPExecutable();
+  if (foundPath) {
+    return foundPath;
+  }
+
+  return undefined;
+}
+
+/**
+ * This class defines a factory used to find the lldb-dap binary to use
+ * depending on the session configuration.
+ */
+export class LLDBDapDescriptorFactory
+  implements vscode.DebugAdapterDescriptorFactory
+{
   async createDebugAdapterDescriptor(
     session: vscode.DebugSession,
     executable: vscode.DebugAdapterExecutable | undefined,
@@ -36,14 +102,40 @@ export class LLDBDapDescriptorFactory
       "lldb-dap",
       session.workspaceFolder,
     );
-    const customPath = config.get<string>("executable-path");
-    const path: string = customPath || executable!!.command;
 
-    const fileUri = vscode.Uri.file(path);
-    if (!(await LLDBDapDescriptorFactory.isValidDebugAdapterPath(fileUri))) {
-      LLDBDapDescriptorFactory.showLLDBDapNotFoundMessage(fileUri.path);
+    const log_path = config.get<string>("log-path");
+    let env: { [key: string]: string } = {};
+    if (log_path) {
+      env["LLDBDAP_LOG"] = log_path;
+    }
+    const configEnvironment =
+      config.get<{ [key: string]: string }>("environment") || {};
+    const dapPath = await getDAPExecutable(session);
+    const dbgOptions = {
+      env: {
+        ...executable?.options?.env,
+        ...configEnvironment,
+        ...env,
+      },
+    };
+    if (dapPath) {
+      if (!(await isExecutable(dapPath))) {
+        LLDBDapDescriptorFactory.showLLDBDapNotFoundMessage(dapPath);
+        return undefined;
+      }
+      return new vscode.DebugAdapterExecutable(dapPath, [], dbgOptions);
+    } else if (executable) {
+      if (!(await isExecutable(executable.command))) {
+        LLDBDapDescriptorFactory.showLLDBDapNotFoundMessage(executable.command);
+        return undefined;
+      }
+      return new vscode.DebugAdapterExecutable(
+        executable.command,
+        executable.args,
+        dbgOptions,
+      );
     }
-    return this.lldbDapOptions.createDapExecutableCommand(session, executable);
+    return undefined;
   }
 
   /**

diff  --git a/lldb/tools/lldb-dap/src-ts/extension.ts b/lldb/tools/lldb-dap/src-ts/extension.ts
index 36d3dfba18c142..71fd48298f8f53 100644
--- a/lldb/tools/lldb-dap/src-ts/extension.ts
+++ b/lldb/tools/lldb-dap/src-ts/extension.ts
@@ -1,74 +1,24 @@
+import * as path from "path";
+import * as util from "util";
 import * as vscode from "vscode";
-import { LLDBDapOptions } from "./types";
-import { DisposableContext } from "./disposable-context";
-import { LLDBDapDescriptorFactory } from "./debug-adapter-factory";
-
-/**
- * This creates the configurations for this project if used as a standalone
- * extension.
- */
-function createDefaultLLDBDapOptions(): LLDBDapOptions {
-  return {
-    debuggerType: "lldb-dap",
-    async createDapExecutableCommand(
-      session: vscode.DebugSession,
-      packageJSONExecutable: vscode.DebugAdapterExecutable | undefined,
-    ): Promise<vscode.DebugAdapterExecutable | undefined> {
-      const config = vscode.workspace.getConfiguration(
-        "lldb-dap",
-        session.workspaceFolder,
-      );
-      const path = config.get<string>("executable-path");
-      const log_path = config.get<string>("log-path");
 
-      let env: { [key: string]: string } = {};
-      if (log_path) {
-        env["LLDBDAP_LOG"] = log_path;
-      }
-      const configEnvironment = config.get<{ [key: string]: string }>("environment") || {};
-      if (path) {
-        const dbgOptions = {
-          env: {
-            ...configEnvironment,
-            ...env,
-          }
-        };
-        return new vscode.DebugAdapterExecutable(path, [], dbgOptions);
-      } else if (packageJSONExecutable) {
-        return new vscode.DebugAdapterExecutable(
-          packageJSONExecutable.command,
-          packageJSONExecutable.args,
-          {
-            ...packageJSONExecutable.options,
-            env: {
-              ...packageJSONExecutable.options?.env,
-              ...configEnvironment,
-              ...env,
-            },
-          },
-        );
-      } else {
-        return undefined;
-      }
-    },
-  };
-}
+import {
+  LLDBDapDescriptorFactory,
+  isExecutable,
+} from "./debug-adapter-factory";
+import { DisposableContext } from "./disposable-context";
 
 /**
  * This class represents the extension and manages its life cycle. Other extensions
  * using it as as library should use this class as the main entry point.
  */
 export class LLDBDapExtension extends DisposableContext {
-  private lldbDapOptions: LLDBDapOptions;
-
-  constructor(lldbDapOptions: LLDBDapOptions) {
+  constructor() {
     super();
-    this.lldbDapOptions = lldbDapOptions;
-
     this.pushSubscription(
       vscode.debug.registerDebugAdapterDescriptorFactory(
-        this.lldbDapOptions.debuggerType,
-        new LLDBDapDescriptorFactory(this.lldbDapOptions),
+        "lldb-dap",
+        new LLDBDapDescriptorFactory(),
       ),
     );
 
@@ -80,10 +30,7 @@ export class LLDBDapExtension extends DisposableContext {
             .get<string>("executable-path");
 
           if (dapPath) {
-            const fileUri = vscode.Uri.file(dapPath);
-            if (
-              await LLDBDapDescriptorFactory.isValidDebugAdapterPath(fileUri)
-            ) {
+            if (await isExecutable(dapPath)) {
               return;
             }
           }
@@ -98,7 +45,5 @@ export class LLDBDapExtension extends DisposableContext {
  * This is the entry point when initialized by VS Code.
  */
 export function activate(context: vscode.ExtensionContext) {
-  context.subscriptions.push(
-    new LLDBDapExtension(createDefaultLLDBDapOptions()),
-  );
+  context.subscriptions.push(new LLDBDapExtension());
 }

diff  --git a/lldb/tools/lldb-dap/src-ts/types.ts b/lldb/tools/lldb-dap/src-ts/types.ts
deleted file mode 100644
index 63a8c73982caf3..00000000000000
--- a/lldb/tools/lldb-dap/src-ts/types.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import * as vscode from "vscode";
-
-/**
- * Callback used to generate the actual command to be executed to launch the lldb-dap binary.
- *
- * @param session - The information of the debug session to be launched.
- *
- * @param packageJSONExecutable - An optional {@link vscode.DebugAdapterExecutable executable} for
- * lldb-dap if specified in the package.json file.
- */
-export type LLDBDapCreateDAPExecutableCommand = (
-  session: vscode.DebugSession,
-  packageJSONExecutable: vscode.DebugAdapterExecutable | undefined,
-) => Promise<vscode.DebugAdapterExecutable | undefined>;
-
-/**
- * The options that this extension accepts.
- */
-export interface LLDBDapOptions {
-  createDapExecutableCommand: LLDBDapCreateDAPExecutableCommand;
-  // The name of the debugger type as specified in the package.json file.
-  debuggerType: string;
-}


        


More information about the lldb-commits mailing list