[Lldb-commits] [lldb] 3eb13f8 - [lldb] Stop hard-linking libpython into the dynamic Python plugin (#200530)
via lldb-commits
lldb-commits at lists.llvm.org
Tue Jun 2 16:47:58 PDT 2026
Author: Jonas Devlieghere
Date: 2026-06-02T16:47:54-07:00
New Revision: 3eb13f8db39ed42827122489c830c414cb6660e3
URL: https://github.com/llvm/llvm-project/commit/3eb13f8db39ed42827122489c830c414cb6660e3
DIFF: https://github.com/llvm/llvm-project/commit/3eb13f8db39ed42827122489c830c414cb6660e3.diff
LOG: [lldb] Stop hard-linking libpython into the dynamic Python plugin (#200530)
Drops ${Python3_LIBRARIES} from the SHARED build of
lldbPluginScriptInterpreterPython and lets undefined Python symbols
through at link time (`-undefined dynamic_lookup` on Darwin,
`--allow-shlib-undefined` on Linux; Windows keeps its existing
delay-load + import lib).
SystemInitializerFull::Initialize resolves the Python runtime loader
via ScriptInterpreterRuntimeLoader::Get(eScriptLanguagePython) and
calls Load() before initializing any plugin, so libpython is mapped
into the process before either entry point that references it: the
static script interpreter's Initialize() (which invokes Python via
the LLDB_PLUGIN_INITIALIZE loop) and the dynamic plugin's dlopen
(whose undefined references resolve against the in-process
libpython). This covers both LLDB_ENABLE_DYNAMIC_SCRIPTINTERPRETERS
=ON and =OFF, and keeps Windows working in static builds where the
delay-load thunks live in liblldb itself. The loader is
once_flag-cached, and errors propagate out via the existing Expected
return.
`import lldb` from a running Python works because libpython is
already mapped into the process. The Python runtime loader probes
for stable-ABI symbols (Py_IsInitialized, Py_InitializeFromConfig)
via dlsym(RTLD_DEFAULT) / GetProcAddress and, finding them, returns
success without dlopen'ing a second libpython on top.
The dynamic plugins are added as test-suite dependencies so
check-lldb-shell and check-lldb-api wait for them; they can't be
build-order deps of liblldb itself because the plugins link against
liblldb (CMake SHARED cycle).
The unit-test static variant lldbStaticScriptInterpreterPython keeps
hard-linking libpython so link-time symbol checking is preserved.
Added:
Modified:
lldb/source/API/SystemInitializerFull.cpp
lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt
lldb/test/CMakeLists.txt
Removed:
################################################################################
diff --git a/lldb/source/API/SystemInitializerFull.cpp b/lldb/source/API/SystemInitializerFull.cpp
index d994915913cc1..6aadcae673a2b 100644
--- a/lldb/source/API/SystemInitializerFull.cpp
+++ b/lldb/source/API/SystemInitializerFull.cpp
@@ -22,6 +22,11 @@
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/TargetSelect.h"
+#if LLDB_ENABLE_PYTHON
+#include "lldb/Host/ScriptInterpreterRuntimeLoader.h"
+#include "lldb/lldb-enumerations.h"
+#endif
+
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wglobal-constructors"
#include "llvm/ExecutionEngine/MCJIT.h"
@@ -42,6 +47,21 @@ llvm::Error SystemInitializerFull::Initialize() {
if (error)
return error;
+#if LLDB_ENABLE_PYTHON
+ // Map libpython into the process before any code that might reference it
+ // runs. This is required by both the static script interpreter (whose
+ // Initialize() invokes Python via the LLDB_PLUGIN_INITIALIZE loop below)
+ // and the dynamic plugin (whose dlopen needs Python's symbols visible in
+ // the process). The loader is once_flag-cached and a no-op when libpython
+ // is already in the process (e.g. `import lldb` from Python).
+ llvm::Expected<ScriptInterpreterRuntimeLoader &> python_loader =
+ ScriptInterpreterRuntimeLoader::Get(lldb::eScriptLanguagePython);
+ if (!python_loader)
+ return python_loader.takeError();
+ if (llvm::Error err = python_loader->Load())
+ return err;
+#endif
+
// Initialize LLVM and Clang
llvm::InitializeAllTargets();
llvm::InitializeAllAsmPrinters();
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt b/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt
index 574dcdf874ada..03ef6b10b06c4 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt
@@ -46,14 +46,28 @@ endif()
if (LLDB_ENABLE_DYNAMIC_SCRIPTINTERPRETERS)
# Shared library loaded at runtime by PluginManager. Private lldb symbols are
# resolved via liblldb's re-exports, so lldb_private libs aren't linked here.
+ # Python is dlopen'd at runtime by ScriptInterpreterRuntimeLoader, so the
+ # plugin is built with allow-undefined-symbol semantics on POSIX.
add_lldb_library(lldbPluginScriptInterpreterPython SHARED
${python_plugin_sources}
LINK_LIBS
liblldb
- ${Python3_LIBRARIES}
${LLDB_LIBEDIT_LIBS}
)
add_python_wrapper(lldbPluginScriptInterpreterPython)
+ if (APPLE)
+ target_link_options(lldbPluginScriptInterpreterPython PRIVATE
+ "LINKER:-undefined,dynamic_lookup")
+ elseif (UNIX)
+ target_link_options(lldbPluginScriptInterpreterPython PRIVATE
+ "LINKER:--unresolved-symbols=ignore-all")
+ else()
+ # Windows continues to use delay-load + import lib.
+ target_link_libraries(lldbPluginScriptInterpreterPython PRIVATE
+ ${Python3_LIBRARIES})
+ target_link_directories(lldbPluginScriptInterpreterPython PRIVATE
+ ${PYTHON_SABI_LIBRARY_DIRS})
+ endif()
# Static variant linked directly by unit tests. Separate compilation is
# required so llvm::Error RTTI (ErrorInfoBase::ID) has a single address
@@ -76,7 +90,6 @@ if (LLDB_ENABLE_DYNAMIC_SCRIPTINTERPRETERS)
target_include_directories(lldbStaticScriptInterpreterPython
PUBLIC ${Python3_INCLUDE_DIRS})
- target_link_directories(lldbPluginScriptInterpreterPython PRIVATE ${PYTHON_SABI_LIBRARY_DIRS})
target_link_directories(lldbStaticScriptInterpreterPython PUBLIC ${PYTHON_SABI_LIBRARY_DIRS})
else()
add_lldb_library(lldbPluginScriptInterpreterPython PLUGIN
diff --git a/lldb/test/CMakeLists.txt b/lldb/test/CMakeLists.txt
index 0a5c3b99f0cc5..0b01936c2590b 100644
--- a/lldb/test/CMakeLists.txt
+++ b/lldb/test/CMakeLists.txt
@@ -128,6 +128,17 @@ if(TARGET liblldb)
add_lldb_test_dependency(liblldb)
endif()
+# When script interpreter plugins are built as separate shared libraries, they
+# are loaded by liblldb at runtime and aren't pulled in by the liblldb target.
+if(LLDB_ENABLE_DYNAMIC_SCRIPTINTERPRETERS)
+ if(TARGET lldbPluginScriptInterpreterPython)
+ add_lldb_test_dependency(lldbPluginScriptInterpreterPython)
+ endif()
+ if(TARGET lldbPluginScriptInterpreterLua)
+ add_lldb_test_dependency(lldbPluginScriptInterpreterLua)
+ endif()
+endif()
+
if(TARGET lldb-framework)
add_lldb_test_dependency(lldb-framework)
endif()
More information about the lldb-commits
mailing list