https://github.com/Nerixyz updated https://github.com/llvm/llvm-project/pull/200843
>From 051c4c84ac4c6d033c4cdb46272e0d0a7d5accf8 Mon Sep 17 00:00:00 2001 From: Nerixyz <[email protected]> Date: Mon, 1 Jun 2026 16:30:50 +0200 Subject: [PATCH 1/6] [lldb] Fix Windows build with dynamic Python plugin --- lldb/bindings/python/CMakeLists.txt | 3 +++ lldb/include/lldb/Host/FileBase.h | 2 +- lldb/source/Host/common/File.cpp | 1 - .../Plugins/ScriptInterpreter/Python/CMakeLists.txt | 10 ++++++++++ 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/lldb/bindings/python/CMakeLists.txt b/lldb/bindings/python/CMakeLists.txt index 2916d004a389e..d76b4d5f4951e 100644 --- a/lldb/bindings/python/CMakeLists.txt +++ b/lldb/bindings/python/CMakeLists.txt @@ -157,6 +157,9 @@ function(finish_swig_python swig_target lldb_python_bindings_dir lldb_python_tar create_relative_symlink(${swig_target} ${LIBLLDB_SYMLINK_DEST} ${lldb_python_target_dir}/native/ ${LIBLLDB_SYMLINK_OUTPUT_FILE}) + if (LLDB_ENABLE_DYNAMIC_SCRIPTINTERPRETERS) + add_dependencies(${swig_target} lldbPluginScriptInterpreterPython) + endif() if (NOT WIN32) add_dependencies(${swig_target} lldb-python-wrapper) diff --git a/lldb/include/lldb/Host/FileBase.h b/lldb/include/lldb/Host/FileBase.h index 54ca89f3201c6..bc0b2914ded8c 100644 --- a/lldb/include/lldb/Host/FileBase.h +++ b/lldb/include/lldb/Host/FileBase.h @@ -33,7 +33,7 @@ LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); /// or stream functionality but are not backed by any host OS file. class File : public IOObject { public: - static int kInvalidDescriptor; + static constexpr int kInvalidDescriptor = -1; static FILE *kInvalidStream; // NB this enum is used in the lldb platform gdb-remote packet diff --git a/lldb/source/Host/common/File.cpp b/lldb/source/Host/common/File.cpp index 499df4e542ab2..a863e323c65ff 100644 --- a/lldb/source/Host/common/File.cpp +++ b/lldb/source/Host/common/File.cpp @@ -93,7 +93,6 @@ Expected<File::OpenOptions> File::GetOptionsFromMode(llvm::StringRef mode) { "invalid mode, cannot convert to File::OpenOptions"); } -int File::kInvalidDescriptor = -1; FILE *File::kInvalidStream = nullptr; Status File::Read(void *buf, size_t &num_bytes) { diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt b/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt index 574dcdf874ada..55d8b6060486c 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt +++ b/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt @@ -48,6 +48,8 @@ if (LLDB_ENABLE_DYNAMIC_SCRIPTINTERPRETERS) # resolved via liblldb's re-exports, so lldb_private libs aren't linked here. add_lldb_library(lldbPluginScriptInterpreterPython SHARED ${python_plugin_sources} + LINK_COMPONENTS + Support LINK_LIBS liblldb ${Python3_LIBRARIES} @@ -78,6 +80,14 @@ if (LLDB_ENABLE_DYNAMIC_SCRIPTINTERPRETERS) target_link_directories(lldbPluginScriptInterpreterPython PRIVATE ${PYTHON_SABI_LIBRARY_DIRS}) target_link_directories(lldbStaticScriptInterpreterPython PUBLIC ${PYTHON_SABI_LIBRARY_DIRS}) + if(WIN32 AND NOT MINGW) + # Windows doesn't have "lib" as CMAKE_SHARED_LIBRARY_PREFIX. To be + # consistent with Unix, the output is still prefixed with "lib". + set_target_properties(lldbPluginScriptInterpreterPython + PROPERTIES + OUTPUT_NAME liblldbPluginScriptInterpreterPython + ) + endif() else() add_lldb_library(lldbPluginScriptInterpreterPython PLUGIN ${python_plugin_sources} >From 9a689b53f6559510619493bfc593cc10a7efa760 Mon Sep 17 00:00:00 2001 From: Nerixyz <[email protected]> Date: Mon, 1 Jun 2026 17:40:06 +0200 Subject: [PATCH 2/6] Update lldb/include/lldb/Host/FileBase.h Co-authored-by: Charles Zablit <[email protected]> --- lldb/include/lldb/Host/FileBase.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/include/lldb/Host/FileBase.h b/lldb/include/lldb/Host/FileBase.h index bc0b2914ded8c..45e0a49545ee4 100644 --- a/lldb/include/lldb/Host/FileBase.h +++ b/lldb/include/lldb/Host/FileBase.h @@ -34,7 +34,7 @@ LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); class File : public IOObject { public: static constexpr int kInvalidDescriptor = -1; - static FILE *kInvalidStream; + static constexpr FILE *kInvalidStream = nullptr; // NB this enum is used in the lldb platform gdb-remote packet // vFile:open: and existing values cannot be modified. >From 6125960fe92e6e9cbfded84348f62e071df988a6 Mon Sep 17 00:00:00 2001 From: Nerixyz <[email protected]> Date: Mon, 1 Jun 2026 17:49:28 +0200 Subject: [PATCH 3/6] fix: remove old definition --- lldb/source/Host/common/File.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/lldb/source/Host/common/File.cpp b/lldb/source/Host/common/File.cpp index a863e323c65ff..5870d2f1457ad 100644 --- a/lldb/source/Host/common/File.cpp +++ b/lldb/source/Host/common/File.cpp @@ -93,8 +93,6 @@ Expected<File::OpenOptions> File::GetOptionsFromMode(llvm::StringRef mode) { "invalid mode, cannot convert to File::OpenOptions"); } -FILE *File::kInvalidStream = nullptr; - Status File::Read(void *buf, size_t &num_bytes) { return std::error_code(ENOTSUP, std::system_category()); } >From da6a2429292894834e6f931bcb05a69e6802cd5d Mon Sep 17 00:00:00 2001 From: Nerixyz <[email protected]> Date: Mon, 1 Jun 2026 17:54:09 +0200 Subject: [PATCH 4/6] fix: only link `Support` on Windows --- lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt b/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt index 55d8b6060486c..2779658d981cb 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt +++ b/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt @@ -41,6 +41,7 @@ if (WIN32) # Add the library directories to allow Python to use #pragma comment(lib, "python3.lib"). # FIXME: We should use Python3_SABI_LIBRARY_DIRS here, but this requires CMake 3.26. set(PYTHON_SABI_LIBRARY_DIRS ${Python3_LIBRARY_DIRS}) + set(shared_python_plugin_link_components Support) endif() if (LLDB_ENABLE_DYNAMIC_SCRIPTINTERPRETERS) @@ -49,7 +50,7 @@ if (LLDB_ENABLE_DYNAMIC_SCRIPTINTERPRETERS) add_lldb_library(lldbPluginScriptInterpreterPython SHARED ${python_plugin_sources} LINK_COMPONENTS - Support + ${shared_python_plugin_link_components} LINK_LIBS liblldb ${Python3_LIBRARIES} >From 66cc1468aa488e1b617a5e5a630542aa4fbd4794 Mon Sep 17 00:00:00 2001 From: Nerixyz <[email protected]> Date: Tue, 16 Jun 2026 18:05:02 +0200 Subject: [PATCH 5/6] fix: add back OUTPUT_NAME adjustment --- .../Plugins/ScriptInterpreter/Python/CMakeLists.txt | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt b/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt index 85962b6268565..abb7c2c6ee4e3 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt +++ b/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt @@ -73,6 +73,14 @@ if (LLDB_ENABLE_DYNAMIC_SCRIPTINTERPRETERS) endif() target_link_directories(lldbPluginScriptInterpreterPython PRIVATE ${PYTHON_SABI_LIBRARY_DIRS}) + if(NOT MINGW) + # Windows doesn't have "lib" as CMAKE_SHARED_LIBRARY_PREFIX. To be + # consistent with Unix, the output is still prefixed with "lib". + set_target_properties(lldbPluginScriptInterpreterPython + PROPERTIES + OUTPUT_NAME liblldbPluginScriptInterpreterPython + ) + endif() endif() if (NOT CMAKE_SYSTEM_NAME MATCHES "Windows") @@ -85,8 +93,6 @@ if (LLDB_ENABLE_DYNAMIC_SCRIPTINTERPRETERS) # shared between the test binary and the plugin code. add_lldb_library(lldbStaticScriptInterpreterPython ${python_plugin_sources} - LINK_COMPONENTS - Support LINK_LIBS lldbBreakpoint lldbCore >From b865b8e382e05e9387c55c185ec3a2b673052e7a Mon Sep 17 00:00:00 2001 From: Nerixyz <[email protected]> Date: Fri, 19 Jun 2026 17:15:11 +0200 Subject: [PATCH 6/6] refactor: export required undefined symbols instead --- lldb/bindings/python/CMakeLists.txt | 2 + lldb/cmake/modules/AddLLDB.cmake | 6 +- lldb/include/lldb/Host/FileBase.h | 4 +- lldb/scripts/msvc_extract_private_symbols.py | 85 ++++++++++++------- lldb/source/API/CMakeLists.txt | 18 +++- lldb/source/Host/common/File.cpp | 3 + .../ScriptInterpreter/Python/CMakeLists.txt | 19 +++-- 7 files changed, 96 insertions(+), 41 deletions(-) diff --git a/lldb/bindings/python/CMakeLists.txt b/lldb/bindings/python/CMakeLists.txt index 4bc49da2d0b04..c2c127b206126 100644 --- a/lldb/bindings/python/CMakeLists.txt +++ b/lldb/bindings/python/CMakeLists.txt @@ -244,6 +244,8 @@ function(add_python_wrapper target) add_dependencies(${target} swig_wrapper_python) add_swig_wrapper(${target} ${lldb_python_wrapper}) + + set_source_files_properties(${lldb_python_wrapper} PROPERTIES SKIP_PRECOMPILE_HEADERS ON) # lib/pythonX.Y/dist-packages/lldb/_lldb.so is a symlink to lib/liblldb.so, # which depends on lib/libLLVM*.so (BUILD_SHARED_LIBS) or lib/libLLVM-10git.so diff --git a/lldb/cmake/modules/AddLLDB.cmake b/lldb/cmake/modules/AddLLDB.cmake index d09def0afdb74..023634d618f9c 100644 --- a/lldb/cmake/modules/AddLLDB.cmake +++ b/lldb/cmake/modules/AddLLDB.cmake @@ -183,7 +183,7 @@ function(add_lldb_library name) ) cmake_parse_arguments(PARAM - "MODULE;SHARED;STATIC;OBJECT;PLUGIN;FRAMEWORK;NO_INTERNAL_DEPENDENCIES;NO_PLUGIN_DEPENDENCIES" + "MODULE;SHARED;STATIC;OBJECT;PLUGIN;FRAMEWORK;NO_INTERNAL_DEPENDENCIES;NO_PLUGIN_DEPENDENCIES;CONSUMES_LIBLLDB" "INSTALL_PREFIX" "LINK_LIBS;CLANG_LIBS;ALLOWED_INTERNAL_DEPENDENCIES" ${ARGN}) @@ -355,6 +355,10 @@ function(add_lldb_library name) if (LLDB_EXPORT_ALL_SYMBOLS OR LLDB_ENABLE_DYNAMIC_SCRIPTINTERPRETERS) set_target_properties(${name} PROPERTIES CXX_VISIBILITY_PRESET default) endif() + + if (PARAM_CONSUMES_LIBLLDB) + set_property(GLOBAL APPEND PROPERTY LLDB_LIBLLDB_CONSUMERS ${name}) + endif() endfunction(add_lldb_library) function(add_lldb_executable name) diff --git a/lldb/include/lldb/Host/FileBase.h b/lldb/include/lldb/Host/FileBase.h index 45e0a49545ee4..54ca89f3201c6 100644 --- a/lldb/include/lldb/Host/FileBase.h +++ b/lldb/include/lldb/Host/FileBase.h @@ -33,8 +33,8 @@ LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); /// or stream functionality but are not backed by any host OS file. class File : public IOObject { public: - static constexpr int kInvalidDescriptor = -1; - static constexpr FILE *kInvalidStream = nullptr; + static int kInvalidDescriptor; + static FILE *kInvalidStream; // NB this enum is used in the lldb platform gdb-remote packet // vFile:open: and existing values cannot be modified. diff --git a/lldb/scripts/msvc_extract_private_symbols.py b/lldb/scripts/msvc_extract_private_symbols.py index b741310d717c2..f72c8260c33bd 100644 --- a/lldb/scripts/msvc_extract_private_symbols.py +++ b/lldb/scripts/msvc_extract_private_symbols.py @@ -13,17 +13,13 @@ import sys -def extract_symbols(nm_path: str, lib: str): +def extract_symbols(nm_path: str, lib: str, regex: re.Pattern[str], nm_flags: list[str]): """Extract all of the private lldb symbols from the given path to llvm-nm and library to extract from.""" - # Matches mangled symbols containing 'lldb_private'. - lldb_sym_re = r"[0-9a-zA-Z]* [BT] (?P<symbol>[?]+[^?].*lldb_private.*)" - - # '-g' means we only get global symbols. # '-p' do not waste time sorting the symbols. process = subprocess.Popen( - [nm_path, "-g", "-p", lib], + [nm_path, "-p", lib] + nm_flags, bufsize=1, stdout=subprocess.PIPE, stdin=subprocess.PIPE, @@ -33,7 +29,7 @@ def extract_symbols(nm_path: str, lib: str): lldb_symbols = set() for line in process.stdout: - match = re.match(lldb_sym_re, line) + match = re.match(regex, line) if match: symbol = match.group("symbol") assert ( @@ -49,6 +45,26 @@ def extract_symbols(nm_path: str, lib: str): return lldb_symbols +def extract_exports(nm_path: str, lib: str): + # Matches mangled symbols containing 'lldb_private'. + regex = re.compile(r"[0-9a-zA-Z]* [BT] (?P<symbol>[?]+[^?].*lldb_private.*)") + # '-g': Only get the global symbols + return extract_symbols(nm_path, lib, regex, ['-g']) + + +def extract_undef(nm_path: str, lib: str): + # Matches mangled symbols containing 'lldb_private' or 'llvm'. + regex_undef = re.compile(r"^0* +U (?P<symbol>[?]+[^?].*(?:lldb_private|llvm).*)") + regex_global = re.compile(r"[0-9a-zA-Z]* [BT] (?P<symbol>[?]+[^?].*(?:lldb_private|llvm).*)") + # '-u': Only get the undefined symbols + undef = extract_symbols(nm_path, lib, regex_undef, ['-u']) + # '-g': Only get the global symbols + globals = extract_symbols(nm_path, lib, regex_global, ['-g']) + # If this is a static library, only return symbols undefined in all object + # files. + return undef - globals + + def main(): parser = argparse.ArgumentParser(description="Generate LLDB dll exports") parser.add_argument( @@ -56,41 +72,48 @@ def main(): ) parser.add_argument("--nm", help="Path to the llvm-nm executable.") parser.add_argument( - "libs", + "--libs", metavar="lib", type=str, nargs="+", - help="The libraries to extract symbols from.", + help="Libraries to extract exported symbols from.", + ) + parser.add_argument( + "--consuming-libs", + metavar="lib", + type=str, + nargs="*", + help="Libraries to extract undefined symbols from.", ) args = parser.parse_args() # Get the list of libraries to extract symbols from libs = list() - for lib in args.libs: - # When invoked by cmake the arguments are the cmake target names of the - # libraries, so we need to add .lib/.a to the end and maybe lib to the - # start to get the filename. Also allow objects. - suffixes = [".lib", ".a", ".obj", ".o"] - if not any([lib.endswith(s) for s in suffixes]): - for suffix in suffixes: - if os.path.exists(lib + suffix): - lib = lib + suffix - break - if os.path.exists("lib" + lib + suffix): - lib = "lib" + lib + suffix - break - if not any([lib.endswith(s) for s in suffixes]): - print( - "Unknown extension type for library argument: " + lib, file=sys.stderr - ) - exit(1) - libs.append(lib) + for input_libs, is_consuming in ((args.libs, False), (args.consuming_libs, True)): + for lib in input_libs: + # When invoked by cmake the arguments are the cmake target names of the + # libraries, so we need to add .lib/.a to the end and maybe lib to the + # start to get the filename. Also allow objects. + suffixes = [".lib", ".a", ".obj", ".o"] + if not any([lib.endswith(s) for s in suffixes]): + for suffix in suffixes: + if os.path.exists(lib + suffix): + lib = lib + suffix + break + if os.path.exists("lib" + lib + suffix): + lib = "lib" + lib + suffix + break + if not any([lib.endswith(s) for s in suffixes]): + print( + "Unknown extension type for library argument: " + lib, file=sys.stderr + ) + exit(1) + libs.append((lib, is_consuming)) # Extract symbols from the input libraries. symbols = set() - for lib in libs: - for sym in list(extract_symbols(args.nm, lib)): - symbols.add(sym) + for (lib, is_consuming) in libs: + symbols |= extract_undef(args.nm, lib) if is_consuming else extract_exports(args.nm, lib) # Write out the symbols to the output file. with open(args.o, "w", newline="") as f: diff --git a/lldb/source/API/CMakeLists.txt b/lldb/source/API/CMakeLists.txt index 15c52aab41368..c2247ae0b0306 100644 --- a/lldb/source/API/CMakeLists.txt +++ b/lldb/source/API/CMakeLists.txt @@ -227,7 +227,18 @@ elseif (LLDB_EXPORT_ALL_SYMBOLS OR LLDB_ENABLE_DYNAMIC_SCRIPTINTERPRETERS) endif() endif() endforeach(lib) + # The reverse to lldb_libs: Export all symbols required by these libraries. + set(lldb_consuming_libs "") + get_property(liblldb_consumers GLOBAL PROPERTY LLDB_LIBLLDB_CONSUMERS) + foreach(lib ${liblldb_consumers}) + get_target_property(lib_type ${lib} TYPE) + if("${lib_type}" STREQUAL "STATIC_LIBRARY") + list(APPEND lldb_consuming_libs ${lib}) + endif() + endforeach() + list(REMOVE_DUPLICATES lldb_libs) + list(REMOVE_DUPLICATES lldb_consuming_libs) # Extract all of the private symbols and produce a single file we can use for # the exports. @@ -237,10 +248,13 @@ elseif (LLDB_EXPORT_ALL_SYMBOLS OR LLDB_ENABLE_DYNAMIC_SCRIPTINTERPRETERS) OUTPUT ${exported_symbol_file} COMMAND "${Python3_EXECUTABLE}" ${LLDB_SOURCE_DIR}/scripts/msvc_extract_private_symbols.py - ${lldb_libs} -o ${exported_symbol_file} --nm=${llvm_nm_exe} + --libs ${lldb_libs} + --consuming-libs ${lldb_consuming_libs} + -o ${exported_symbol_file} + --nm=${llvm_nm_exe} WORKING_DIRECTORY ${LLVM_LIBRARY_OUTPUT_INTDIR} DEPENDS ${LLDB_SOURCE_DIR}/scripts/msvc_extract_private_symbols.py - ${lldb_libs} ${llvm_nm_target} + ${lldb_libs} ${lldb_consuming_libs} ${llvm_nm_target} VERBATIM COMMENT "Generating liblldb private export list" ) diff --git a/lldb/source/Host/common/File.cpp b/lldb/source/Host/common/File.cpp index 5870d2f1457ad..499df4e542ab2 100644 --- a/lldb/source/Host/common/File.cpp +++ b/lldb/source/Host/common/File.cpp @@ -93,6 +93,9 @@ Expected<File::OpenOptions> File::GetOptionsFromMode(llvm::StringRef mode) { "invalid mode, cannot convert to File::OpenOptions"); } +int File::kInvalidDescriptor = -1; +FILE *File::kInvalidStream = nullptr; + Status File::Read(void *buf, size_t &num_bytes) { return std::error_code(ENOTSUP, std::system_category()); } diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt b/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt index abb7c2c6ee4e3..cae9286cd8030 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt +++ b/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt @@ -41,23 +41,32 @@ if (WIN32) # Add the library directories to allow Python to use #pragma comment(lib, "python3.lib"). # FIXME: We should use Python3_SABI_LIBRARY_DIRS here, but this requires CMake 3.26. set(PYTHON_SABI_LIBRARY_DIRS ${Python3_LIBRARY_DIRS}) - set(shared_python_plugin_link_components Support) endif() if (LLDB_ENABLE_DYNAMIC_SCRIPTINTERPRETERS) + add_lldb_library(lldbPluginScriptInterpreterPythonObjects OBJECT + # Export all undefined symbols in liblldb for us on MSVC. + CONSUMES_LIBLLDB + ${python_plugin_sources} + ) + # add_lldb_library/llvm_add_library will actually create + # lldbPluginScriptInterpreterPythonObjects as a static library that links to + # "obj.{name}". On MSVC, we can't link to the static one, but need to link to + # the object library. + set(objlib obj.lldbPluginScriptInterpreterPythonObjects) + add_python_wrapper(${objlib}) + target_include_directories(${objlib} PUBLIC ${Python3_INCLUDE_DIRS}) + # 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_COMPONENTS - ${shared_python_plugin_link_components} LINK_LIBS liblldb ${LLDB_LIBEDIT_LIBS} + ${objlib} ) - add_python_wrapper(lldbPluginScriptInterpreterPython) if (APPLE) target_link_options(lldbPluginScriptInterpreterPython PRIVATE "LINKER:-undefined,dynamic_lookup") _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
