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() _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
