Author: Charles Zablit
Date: 2026-02-10T16:45:36+01:00
New Revision: 67e571df8c274f6e5357e822d79ca2c34c0056c4

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

LOG: [lldb-dap][windows] add support for out of PATH python.dll resolution 
(#179306)

Added: 
    lldb/include/lldb/Host/windows/PythonPathSetup/PythonPathSetup.h
    lldb/source/Host/windows/PythonPathSetup/CMakeLists.txt
    lldb/source/Host/windows/PythonPathSetup/PythonPathSetup.cpp

Modified: 
    lldb/CMakeLists.txt
    lldb/source/Host/CMakeLists.txt
    lldb/tools/driver/CMakeLists.txt
    lldb/tools/driver/Driver.cpp
    lldb/tools/lldb-dap/tool/CMakeLists.txt
    lldb/tools/lldb-dap/tool/lldb-dap.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/CMakeLists.txt b/lldb/CMakeLists.txt
index 0736e6ba132c8..0a1ca5cf391ef 100644
--- a/lldb/CMakeLists.txt
+++ b/lldb/CMakeLists.txt
@@ -61,6 +61,10 @@ if (LLDB_ENABLE_PYTHON)
     "Path to python interpreter exectuable, relative to python's install 
prefix")
   set(cachestring_LLDB_PYTHON_EXT_SUFFIX
     "Filename extension for native code python modules")
+  set(cachestring_LLDB_PYTHON_DLL_RELATIVE_PATH
+    "Relative path from LLDB executable to Python DLL directory (Windows 
only)")
+  set(cachestring_LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME
+    "Filename of Python runtime library to search for, e.g. python311.dll 
(Windows only)")
 
   if (LLDB_ENABLE_PYTHON_LIMITED_API)
     set(stable_abi "--stable-abi")

diff  --git a/lldb/include/lldb/Host/windows/PythonPathSetup/PythonPathSetup.h 
b/lldb/include/lldb/Host/windows/PythonPathSetup/PythonPathSetup.h
new file mode 100644
index 0000000000000..5016e35304f70
--- /dev/null
+++ b/lldb/include/lldb/Host/windows/PythonPathSetup/PythonPathSetup.h
@@ -0,0 +1,47 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_HOST_PYTHONPATHSETUP_H
+#define LLDB_SOURCE_HOST_PYTHONPATHSETUP_H
+
+#include "llvm/Support/Error.h"
+
+#ifdef LLDB_PYTHON_DLL_RELATIVE_PATH
+/// 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();
+#endif
+
+/// Attempts to setup the DLL search path for the Python runtime library.
+///
+/// In the following paragraphs, python3xx.dll refers to the Python runtime
+/// library name which is defined by LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME, e.g.
+/// python311.dll for Python 3.11.
+///
+/// The setup flow depends on which macros are defined:
+///
+/// - If only LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME is defined, checks whether
+///   python3xx.dll can be loaded. Returns an error if it cannot.
+///
+/// - If only LLDB_PYTHON_DLL_RELATIVE_PATH is defined, attempts to resolve the
+///   relative path and add it to the DLL search path. Returns an error if this
+///   fails. Note that this may succeed even if python3xx.dll is not present in
+///   the added search path.
+///
+/// - If both LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME and
+///   LLDB_PYTHON_DLL_RELATIVE_PATH are defined, first checks if python3xx.dll
+///   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();
+
+#endif // LLDB_SOURCE_HOST_PYTHONPATHSETUP_H

diff  --git a/lldb/source/Host/CMakeLists.txt b/lldb/source/Host/CMakeLists.txt
index 8ad485fa40285..8c198c655e0a6 100644
--- a/lldb/source/Host/CMakeLists.txt
+++ b/lldb/source/Host/CMakeLists.txt
@@ -65,6 +65,7 @@ add_host_subdirectory(posix
   )
 
 if (CMAKE_SYSTEM_NAME MATCHES "Windows")
+  add_subdirectory(windows/PythonPathSetup)
   add_host_subdirectory(windows
     windows/ConnectionGenericFileWindows.cpp
     windows/FileSystem.cpp

diff  --git a/lldb/source/Host/windows/PythonPathSetup/CMakeLists.txt 
b/lldb/source/Host/windows/PythonPathSetup/CMakeLists.txt
new file mode 100644
index 0000000000000..6b84a7187160b
--- /dev/null
+++ b/lldb/source/Host/windows/PythonPathSetup/CMakeLists.txt
@@ -0,0 +1,13 @@
+add_lldb_library(lldbHostPythonPathSetup STATIC
+  PythonPathSetup.cpp
+
+  LINK_LIBS
+    LLVMSupport
+)
+
+if(DEFINED LLDB_PYTHON_DLL_RELATIVE_PATH)
+  target_compile_definitions(lldbHostPythonPathSetup PRIVATE 
LLDB_PYTHON_DLL_RELATIVE_PATH="${LLDB_PYTHON_DLL_RELATIVE_PATH}")
+endif()
+if(DEFINED LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME)
+  target_compile_definitions(lldbHostPythonPathSetup PRIVATE 
LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME="${LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME}")
+endif()

diff  --git a/lldb/source/Host/windows/PythonPathSetup/PythonPathSetup.cpp 
b/lldb/source/Host/windows/PythonPathSetup/PythonPathSetup.cpp
new file mode 100644
index 0000000000000..d378e6984b056
--- /dev/null
+++ b/lldb/source/Host/windows/PythonPathSetup/PythonPathSetup.cpp
@@ -0,0 +1,92 @@
+//===----------------------------------------------------------------------===//
+//
+// 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/Host/windows/PythonPathSetup/PythonPathSetup.h"
+
+#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 <pathcch.h>
+
+using namespace llvm;
+
+#ifdef LLDB_PYTHON_DLL_RELATIVE_PATH
+/// Returns the full path to the lldb.exe executable.
+static std::wstring GetPathToExecutableW() {
+  std::vector<WCHAR> buffer(MAX_PATH);
+  while (buffer.size() <= PATHCCH_MAX_CCH) {
+    DWORD len = GetModuleFileNameW(NULL, buffer.data(), buffer.size());
+    if (len == 0)
+      return L"";
+    if (len < buffer.size())
+      return std::wstring(buffer.data(), len);
+    if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER)
+      buffer.resize(buffer.size() * 2);
+  }
+  return L"";
+}
+
+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
+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
+
+llvm::Error SetupPythonRuntimeLibrary() {
+#ifdef LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME
+  if (IsPythonDLLInPath())
+    return Error::success();
+#ifdef LLDB_PYTHON_DLL_RELATIVE_PATH
+  if (AddPythonDLLToSearchPath() && IsPythonDLLInPath())
+    return Error::success();
+#endif
+  return createStringError(
+      inconvertibleErrorCode(),
+      "unable to find '" LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME "'");
+#elif defined(LLDB_PYTHON_DLL_RELATIVE_PATH)
+  if (!AddPythonDLLToSearchPath())
+    return createStringError(inconvertibleErrorCode(),
+                             "unable to find the Python runtime library");
+#endif
+  return Error::success();
+}

diff  --git a/lldb/tools/driver/CMakeLists.txt 
b/lldb/tools/driver/CMakeLists.txt
index efe51506f3545..7043f648518d6 100644
--- a/lldb/tools/driver/CMakeLists.txt
+++ b/lldb/tools/driver/CMakeLists.txt
@@ -16,6 +16,16 @@ if (UNIX AND "${CMAKE_SYSTEM_NAME}" MATCHES "AIX")
   add_definitions("-D_ALL_SOURCE")                                             
 endif()
 
+set(LLDB_DRIVER_LINK_LIBS
+  liblldb
+  lldbHost
+  lldbUtility
+)
+
+if(WIN32)
+  list(APPEND LLDB_DRIVER_LINK_LIBS lldbHostPythonPathSetup)
+endif()
+
 add_lldb_tool(lldb
   Driver.cpp
   Platform.cpp
@@ -24,9 +34,7 @@ add_lldb_tool(lldb
     Option
     Support
   LINK_LIBS
-    liblldb
-    lldbHost
-    lldbUtility
+    ${LLDB_DRIVER_LINK_LIBS}
   )
 
 add_dependencies(lldb
@@ -34,13 +42,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 
diff erent locations.

diff  --git a/lldb/tools/driver/Driver.cpp b/lldb/tools/driver/Driver.cpp
index 72ed9d02930d4..1f333cea9b50d 100644
--- a/lldb/tools/driver/Driver.cpp
+++ b/lldb/tools/driver/Driver.cpp
@@ -34,7 +34,7 @@
 #include "llvm/Support/raw_ostream.h"
 
 #ifdef _WIN32
-#include "llvm/Support/Windows/WindowsSupport.h"
+#include "lldb/Host/windows/PythonPathSetup/PythonPathSetup.h"
 #endif
 
 #include <algorithm>
@@ -433,90 +433,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) {
@@ -821,7 +737,8 @@ int main(int argc, char const *argv[]) {
 #endif
 
 #ifdef _WIN32
-  SetupPythonRuntimeLibrary();
+  if (llvm::Error error = SetupPythonRuntimeLibrary())
+    llvm::WithColor::error() << llvm::toString(std::move(error)) << '\n';
 #endif
 
   // Parse arguments.

diff  --git a/lldb/tools/lldb-dap/tool/CMakeLists.txt 
b/lldb/tools/lldb-dap/tool/CMakeLists.txt
index 692aeedd9531b..2216e54064bf3 100644
--- a/lldb/tools/lldb-dap/tool/CMakeLists.txt
+++ b/lldb/tools/lldb-dap/tool/CMakeLists.txt
@@ -2,11 +2,18 @@ set(LLVM_TARGET_DEFINITIONS Options.td)
 tablegen(LLVM Options.inc -gen-opt-parser-defs)
 add_public_tablegen_target(LLDBDAPOptionsTableGen)
 
+set(LLDB_DAP_LINK_LIBS lldbDAP)
+
+if(WIN32)
+  list(APPEND LLDB_DAP_LINK_LIBS lldbHostPythonPathSetup)
+  list(APPEND LLDB_DAP_LINK_LIBS liblldb)
+endif()
+
 add_lldb_tool(lldb-dap
   lldb-dap.cpp
 
   LINK_LIBS
-    lldbDAP
+    ${LLDB_DAP_LINK_LIBS}
   )
 
 add_dependencies(lldb-dap

diff  --git a/lldb/tools/lldb-dap/tool/lldb-dap.cpp 
b/lldb/tools/lldb-dap/tool/lldb-dap.cpp
index babc3c98646cb..bfd7c5d39ec4a 100644
--- a/lldb/tools/lldb-dap/tool/lldb-dap.cpp
+++ b/lldb/tools/lldb-dap/tool/lldb-dap.cpp
@@ -70,6 +70,7 @@
 #undef GetObject
 #include <io.h>
 typedef int socklen_t;
+#include "lldb/Host/windows/PythonPathSetup/PythonPathSetup.h"
 #else
 #include <netinet/in.h>
 #include <sys/socket.h>
@@ -522,6 +523,11 @@ 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';
+#endif
+
   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

Reply via email to