[Lldb-commits] [lldb] [lldb] Drop client-side Python pre-load and remove PythonPathSetup (PR #200533)
Jonas Devlieghere via lldb-commits
lldb-commits at lists.llvm.org
Tue Jun 2 16:59:38 PDT 2026
https://github.com/JDevlieghere updated https://github.com/llvm/llvm-project/pull/200533
>From f09d496bf7608c1ad41c04efee2d0a43ceaa1497 Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <jonas at devlieghere.com>
Date: Tue, 2 Jun 2026 16:59:20 -0700
Subject: [PATCH] [lldb] Replace PythonPathSetup with
ScriptInterpreterRuntimeLoader
PythonPathSetup was a Windows-only helper that pre-mapped python3xx.dll
into lldb.exe / lldb-dap.exe so liblldb.dll's direct imports from
python3xx.dll would resolve when the delay-load thunk for liblldb fired
on the first SB call. ScriptInterpreterRuntimeLoader's Windows backend
has subsumed that responsibility, so this commit deletes the helper and
rewrites the two clients on the new API.
The Windows pre-load itself stays in the clients: the central load in
SystemInitializerFull::Initialize() lives behind the liblldb.dll thunk
that the import binding fires against, so the loader still has to run
from the binary that statically links lldbHost (lldb.exe / lldb-dap.exe)
before the first SB call lands.
- lldb driver: rewrites the Windows pre-load on
ScriptInterpreterRuntimeLoader::Get(eScriptLanguagePython)->Load()
and drops the lldbHostPythonPathSetup link dep.
- lldb-dap: same rewrite, with the pre-load moved before PrintVersion so
`--version` (which calls SBDebugger::GetVersionString()) works on
Windows. --check-python is rewritten on the loader's instance API,
including the Expected<StringRef> return from GetLoadedPath().
- lldb/Host/windows/PythonPathSetup (header, source, CMakeLists.txt) is
deleted, and lldb/source/Host/CMakeLists.txt drops its
add_subdirectory.
---
.../windows/PythonPathSetup/PythonPathSetup.h | 52 ---------
lldb/source/Host/CMakeLists.txt | 1 -
.../windows/PythonPathSetup/CMakeLists.txt | 10 --
.../PythonPathSetup/PythonPathSetup.cpp | 103 ------------------
lldb/tools/driver/CMakeLists.txt | 4 -
lldb/tools/driver/Driver.cpp | 27 +++--
lldb/tools/lldb-dap/tool/CMakeLists.txt | 4 -
lldb/tools/lldb-dap/tool/lldb-dap.cpp | 45 ++++++--
8 files changed, 52 insertions(+), 194 deletions(-)
delete mode 100644 lldb/include/lldb/Host/windows/PythonPathSetup/PythonPathSetup.h
delete mode 100644 lldb/source/Host/windows/PythonPathSetup/CMakeLists.txt
delete mode 100644 lldb/source/Host/windows/PythonPathSetup/PythonPathSetup.cpp
diff --git a/lldb/include/lldb/Host/windows/PythonPathSetup/PythonPathSetup.h b/lldb/include/lldb/Host/windows/PythonPathSetup/PythonPathSetup.h
deleted file mode 100644
index ca46c8b823cd1..0000000000000
--- a/lldb/include/lldb/Host/windows/PythonPathSetup/PythonPathSetup.h
+++ /dev/null
@@ -1,52 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// 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.
-///
-/// \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<std::string> SetupPythonRuntimeLibrary();
-
-#endif // LLDB_SOURCE_HOST_PYTHONPATHSETUP_H
diff --git a/lldb/source/Host/CMakeLists.txt b/lldb/source/Host/CMakeLists.txt
index 7d26659b9d6c1..28c639ee38215 100644
--- a/lldb/source/Host/CMakeLists.txt
+++ b/lldb/source/Host/CMakeLists.txt
@@ -76,7 +76,6 @@ add_host_subdirectory(posix
)
if (CMAKE_SYSTEM_NAME MATCHES "Windows")
- add_subdirectory(windows/PythonPathSetup)
add_host_subdirectory(windows
windows/ConnectionConPTYWindows.cpp
windows/ConnectionGenericFileWindows.cpp
diff --git a/lldb/source/Host/windows/PythonPathSetup/CMakeLists.txt b/lldb/source/Host/windows/PythonPathSetup/CMakeLists.txt
deleted file mode 100644
index 96f2b482b376f..0000000000000
--- a/lldb/source/Host/windows/PythonPathSetup/CMakeLists.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-add_lldb_library(lldbHostPythonPathSetup STATIC
- PythonPathSetup.cpp
-)
-
-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
deleted file mode 100644
index 0da2267e8c78a..0000000000000
--- a/lldb/source/Host/windows/PythonPathSetup/PythonPathSetup.cpp
+++ /dev/null
@@ -1,103 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// 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;
-
-#if defined(LLDB_PYTHON_DLL_RELATIVE_PATH) || \
- defined(LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME)
-static std::string GetModulePath(HMODULE module) {
- std::vector<WCHAR> buffer(MAX_PATH);
- while (buffer.size() <= PATHCCH_MAX_CCH) {
- DWORD len = GetModuleFileNameW(module, buffer.data(), buffer.size());
- if (len == 0)
- return "";
- if (len < buffer.size()) {
- std::string buffer_utf8;
- if (convertWideToUTF8(std::wstring(buffer.data(), len), buffer_utf8))
- return buffer_utf8;
- return "";
- }
- if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER)
- buffer.resize(buffer.size() * 2);
- }
- return "";
-}
-#endif
-
-#ifdef LLDB_PYTHON_DLL_RELATIVE_PATH
-/// Returns the full path to the lldb.exe executable.
-static std::string GetPathToExecutable() { return GetModulePath(nullptr); }
-
-bool AddPythonDLLToSearchPath() {
- std::string path_str = GetPathToExecutable();
- if (path_str.empty())
- return false;
-
- SmallVector<char, MAX_PATH> path(path_str.begin(), path_str.end());
- sys::path::remove_filename(path);
- sys::path::append(path, LLDB_PYTHON_DLL_RELATIVE_PATH);
- sys::fs::make_absolute(path);
-
- SmallVector<wchar_t, 1> path_wide;
- if (sys::windows::widenPath(path.data(), path_wide))
- return false;
-
- if (sys::fs::exists(path))
- return SetDllDirectoryW(path_wide.data());
- return false;
-}
-#endif
-
-#ifdef LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME
-std::optional<std::string> GetPythonDLLPath() {
-#define WIDEN2(x) L##x
-#define WIDEN(x) WIDEN2(x)
- HMODULE h = LoadLibraryW(WIDEN(LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME));
- if (!h)
- return std::nullopt;
-
- std::string path = GetModulePath(h);
- FreeLibrary(h);
-
- return path;
-#undef WIDEN2
-#undef WIDEN
-}
-#endif
-
-llvm::Expected<std::string> SetupPythonRuntimeLibrary() {
-#ifdef LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME
- if (std::optional<std::string> python_path = GetPythonDLLPath())
- return *python_path;
-#ifdef LLDB_PYTHON_DLL_RELATIVE_PATH
- if (AddPythonDLLToSearchPath()) {
- if (std::optional<std::string> python_path = GetPythonDLLPath())
- return *python_path;
- }
-#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 "";
-}
diff --git a/lldb/tools/driver/CMakeLists.txt b/lldb/tools/driver/CMakeLists.txt
index 1c93ed9fad927..0534ddc9a58c3 100644
--- a/lldb/tools/driver/CMakeLists.txt
+++ b/lldb/tools/driver/CMakeLists.txt
@@ -34,10 +34,6 @@ set(LLDB_DRIVER_LINK_LIBS
lldbUtility
)
-if(WIN32)
- list(APPEND LLDB_DRIVER_LINK_LIBS lldbHostPythonPathSetup)
-endif()
-
add_lldb_tool(lldb
Driver.cpp
Platform.cpp
diff --git a/lldb/tools/driver/Driver.cpp b/lldb/tools/driver/Driver.cpp
index e58286f9ff41e..2bb77d275138e 100644
--- a/lldb/tools/driver/Driver.cpp
+++ b/lldb/tools/driver/Driver.cpp
@@ -34,7 +34,10 @@
#include "llvm/Support/raw_ostream.h"
#ifdef _WIN32
-#include "lldb/Host/windows/PythonPathSetup/PythonPathSetup.h"
+#include "lldb/Host/Config.h"
+#if LLDB_ENABLE_PYTHON
+#include "lldb/Host/ScriptInterpreterRuntimeLoader.h"
+#endif
#endif
#include <algorithm>
@@ -735,13 +738,6 @@ int main(int argc, char const *argv[]) {
"~/Library/Logs/DiagnosticReports/.\n");
#endif
-#ifdef _WIN32
- auto python_path_or_err = SetupPythonRuntimeLibrary();
- if (!python_path_or_err)
- llvm::WithColor::error()
- << llvm::toString(python_path_or_err.takeError()) << '\n';
-#endif
-
// Parse arguments.
LLDBOptTable T;
unsigned MissingArgIndex;
@@ -774,6 +770,21 @@ int main(int argc, char const *argv[]) {
return 1;
}
+#if defined(_WIN32) && LLDB_ENABLE_PYTHON
+ // liblldb.dll has direct imports from python3xx.dll (the script interpreter
+ // plugin is statically linked into liblldb), so the loader needs to find
+ // python3xx.dll before lldb.exe's delay-load thunk for liblldb fires on the
+ // first SB call below. The runtime loader is statically linked into lldb.exe
+ // via lldbHost (it has no LLDB_API export), so this call does not itself
+ // trigger the liblldb.dll load.
+ llvm::Expected<lldb_private::ScriptInterpreterRuntimeLoader &> python_loader =
+ lldb_private::ScriptInterpreterRuntimeLoader::Get(eScriptLanguagePython);
+ if (!python_loader)
+ WithColor::warning() << llvm::toString(python_loader.takeError()) << '\n';
+ else if (llvm::Error err = python_loader->Load())
+ WithColor::warning() << llvm::toString(std::move(err)) << '\n';
+#endif
+
SBError error = SBDebugger::InitializeWithErrorHandling();
if (error.Fail()) {
WithColor::error() << "initialization failed: " << error.GetCString()
diff --git a/lldb/tools/lldb-dap/tool/CMakeLists.txt b/lldb/tools/lldb-dap/tool/CMakeLists.txt
index fbd3cf0cd4377..33263cb5adb6b 100644
--- a/lldb/tools/lldb-dap/tool/CMakeLists.txt
+++ b/lldb/tools/lldb-dap/tool/CMakeLists.txt
@@ -4,10 +4,6 @@ add_public_tablegen_target(LLDBDAPOptionsTableGen)
set(LLDB_DAP_LINK_LIBS lldbDAP liblldb lldbHost)
-if(WIN32)
- list(APPEND LLDB_DAP_LINK_LIBS lldbHostPythonPathSetup)
-endif()
-
add_lldb_tool(lldb-dap
lldb-dap.cpp
diff --git a/lldb/tools/lldb-dap/tool/lldb-dap.cpp b/lldb/tools/lldb-dap/tool/lldb-dap.cpp
index c78eb2d1f23a7..0882e593dc330 100644
--- a/lldb/tools/lldb-dap/tool/lldb-dap.cpp
+++ b/lldb/tools/lldb-dap/tool/lldb-dap.cpp
@@ -75,8 +75,8 @@
#undef GetObject
#include <io.h>
typedef int socklen_t;
+#include "lldb/Host/ScriptInterpreterRuntimeLoader.h"
#include "lldb/Host/windows/ProcessLauncherWindows.h"
-#include "lldb/Host/windows/PythonPathSetup/PythonPathSetup.h"
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/Program.h"
#else
@@ -760,6 +760,22 @@ int main(int argc, char *argv[]) {
return EXIT_SUCCESS;
}
+#if defined(_WIN32) && LLDB_ENABLE_PYTHON
+ // liblldb.dll has direct imports from python3xx.dll, so pre-load the Python
+ // runtime before any SB call (PrintVersion below, SBDebugger::Initialize
+ // later) triggers lldb-dap.exe's delay-load thunk for liblldb.dll. The
+ // runtime loader is statically linked into lldb-dap.exe via lldbHost (no
+ // LLDB_API export), so this call does not itself trigger the load.
+ llvm::Expected<lldb_private::ScriptInterpreterRuntimeLoader &> python_loader =
+ lldb_private::ScriptInterpreterRuntimeLoader::Get(
+ lldb::eScriptLanguagePython);
+ if (!python_loader)
+ llvm::WithColor::warning()
+ << llvm::toString(python_loader.takeError()) << '\n';
+ else if (llvm::Error err = python_loader->Load())
+ llvm::WithColor::warning() << llvm::toString(std::move(err)) << '\n';
+#endif
+
if (input_args.hasArg(OPT_version)) {
PrintVersion();
return EXIT_SUCCESS;
@@ -771,26 +787,31 @@ int main(int argc, char *argv[]) {
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::Expected<lldb_private::ScriptInterpreterRuntimeLoader &> loader =
+ lldb_private::ScriptInterpreterRuntimeLoader::Get(
+ lldb::eScriptLanguagePython);
+ if (!loader) {
+ llvm::WithColor::error() << llvm::toString(loader.takeError()) << '\n';
+ return EXIT_FAILURE;
+ }
+ if (llvm::Error err = loader->Load()) {
+ llvm::WithColor::error() << llvm::toString(std::move(err)) << '\n';
+ return EXIT_FAILURE;
+ }
+ llvm::Expected<llvm::StringRef> python_path = loader->GetLoadedPath();
+ if (!python_path) {
llvm::WithColor::error()
- << llvm::toString(python_path_or_err.takeError()) << '\n';
+ << llvm::toString(python_path.takeError()) << '\n';
return EXIT_FAILURE;
}
- std::string python_path = *python_path_or_err;
- if (python_path.empty()) {
+ if (python_path->empty()) {
llvm::WithColor::error()
<< "unable to look for the Python shared library" << '\n';
return EXIT_FAILURE;
}
- llvm::outs() << python_path << '\n';
+ llvm::outs() << *python_path << '\n';
return EXIT_SUCCESS;
}
-
- auto python_path_or_err = SetupPythonRuntimeLibrary();
- if (!python_path_or_err)
- llvm::WithColor::error()
- << llvm::toString(python_path_or_err.takeError()) << '\n';
#endif
if (input_args.hasArg(OPT_client)) {
More information about the lldb-commits
mailing list