diff --git a/lldb/include/lldb/Host/windows/PythonPathSetup/PythonPathSetup.h b/lldb/include/lldb/Host/windows/PythonPathSetup/PythonPathSetup.h index 3e297a92c7128..468eb26b04a23 100644 --- a/lldb/include/lldb/Host/windows/PythonPathSetup/PythonPathSetup.h +++ b/lldb/include/lldb/Host/windows/PythonPathSetup/PythonPathSetup.h @@ -42,7 +42,12 @@ bool AddPythonDLLToSearchPath(); /// can be loaded. If successful, returns immediately. Otherwise, attempts to /// resolve the relative path and add it to the DLL search path, then checks /// again if python3xx.dll can be loaded. -llvm::Error SetupPythonRuntimeLibrary(); +/// +/// \return If LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME is defined, return the +/// absolute path of the Python shared library which was resolved or an error if +/// it could not be found. If LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME and +/// LLDB_PYTHON_DLL_RELATIVE_PATH are not defined, return an empty string. +llvm::Expected SetupPythonRuntimeLibrary(); // BEGIN SWIFT extern const std::string g_python_installation_note; diff --git a/lldb/source/Host/windows/PythonPathSetup/PythonPathSetup.cpp b/lldb/source/Host/windows/PythonPathSetup/PythonPathSetup.cpp index ee76e9c9b2520..a8d8f10fa06dc 100644 --- a/lldb/source/Host/windows/PythonPathSetup/PythonPathSetup.cpp +++ b/lldb/source/Host/windows/PythonPathSetup/PythonPathSetup.cpp @@ -19,10 +19,11 @@ using namespace llvm; +#ifdef LLDB_PYTHON_DLL_RELATIVE_PATH static std::string GetModulePath(HMODULE module) { std::vector buffer(MAX_PATH); while (buffer.size() <= PATHCCH_MAX_CCH) { - DWORD len = GetModuleFileNameW(NULL, buffer.data(), buffer.size()); + DWORD len = GetModuleFileNameW(module, buffer.data(), buffer.size()); if (len == 0) return ""; if (len < buffer.size()) { @@ -40,7 +41,6 @@ static std::string GetModulePath(HMODULE module) { /// Returns the full path to the lldb.exe executable. static std::string GetPathToExecutable() { return GetModulePath(NULL); } -#ifdef LLDB_PYTHON_DLL_RELATIVE_PATH bool AddPythonDLLToSearchPath() { std::string path_str = GetPathToExecutable(); if (path_str.empty()) @@ -62,26 +62,31 @@ bool AddPythonDLLToSearchPath() { #endif #ifdef LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME -bool IsPythonDLLInPath() { +std::optional GetPythonDLLPath() { #define WIDEN2(x) L##x #define WIDEN(x) WIDEN2(x) HMODULE h = LoadLibraryW(WIDEN(LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME)); if (!h) - return false; + return std::nullopt; + + std::string path = GetModulePath(h); FreeLibrary(h); - return true; + + return path; #undef WIDEN2 #undef WIDEN } #endif -llvm::Error SetupPythonRuntimeLibrary() { +llvm::Expected SetupPythonRuntimeLibrary() { #ifdef LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME - if (IsPythonDLLInPath()) - return Error::success(); + if (std::optional python_path = GetPythonDLLPath()) + return *python_path; #ifdef LLDB_PYTHON_DLL_RELATIVE_PATH - if (AddPythonDLLToSearchPath() && IsPythonDLLInPath()) - return Error::success(); + if (AddPythonDLLToSearchPath()) { + if (std::optional python_path = GetPythonDLLPath()) + return *python_path; + } #endif return createStringError( inconvertibleErrorCode(), @@ -91,7 +96,7 @@ llvm::Error SetupPythonRuntimeLibrary() { return createStringError(inconvertibleErrorCode(), "unable to find the Python runtime library"); #endif - return Error::success(); + return ""; } // BEGIN SWIFT diff --git a/lldb/tools/driver/Driver.cpp b/lldb/tools/driver/Driver.cpp index b719e9f0d33c3..d8a9692c6c487 100644 --- a/lldb/tools/driver/Driver.cpp +++ b/lldb/tools/driver/Driver.cpp @@ -741,8 +741,10 @@ int main(int argc, char const *argv[]) { #endif #ifdef _WIN32 - if (llvm::Error error = SetupPythonRuntimeLibrary()) { - llvm::WithColor::error() << llvm::toString(std::move(error)) << '\n'; + auto python_path_or_err = SetupPythonRuntimeLibrary(); + if (!python_path_or_err) { + llvm::WithColor::error() + << llvm::toString(std::move(python_path_or_err.takeError())) << '\n'; // BEGIN SWIFT llvm::WithColor::note() << g_python_installation_note; return 1; diff --git a/lldb/tools/lldb-dap/src-ts/debug-configuration-provider.ts b/lldb/tools/lldb-dap/src-ts/debug-configuration-provider.ts index 1e16dac031125..501d925bf1dc3 100644 --- a/lldb/tools/lldb-dap/src-ts/debug-configuration-provider.ts +++ b/lldb/tools/lldb-dap/src-ts/debug-configuration-provider.ts @@ -1,6 +1,7 @@ import * as vscode from "vscode"; import * as child_process from "child_process"; import * as util from "util"; +import * as os from "os"; import { LLDBDapServer } from "./lldb-dap-server"; import { createDebugAdapterExecutable } from "./debug-adapter-factory"; import { ConfigureButton, showErrorMessage } from "./ui/show-error-message"; @@ -70,8 +71,7 @@ const configurations: Record = { }; export class LLDBDapConfigurationProvider - implements vscode.DebugConfigurationProvider -{ + implements vscode.DebugConfigurationProvider { constructor( private readonly server: LLDBDapServer, private readonly logger: vscode.LogOutputChannel, @@ -110,7 +110,7 @@ export class LLDBDapConfigurationProvider ); this.logger.debug( "Initial debug configuration:\n" + - JSON.stringify(debugConfiguration, undefined, 2), + JSON.stringify(debugConfiguration, undefined, 2), ); let config = vscode.workspace.getConfiguration("lldb-dap"); for (const [key, cfg] of Object.entries(configurations)) { @@ -195,6 +195,22 @@ export class LLDBDapConfigurationProvider return undefined; } + if (os.platform() === "win32") { + const pythonCheckProcess = child_process.spawnSync(executable.command, [ + "--check-python", + ]); + if (pythonCheckProcess.status !== 0) { + await vscode.window.showErrorMessage( + "Python is not installed correctly. Please install it to use lldb-dap.", + { + modal: true, + detail: pythonCheckProcess.stderr?.toString() ?? "", + }, + ); + return undefined; + } + } + // Server mode needs to be handled here since DebugAdapterDescriptorFactory // will show an unhelpful error if it returns undefined. We'd rather show a // nicer error message here and allow stopping the debug session gracefully. @@ -222,7 +238,7 @@ export class LLDBDapConfigurationProvider this.logger.info( "Resolved debug configuration:\n" + - JSON.stringify(debugConfiguration, undefined, 2), + JSON.stringify(debugConfiguration, undefined, 2), ); return debugConfiguration; diff --git a/lldb/tools/lldb-dap/tool/Options.td b/lldb/tools/lldb-dap/tool/Options.td index 867753e9294a6..87495e0d56502 100644 --- a/lldb/tools/lldb-dap/tool/Options.td +++ b/lldb/tools/lldb-dap/tool/Options.td @@ -17,6 +17,10 @@ def: Flag<["-"], "v">, Alias, HelpText<"Alias for --version">; +def check_python : F<"check-python">, + HelpText<"Prints the path to the resolved Python DLL. " + "(Windows only).">; + def wait_for_debugger: F<"wait-for-debugger">, HelpText<"Pause the program at startup.">; def: Flag<["-"], "g">, diff --git a/lldb/tools/lldb-dap/tool/lldb-dap.cpp b/lldb/tools/lldb-dap/tool/lldb-dap.cpp index 1e57e6529e0e6..3308e41a4dfed 100644 --- a/lldb/tools/lldb-dap/tool/lldb-dap.cpp +++ b/lldb/tools/lldb-dap/tool/lldb-dap.cpp @@ -475,16 +475,6 @@ int main(int argc, char *argv[]) { "~/Library/Logs/DiagnosticReports/.\n"); #endif -#ifdef _WIN32 - if (llvm::Error error = SetupPythonRuntimeLibrary()) { - llvm::WithColor::error() << llvm::toString(std::move(error)) << '\n'; - // BEGIN SWIFT - llvm::WithColor::note() << g_python_installation_note; - return 1; - // END SWIFT - } -#endif - llvm::SmallString<256> program_path(argv[0]); llvm::sys::fs::make_absolute(program_path); DAP::debug_adapter_path = program_path; @@ -504,6 +494,39 @@ int main(int argc, char *argv[]) { return EXIT_SUCCESS; } +#ifdef _WIN32 + if (input_args.hasArg(OPT_check_python)) { +#ifndef LLDB_ENABLE_PYTHON + llvm::errs() << "lldb-dap was not built with Python support" << '\n'; + return EXIT_SUCCESS; +#endif + auto python_path_or_err = SetupPythonRuntimeLibrary(); + if (!python_path_or_err) { + llvm::WithColor::error() + << llvm::toString(python_path_or_err.takeError()) << '\n'; + return EXIT_FAILURE; + } + std::string python_path = *python_path_or_err; + if (python_path.empty()) { + llvm::WithColor::error() + << "unable to look for the Python shared library" << '\n'; + return EXIT_FAILURE; + } + llvm::outs() << python_path << '\n'; + return EXIT_SUCCESS; + } + + auto python_path_or_err = SetupPythonRuntimeLibrary(); + if (!python_path_or_err) { + llvm::WithColor::error() + << llvm::toString(std::move(python_path_or_err.takeError())) << '\n'; + // BEGIN SWIFT + llvm::WithColor::note() << g_python_installation_note; + return 1; + // END SWIFT + } +#endif + ReplMode default_repl_mode = ReplMode::Auto; if (input_args.hasArg(OPT_repl_mode)) { llvm::opt::Arg *repl_mode = input_args.getLastArg(OPT_repl_mode);