[Lldb-commits] [lldb] [lldb] Support dynamically loading ScriptInterpreter plugins (PR #189718)
Jonas Devlieghere via lldb-commits
lldb-commits at lists.llvm.org
Mon May 4 09:45:59 PDT 2026
https://github.com/JDevlieghere updated https://github.com/llvm/llvm-project/pull/189718
>From 7de120fb7385eff4dbcf054cd8695e7c599ceb50 Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <jonas at devlieghere.com>
Date: Thu, 5 Mar 2026 16:35:28 -0800
Subject: [PATCH] [lldb] Support dynamically loading ScriptInterpreter plugins
---
lldb/bindings/lua/CMakeLists.txt | 12 +++-
lldb/bindings/python/CMakeLists.txt | 12 +++-
lldb/cmake/modules/LLDBConfig.cmake | 12 +++-
lldb/include/lldb/Host/Config.h.cmake | 2 +
lldb/source/API/CMakeLists.txt | 12 ++--
.../ScriptInterpreter/Lua/CMakeLists.txt | 41 ++++++++++--
.../ScriptInterpreter/Python/CMakeLists.txt | 62 +++++++++++++++----
.../Python/ScriptInterpreterPython.cpp | 6 ++
lldb/tools/driver/CMakeLists.txt | 10 +++
lldb/tools/lldb-dap/CMakeLists.txt | 15 +++--
lldb/unittests/DAP/CMakeLists.txt | 5 +-
.../ScriptInterpreter/Lua/CMakeLists.txt | 8 ++-
.../ScriptInterpreter/Python/CMakeLists.txt | 8 ++-
13 files changed, 172 insertions(+), 33 deletions(-)
diff --git a/lldb/bindings/lua/CMakeLists.txt b/lldb/bindings/lua/CMakeLists.txt
index 677a07044c2af..cdec571022d00 100644
--- a/lldb/bindings/lua/CMakeLists.txt
+++ b/lldb/bindings/lua/CMakeLists.txt
@@ -32,9 +32,17 @@ function(finish_swig_lua swig_target lldb_lua_bindings_dir lldb_lua_target_dir)
DEPENDS swig_wrapper_lua liblldb
COMMENT "LLDB Lua API")
if(LLDB_BUILD_FRAMEWORK)
- set(LIBLLDB_SYMLINK_DEST "${LLDB_FRAMEWORK_ABSOLUTE_BUILD_DIR}/LLDB.framework/LLDB")
+ if (LLDB_ENABLE_DYNAMIC_SCRIPTINTERPRETERS)
+ set(LIBLLDB_SYMLINK_DEST "${LLDB_FRAMEWORK_ABSOLUTE_BUILD_DIR}/LLDB.framework/liblldbPluginScriptInterpreterLua${CMAKE_SHARED_LIBRARY_SUFFIX}")
+ else()
+ set(LIBLLDB_SYMLINK_DEST "${LLDB_FRAMEWORK_ABSOLUTE_BUILD_DIR}/LLDB.framework/LLDB")
+ endif()
else()
- set(LIBLLDB_SYMLINK_DEST "${LLVM_SHLIB_OUTPUT_INTDIR}/liblldb${CMAKE_SHARED_LIBRARY_SUFFIX}")
+ if (LLDB_ENABLE_DYNAMIC_SCRIPTINTERPRETERS)
+ set(LIBLLDB_SYMLINK_DEST "${LLVM_SHLIB_OUTPUT_INTDIR}/liblldbPluginScriptInterpreterLua${CMAKE_SHARED_LIBRARY_SUFFIX}")
+ else()
+ set(LIBLLDB_SYMLINK_DEST "${LLVM_SHLIB_OUTPUT_INTDIR}/liblldb${CMAKE_SHARED_LIBRARY_SUFFIX}")
+ endif()
endif()
if(WIN32)
set(LIBLLDB_SYMLINK_OUTPUT_FILE "lldb.dll")
diff --git a/lldb/bindings/python/CMakeLists.txt b/lldb/bindings/python/CMakeLists.txt
index 04457dfd32e3c..7311920cd8833 100644
--- a/lldb/bindings/python/CMakeLists.txt
+++ b/lldb/bindings/python/CMakeLists.txt
@@ -141,9 +141,17 @@ function(finish_swig_python swig_target lldb_python_bindings_dir lldb_python_tar
endif()
if(LLDB_BUILD_FRAMEWORK)
- set(LIBLLDB_SYMLINK_DEST "${LLDB_FRAMEWORK_ABSOLUTE_BUILD_DIR}/LLDB.framework/LLDB")
+ if (LLDB_ENABLE_DYNAMIC_SCRIPTINTERPRETERS)
+ set(LIBLLDB_SYMLINK_DEST "${LLDB_FRAMEWORK_ABSOLUTE_BUILD_DIR}/LLDB.framework/liblldbPluginScriptInterpreterPython${CMAKE_SHARED_LIBRARY_SUFFIX}")
+ else()
+ set(LIBLLDB_SYMLINK_DEST "${LLDB_FRAMEWORK_ABSOLUTE_BUILD_DIR}/LLDB.framework/LLDB")
+ endif()
else()
- set(LIBLLDB_SYMLINK_DEST "${LLVM_SHLIB_OUTPUT_INTDIR}/liblldb${CMAKE_SHARED_LIBRARY_SUFFIX}")
+ if (LLDB_ENABLE_DYNAMIC_SCRIPTINTERPRETERS)
+ set(LIBLLDB_SYMLINK_DEST "${LLVM_SHLIB_OUTPUT_INTDIR}/liblldbPluginScriptInterpreterPython${CMAKE_SHARED_LIBRARY_SUFFIX}")
+ else()
+ set(LIBLLDB_SYMLINK_DEST "${LLVM_SHLIB_OUTPUT_INTDIR}/liblldb${CMAKE_SHARED_LIBRARY_SUFFIX}")
+ endif()
endif()
set(LIBLLDB_SYMLINK_OUTPUT_FILE "_lldb${LLDB_PYTHON_EXT_SUFFIX}")
create_relative_symlink(${swig_target} ${LIBLLDB_SYMLINK_DEST}
diff --git a/lldb/cmake/modules/LLDBConfig.cmake b/lldb/cmake/modules/LLDBConfig.cmake
index 3f75bffab0078..fe828405d0938 100644
--- a/lldb/cmake/modules/LLDBConfig.cmake
+++ b/lldb/cmake/modules/LLDBConfig.cmake
@@ -68,6 +68,7 @@ add_optional_dependency(LLDB_ENABLE_TREESITTER "Enable Tree-sitter syntax highli
option(LLDB_USE_ENTITLEMENTS "When codesigning, use entitlements if available" ON)
option(LLDB_BUILD_FRAMEWORK "Build LLDB.framework (Darwin only)" OFF)
option(LLDB_ENABLE_PROTOCOL_SERVERS "Enable protocol servers (e.g. MCP) in LLDB" ON)
+option(LLDB_ENABLE_DYNAMIC_SCRIPTINTERPRETERS "Build the script interpreter plugins as shared libraries" OFF)
option(LLDB_NO_INSTALL_DEFAULT_RPATH "Disable default RPATH settings in binaries" OFF)
option(LLDB_USE_SYSTEM_DEBUGSERVER "Use the system's debugserver for testing (Darwin only)." OFF)
option(LLDB_SKIP_STRIP "Whether to skip stripping of binaries when installing lldb." OFF)
@@ -130,9 +131,18 @@ if(APPLE AND CMAKE_GENERATOR STREQUAL Xcode)
endif()
endif()
-set(LLDB_EXPORT_ALL_SYMBOLS 0 CACHE BOOL
+if (LLDB_ENABLE_DYNAMIC_SCRIPTINTERPRETERS)
+ set(default_export_all_symbols ON)
+else()
+ set(default_export_all_symbols OFF)
+endif()
+set(LLDB_EXPORT_ALL_SYMBOLS ${default_export_all_symbols} CACHE BOOL
"Causes lldb to export some private symbols when building liblldb. See lldb/source/API/liblldb-private.exports for the full list of symbols that get exported.")
+if (LLDB_ENABLE_DYNAMIC_SCRIPTINTERPRETERS AND NOT LLDB_EXPORT_ALL_SYMBOLS)
+ message(FATAL_ERROR "Building dynamic ScriptInterpreter plugins (LLDB_ENABLE_DYNAMIC_SCRIPTINTERPRETERS) requires exporting all symbols (LLDB_EXPORT_ALL_SYMBOLS)")
+endif()
+
set(LLDB_EXPORT_ALL_SYMBOLS_EXPORTS_FILE "" CACHE PATH
"When `LLDB_EXPORT_ALL_SYMBOLS` is enabled, this specifies the exports file to use when building liblldb.")
diff --git a/lldb/include/lldb/Host/Config.h.cmake b/lldb/include/lldb/Host/Config.h.cmake
index 06ab9b9a7775c..ae32c001ee5dc 100644
--- a/lldb/include/lldb/Host/Config.h.cmake
+++ b/lldb/include/lldb/Host/Config.h.cmake
@@ -49,6 +49,8 @@
#cmakedefine01 LLDB_EMBED_PYTHON_HOME
+#cmakedefine01 LLDB_ENABLE_DYNAMIC_SCRIPTINTERPRETERS
+
#cmakedefine01 LLDB_ENABLE_TREESITTER
#cmakedefine01 LLDB_ENABLE_MTE
diff --git a/lldb/source/API/CMakeLists.txt b/lldb/source/API/CMakeLists.txt
index a049d6aa9d464..311c739b550f8 100644
--- a/lldb/source/API/CMakeLists.txt
+++ b/lldb/source/API/CMakeLists.txt
@@ -142,12 +142,14 @@ add_lldb_library(liblldb SHARED ${option_framework}
${option_install_prefix}
)
-if (LLDB_ENABLE_PYTHON)
- add_python_wrapper(liblldb)
-endif()
+if (NOT LLDB_ENABLE_DYNAMIC_SCRIPTINTERPRETERS)
+ if (LLDB_ENABLE_PYTHON)
+ add_python_wrapper(liblldb)
+ endif()
-if(LLDB_ENABLE_LUA)
- add_lua_wrapper(liblldb)
+ if(LLDB_ENABLE_LUA)
+ add_lua_wrapper(liblldb)
+ endif()
endif()
set_target_properties(liblldb
diff --git a/lldb/source/Plugins/ScriptInterpreter/Lua/CMakeLists.txt b/lldb/source/Plugins/ScriptInterpreter/Lua/CMakeLists.txt
index 63b035c072c5d..35341282ce144 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Lua/CMakeLists.txt
+++ b/lldb/source/Plugins/ScriptInterpreter/Lua/CMakeLists.txt
@@ -1,12 +1,45 @@
-add_lldb_library(lldbPluginScriptInterpreterLua PLUGIN
+set(lua_plugin_sources
LuaState.cpp
ScriptInterpreterLua.cpp
+)
- LINK_LIBS
- lldbCore
- lldbInterpreter
+set(lua_plugin_static_link_libs
+ lldbCore
+ lldbInterpreter
+ ${LUA_LIBRARIES}
+)
+
+if (LLDB_ENABLE_DYNAMIC_SCRIPTINTERPRETERS)
+ set(plugin_kind SHARED)
+ set(link_libs
+ liblldb
${LUA_LIBRARIES}
)
+else()
+ set(plugin_kind PLUGIN)
+ set(link_libs ${lua_plugin_static_link_libs})
+endif()
+
+add_lldb_library(lldbPluginScriptInterpreterLua ${plugin_kind}
+ ${lua_plugin_sources}
+
+ LINK_LIBS
+ ${link_libs}
+ )
target_include_directories(lldbPluginScriptInterpreterLua
PUBLIC ${LUA_INCLUDE_DIR})
+
+if (LLDB_ENABLE_DYNAMIC_SCRIPTINTERPRETERS)
+ add_lua_wrapper(lldbPluginScriptInterpreterLua)
+
+ add_lldb_library(lldbStaticScriptInterpreterLua
+ ${lua_plugin_sources}
+
+ LINK_LIBS
+ ${lua_plugin_static_link_libs}
+ )
+
+ target_include_directories(lldbStaticScriptInterpreterLua
+ PUBLIC ${LUA_INCLUDE_DIR})
+endif()
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt b/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt
index 69dd9e669ad9d..92dfcc77174fd 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt
@@ -18,7 +18,7 @@ if (LLDB_ENABLE_LIBEDIT)
list(APPEND LLDB_LIBEDIT_LIBS LibEdit::LibEdit)
endif()
-add_lldb_library(lldbPluginScriptInterpreterPython PLUGIN
+set(python_plugin_sources
PythonDataObjects.cpp
PythonReadline.cpp
ScriptInterpreterPython.cpp
@@ -35,21 +35,61 @@ add_lldb_library(lldbPluginScriptInterpreterPython PLUGIN
Interfaces/ScriptedBreakpointPythonInterface.cpp
Interfaces/ScriptedThreadPlanPythonInterface.cpp
Interfaces/ScriptedThreadPythonInterface.cpp
+)
- LINK_COMPONENTS
- Support
- LINK_LIBS
- lldbBreakpoint
- lldbCore
- lldbDataFormatters
- lldbHost
- lldbInterpreter
- lldbTarget
- lldbValueObject
+set(python_plugin_static_link_components Support)
+set(python_plugin_static_link_libs
+ lldbBreakpoint
+ lldbCore
+ lldbDataFormatters
+ lldbHost
+ lldbInterpreter
+ lldbTarget
+ lldbValueObject
+ ${Python3_LIBRARIES}
+ ${LLDB_LIBEDIT_LIBS}
+)
+
+if (LLDB_ENABLE_DYNAMIC_SCRIPTINTERPRETERS)
+ set(plugin_kind SHARED)
+ set(link_components "")
+ set(link_libs
+ liblldb
${Python3_LIBRARIES}
${LLDB_LIBEDIT_LIBS}
)
+else()
+ set(plugin_kind PLUGIN)
+ set(link_components ${python_plugin_static_link_components})
+ set(link_libs ${python_plugin_static_link_libs})
+endif()
+
+add_lldb_library(lldbPluginScriptInterpreterPython ${plugin_kind}
+ ${python_plugin_sources}
+ LINK_COMPONENTS
+ ${link_components}
+ LINK_LIBS
+ ${link_libs}
+ )
target_include_directories(lldbPluginScriptInterpreterPython
PUBLIC ${Python3_INCLUDE_DIRS})
+
+if (LLDB_ENABLE_DYNAMIC_SCRIPTINTERPRETERS)
+ add_python_wrapper(lldbPluginScriptInterpreterPython)
+
+ # When we're building the script interpreter as a shared library, we don't
+ # want to re-export all the symbols from the unit test. Instead, build a
+ # static variant for unit test.
+ add_lldb_library(lldbStaticScriptInterpreterPython
+ ${python_plugin_sources}
+
+ LINK_COMPONENTS
+ ${python_plugin_static_link_components}
+ LINK_LIBS
+ ${python_plugin_static_link_libs}
+ )
+ target_include_directories(lldbStaticScriptInterpreterPython
+ PUBLIC ${Python3_INCLUDE_DIRS})
+endif()
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
index 355f18682dd2b..984e6f7227216 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
@@ -300,8 +300,14 @@ void ScriptInterpreterPython::Initialize() {
setenv("PYTHONMALLOC", "malloc", /*overwrite=*/true);
#endif
+ // When the script interpreter is a separate shared library, the SWIG wrapper
+ // links directly against it (not liblldb), so the shared library directory
+ // helper is not needed to redirect the library path back to liblldb.
+#if !LLDB_ENABLE_DYNAMIC_SCRIPTINTERPRETERS
HostInfo::SetSharedLibraryDirectoryHelper(
ScriptInterpreterPython::SharedLibraryDirectoryHelper);
+#endif
+
PluginManager::RegisterPlugin(
GetPluginNameStatic(), GetPluginDescriptionStatic(),
lldb::eScriptLanguagePython, ScriptInterpreterPythonImpl::CreateInstance,
diff --git a/lldb/tools/driver/CMakeLists.txt b/lldb/tools/driver/CMakeLists.txt
index 1c93ed9fad927..292da5759757d 100644
--- a/lldb/tools/driver/CMakeLists.txt
+++ b/lldb/tools/driver/CMakeLists.txt
@@ -38,6 +38,16 @@ if(WIN32)
list(APPEND LLDB_DRIVER_LINK_LIBS lldbHostPythonPathSetup)
endif()
+if (LLDB_ENABLE_DYNAMIC_SCRIPTINTERPRETERS)
+ if (LLDB_ENABLE_PYTHON)
+ list(APPEND LLDB_DRIVER_LINK_LIBS lldbPluginScriptInterpreterPython)
+ endif()
+
+ if(LLDB_ENABLE_LUA)
+ list(APPEND LLDB_DRIVER_LINK_LIBS lldbPluginScriptInterpreterLua)
+ endif()
+endif()
+
add_lldb_tool(lldb
Driver.cpp
Platform.cpp
diff --git a/lldb/tools/lldb-dap/CMakeLists.txt b/lldb/tools/lldb-dap/CMakeLists.txt
index 1bb7a2e498b9b..dda527b6b0cc2 100644
--- a/lldb/tools/lldb-dap/CMakeLists.txt
+++ b/lldb/tools/lldb-dap/CMakeLists.txt
@@ -1,6 +1,12 @@
-# We need to include the llvm components we depend on manually, as liblldb does
-# not re-export those.
-set(LLVM_LINK_COMPONENTS Support)
+# When LLDB_EXPORT_ALL_SYMBOLS is OFF, we need to include the LLVM components we
+# depend on manually, as liblldb does not re-export those. When it is ON, liblldb
+# exports all symbols including those from LLVM. In that case we must NOT link
+# them statically to avoid duplicate symbols (e.g. ErrorInfoBase::ID) which
+# breaks LLVM's Error handling across library boundaries.
+if (NOT LLDB_EXPORT_ALL_SYMBOLS)
+ set(LLVM_LINK_COMPONENTS Support)
+ set(llvm_link_components Option Support)
+endif()
add_lldb_library(lldbDAP
Breakpoint.cpp
@@ -75,8 +81,7 @@ add_lldb_library(lldbDAP
Protocol/ProtocolRequests.cpp
LINK_COMPONENTS
- Option
- Support
+ ${llvm_link_components}
LINK_LIBS
liblldb
lldbHost
diff --git a/lldb/unittests/DAP/CMakeLists.txt b/lldb/unittests/DAP/CMakeLists.txt
index 53e0fde5687ec..c6a2a0a9675d2 100644
--- a/lldb/unittests/DAP/CMakeLists.txt
+++ b/lldb/unittests/DAP/CMakeLists.txt
@@ -22,11 +22,14 @@ add_lldb_unittest(DAPTests
LINK_COMPONENTS
Support
+
LINK_LIBS
- liblldb
lldbDAP
+ lldbHost
+ lldbUtility
lldbUtilityHelpers
LLVMTestingSupport
+ liblldb
)
set(test_inputs
diff --git a/lldb/unittests/ScriptInterpreter/Lua/CMakeLists.txt b/lldb/unittests/ScriptInterpreter/Lua/CMakeLists.txt
index 558f76dd5488d..20774844ec024 100644
--- a/lldb/unittests/ScriptInterpreter/Lua/CMakeLists.txt
+++ b/lldb/unittests/ScriptInterpreter/Lua/CMakeLists.txt
@@ -1,3 +1,9 @@
+if (LLDB_ENABLE_DYNAMIC_SCRIPTINTERPRETERS)
+ set(script_interpreter_lua_lib lldbStaticScriptInterpreterLua)
+else()
+ set(script_interpreter_lua_lib lldbPluginScriptInterpreterLua)
+endif()
+
add_lldb_unittest(ScriptInterpreterLuaTests
LuaTests.cpp
ScriptInterpreterTests.cpp
@@ -6,7 +12,7 @@ add_lldb_unittest(ScriptInterpreterLuaTests
Support
LINK_LIBS
lldbHost
- lldbPluginScriptInterpreterLua
+ ${script_interpreter_lua_lib}
lldbPluginPlatformLinux
LLVMTestingSupport
)
diff --git a/lldb/unittests/ScriptInterpreter/Python/CMakeLists.txt b/lldb/unittests/ScriptInterpreter/Python/CMakeLists.txt
index 9b0769616ba6c..ed35b73cd2a0c 100644
--- a/lldb/unittests/ScriptInterpreter/Python/CMakeLists.txt
+++ b/lldb/unittests/ScriptInterpreter/Python/CMakeLists.txt
@@ -4,6 +4,12 @@ if (APPLE AND LLVM_ENABLE_LOCAL_SUBMODULE_VISIBILITY)
remove_module_flags()
endif()
+if (LLDB_ENABLE_DYNAMIC_SCRIPTINTERPRETERS)
+ set(script_interpreter_python_lib lldbStaticScriptInterpreterPython)
+else()
+ set(script_interpreter_python_lib lldbPluginScriptInterpreterPython)
+endif()
+
add_lldb_unittest(ScriptInterpreterPythonTests
PythonDataObjectsTests.cpp
PythonTestSuite.cpp
@@ -12,7 +18,7 @@ add_lldb_unittest(ScriptInterpreterPythonTests
Support
LINK_LIBS
lldbHost
- lldbPluginScriptInterpreterPython
+ ${script_interpreter_python_lib}
LLVMTestingSupport
)
More information about the lldb-commits
mailing list