https://github.com/charles-zablit created https://github.com/llvm/llvm-project/pull/179306
https://github.com/llvm/llvm-project/pull/162509 added support for out of PATH python.dll resolution in lldb. This patch does the same thing for `lldb-dap`. This patch extracts the Python resolution code into a library that is used by `lldb-dap` and `lldb` to resolve the Python path and add it to the DLL search paths. If `python.dll` is not found, users get an error message before `lldb-dap` crashes. >From 6a2ec2cc84a5908721bbba818fe5cbaadf7ff529 Mon Sep 17 00:00:00 2001 From: Charles Zablit <[email protected]> Date: Mon, 2 Feb 2026 18:48:46 +0000 Subject: [PATCH] [lldb-dap][windows] add support for out of PATH python.dll resolution --- .../Utility/PythonPathSetup/PythonPathSetup.h | 22 +++++ lldb/source/Utility/CMakeLists.txt | 2 + .../Utility/PythonPathSetup/CMakeLists.txt | 13 +++ .../PythonPathSetup/PythonPathSetup.cpp | 99 +++++++++++++++++++ lldb/tools/driver/CMakeLists.txt | 8 +- lldb/tools/driver/Driver.cpp | 87 +--------------- lldb/tools/lldb-dap/tool/CMakeLists.txt | 2 + lldb/tools/lldb-dap/tool/lldb-dap.cpp | 3 + 8 files changed, 143 insertions(+), 93 deletions(-) create mode 100644 lldb/include/lldb/Utility/PythonPathSetup/PythonPathSetup.h create mode 100644 lldb/source/Utility/PythonPathSetup/CMakeLists.txt create mode 100644 lldb/source/Utility/PythonPathSetup/PythonPathSetup.cpp diff --git a/lldb/include/lldb/Utility/PythonPathSetup/PythonPathSetup.h b/lldb/include/lldb/Utility/PythonPathSetup/PythonPathSetup.h new file mode 100644 index 0000000000000..e0ad73f62f110 --- /dev/null +++ b/lldb/include/lldb/Utility/PythonPathSetup/PythonPathSetup.h @@ -0,0 +1,22 @@ +//===-- PythonPathSetup.h -------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_UTILITY_PYTHONPATHSETUP_H +#define LLDB_SOURCE_UTILITY_PYTHONPATHSETUP_H + +/// Try to setup the DLL search path for the Python Runtime Library +/// (python3xx.dll). +/// +/// If `LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME` is set, we first check if +/// python3xx.dll is in the search path. If it's not, we try to add it and +/// check for it a second time. +/// If only `LLDB_PYTHON_DLL_RELATIVE_PATH` is set, we try to add python3xx.dll +/// to the search path python.dll is already in the search path or not. +void SetupPythonRuntimeLibrary(); + +#endif // LLDB_SOURCE_UTILITY_PYTHONPATHSETUP_H diff --git a/lldb/source/Utility/CMakeLists.txt b/lldb/source/Utility/CMakeLists.txt index 04f1692e53b35..bb925760a8ee9 100644 --- a/lldb/source/Utility/CMakeLists.txt +++ b/lldb/source/Utility/CMakeLists.txt @@ -1,3 +1,5 @@ +add_subdirectory(PythonPathSetup) + set(LLDB_SYSTEM_LIBS) if (APPLE) diff --git a/lldb/source/Utility/PythonPathSetup/CMakeLists.txt b/lldb/source/Utility/PythonPathSetup/CMakeLists.txt new file mode 100644 index 0000000000000..78dd861a6551f --- /dev/null +++ b/lldb/source/Utility/PythonPathSetup/CMakeLists.txt @@ -0,0 +1,13 @@ +add_lldb_library(lldbUtilityPythonPathSetup STATIC + PythonPathSetup.cpp + + LINK_LIBS + LLVMSupport +) + +if(DEFINED LLDB_PYTHON_DLL_RELATIVE_PATH) + target_compile_definitions(lldbUtilityPythonPathSetup PRIVATE LLDB_PYTHON_DLL_RELATIVE_PATH="${LLDB_PYTHON_DLL_RELATIVE_PATH}") +endif() +if(DEFINED LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME) + target_compile_definitions(lldbUtilityPythonPathSetup PRIVATE LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME="${LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME}") +endif() diff --git a/lldb/source/Utility/PythonPathSetup/PythonPathSetup.cpp b/lldb/source/Utility/PythonPathSetup/PythonPathSetup.cpp new file mode 100644 index 0000000000000..b63de6ec137b8 --- /dev/null +++ b/lldb/source/Utility/PythonPathSetup/PythonPathSetup.cpp @@ -0,0 +1,99 @@ +//===-- PythonPathSetup.cpp -----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "lldb/Utility/PythonPathSetup/PythonPathSetup.h" + +#ifdef _WIN32 +#include "lldb/Host/windows/windows.h" +#include "llvm/Support/Windows/WindowsSupport.h" + +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/ConvertUTF.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/WithColor.h" + +using namespace llvm; + +#ifdef LLDB_PYTHON_DLL_RELATIVE_PATH +/// Returns the full path to the lldb.exe executable. +inline std::wstring GetPathToExecutableW() { + // Iterate until we reach the Windows API maximum path length (32,767). + std::vector<WCHAR> buffer; + buffer.resize(MAX_PATH /*=260*/); + while (buffer.size() < 32767) { + if (GetModuleFileNameW(NULL, buffer.data(), buffer.size()) < buffer.size()) + return std::wstring(buffer.begin(), buffer.end()); + buffer.resize(buffer.size() * 2); + } + return L""; +} + +/// \brief Resolve the full path of the directory defined by +/// LLDB_PYTHON_DLL_RELATIVE_PATH. If it exists, add it to the list of DLL +/// search directories. +/// \return `true` if the library was added to the search path. +/// `false` otherwise. +bool AddPythonDLLToSearchPath() { + std::wstring modulePath = GetPathToExecutableW(); + if (modulePath.empty()) + return false; + + SmallVector<char, MAX_PATH> utf8Path; + if (sys::windows::UTF16ToUTF8(modulePath.c_str(), modulePath.length(), + utf8Path)) + return false; + sys::path::remove_filename(utf8Path); + sys::path::append(utf8Path, LLDB_PYTHON_DLL_RELATIVE_PATH); + sys::fs::make_absolute(utf8Path); + + SmallVector<wchar_t, 1> widePath; + if (sys::windows::widenPath(utf8Path.data(), widePath)) + return false; + + if (sys::fs::exists(utf8Path)) + return SetDllDirectoryW(widePath.data()); + return false; +} +#endif + +#ifdef LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME +/// Returns true if `python3x.dll` can be loaded. +static bool IsPythonDLLInPath() { +#define WIDEN2(x) L##x +#define WIDEN(x) WIDEN2(x) + HMODULE h = LoadLibraryW(WIDEN(LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME)); + if (!h) + return false; + FreeLibrary(h); + return true; +#undef WIDEN2 +#undef WIDEN +} +#endif + +#endif // _WIN32 + +void SetupPythonRuntimeLibrary() { +#ifdef _WIN32 +#ifdef LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME + if (IsPythonDLLInPath()) + return; +#ifdef LLDB_PYTHON_DLL_RELATIVE_PATH + if (AddPythonDLLToSearchPath() && IsPythonDLLInPath()) + return; +#endif + WithColor::error() << "unable to find '" + << LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME << "'.\n"; + return; +#elif defined(LLDB_PYTHON_DLL_RELATIVE_PATH) + if (!AddPythonDLLToSearchPath()) + WithColor::error() << "unable to find the Python runtime library.\n"; +#endif +#endif // _WIN32 +} diff --git a/lldb/tools/driver/CMakeLists.txt b/lldb/tools/driver/CMakeLists.txt index efe51506f3545..c0973b81368d8 100644 --- a/lldb/tools/driver/CMakeLists.txt +++ b/lldb/tools/driver/CMakeLists.txt @@ -24,6 +24,7 @@ add_lldb_tool(lldb Option Support LINK_LIBS + lldbUtilityPythonPathSetup liblldb lldbHost lldbUtility @@ -34,13 +35,6 @@ add_dependencies(lldb ${tablegen_deps} ) -if(DEFINED LLDB_PYTHON_DLL_RELATIVE_PATH) - target_compile_definitions(lldb PRIVATE LLDB_PYTHON_DLL_RELATIVE_PATH="${LLDB_PYTHON_DLL_RELATIVE_PATH}") -endif() -if(DEFINED LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME) - target_compile_definitions(lldb PRIVATE LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME="${LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME}") -endif() - if(LLDB_BUILD_FRAMEWORK) # In the build-tree, we know the exact path to the framework directory. # The installed framework can be in different locations. diff --git a/lldb/tools/driver/Driver.cpp b/lldb/tools/driver/Driver.cpp index 48107717abd31..62dda80fec618 100644 --- a/lldb/tools/driver/Driver.cpp +++ b/lldb/tools/driver/Driver.cpp @@ -21,6 +21,7 @@ #include "lldb/Host/Config.h" #include "lldb/Host/MainLoop.h" #include "lldb/Host/MainLoopBase.h" +#include "lldb/Utility/PythonPathSetup/PythonPathSetup.h" #include "lldb/Utility/Status.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" @@ -433,90 +434,6 @@ SBError Driver::ProcessArgs(const opt::InputArgList &args, bool &exiting) { return error; } -#ifdef _WIN32 -#ifdef LLDB_PYTHON_DLL_RELATIVE_PATH -/// Returns the full path to the lldb.exe executable. -inline std::wstring GetPathToExecutableW() { - // Iterate until we reach the Windows API maximum path length (32,767). - std::vector<WCHAR> buffer; - buffer.resize(MAX_PATH /*=260*/); - while (buffer.size() < 32767) { - if (GetModuleFileNameW(NULL, buffer.data(), buffer.size()) < buffer.size()) - return std::wstring(buffer.begin(), buffer.end()); - buffer.resize(buffer.size() * 2); - } - return L""; -} - -/// \brief Resolve the full path of the directory defined by -/// LLDB_PYTHON_DLL_RELATIVE_PATH. If it exists, add it to the list of DLL -/// search directories. -/// \return `true` if the library was added to the search path. -/// `false` otherwise. -bool AddPythonDLLToSearchPath() { - std::wstring modulePath = GetPathToExecutableW(); - if (modulePath.empty()) - return false; - - SmallVector<char, MAX_PATH> utf8Path; - if (sys::windows::UTF16ToUTF8(modulePath.c_str(), modulePath.length(), - utf8Path)) - return false; - sys::path::remove_filename(utf8Path); - sys::path::append(utf8Path, LLDB_PYTHON_DLL_RELATIVE_PATH); - sys::fs::make_absolute(utf8Path); - - SmallVector<wchar_t, 1> widePath; - if (sys::windows::widenPath(utf8Path.data(), widePath)) - return false; - - if (sys::fs::exists(utf8Path)) - return SetDllDirectoryW(widePath.data()); - return false; -} -#endif - -#ifdef LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME -/// Returns true if `python3x.dll` can be loaded. -bool IsPythonDLLInPath() { -#define WIDEN2(x) L##x -#define WIDEN(x) WIDEN2(x) - HMODULE h = LoadLibraryW(WIDEN(LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME)); - if (!h) - return false; - FreeLibrary(h); - return true; -#undef WIDEN2 -#undef WIDEN -} -#endif - -/// Try to setup the DLL search path for the Python Runtime Library -/// (python3xx.dll). -/// -/// If `LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME` is set, we first check if -/// python3xx.dll is in the search path. If it's not, we try to add it and -/// check for it a second time. -/// If only `LLDB_PYTHON_DLL_RELATIVE_PATH` is set, we try to add python3xx.dll -/// to the search path python.dll is already in the search path or not. -void SetupPythonRuntimeLibrary() { -#ifdef LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME - if (IsPythonDLLInPath()) - return; -#ifdef LLDB_PYTHON_DLL_RELATIVE_PATH - if (AddPythonDLLToSearchPath() && IsPythonDLLInPath()) - return; -#endif - WithColor::error() << "unable to find '" - << LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME << "'.\n"; - return; -#elif defined(LLDB_PYTHON_DLL_RELATIVE_PATH) - if (!AddPythonDLLToSearchPath()) - WithColor::error() << "unable to find the Python runtime library.\n"; -#endif -} -#endif - std::string EscapeString(std::string arg) { std::string::size_type pos = 0; while ((pos = arg.find_first_of("\"\\", pos)) != std::string::npos) { @@ -819,9 +736,7 @@ int main(int argc, char const *argv[]) { "~/Library/Logs/DiagnosticReports/.\n"); #endif -#ifdef _WIN32 SetupPythonRuntimeLibrary(); -#endif // Parse arguments. LLDBOptTable T; diff --git a/lldb/tools/lldb-dap/tool/CMakeLists.txt b/lldb/tools/lldb-dap/tool/CMakeLists.txt index 692aeedd9531b..d75ac02b67708 100644 --- a/lldb/tools/lldb-dap/tool/CMakeLists.txt +++ b/lldb/tools/lldb-dap/tool/CMakeLists.txt @@ -6,6 +6,8 @@ add_lldb_tool(lldb-dap lldb-dap.cpp LINK_LIBS + lldbUtilityPythonPathSetup + liblldb # delay load liblldb lldbDAP ) diff --git a/lldb/tools/lldb-dap/tool/lldb-dap.cpp b/lldb/tools/lldb-dap/tool/lldb-dap.cpp index 15c63543e86f5..ede0719b0d7da 100644 --- a/lldb/tools/lldb-dap/tool/lldb-dap.cpp +++ b/lldb/tools/lldb-dap/tool/lldb-dap.cpp @@ -24,6 +24,7 @@ #include "lldb/Host/MemoryMonitor.h" #include "lldb/Host/Socket.h" #include "lldb/Utility/AnsiTerminal.h" +#include "lldb/Utility/PythonPathSetup/PythonPathSetup.h" #include "lldb/Utility/Status.h" #include "lldb/Utility/UriParser.h" #include "lldb/lldb-forward.h" @@ -523,6 +524,8 @@ int main(int argc, char *argv[]) { "~/Library/Logs/DiagnosticReports/.\n"); #endif + SetupPythonRuntimeLibrary(); + llvm::SmallString<256> program_path(argv[0]); llvm::sys::fs::make_absolute(program_path); DAP::debug_adapter_path = program_path; _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
