[lldb-dap][windows] add support for out of PATH python.dll resolution (#179306)
This commit is contained in:
@@ -61,6 +61,10 @@ if (LLDB_ENABLE_PYTHON)
|
||||
"Path to python interpreter exectuable, relative to python's install prefix")
|
||||
set(cachestring_LLDB_PYTHON_EXT_SUFFIX
|
||||
"Filename extension for native code python modules")
|
||||
set(cachestring_LLDB_PYTHON_DLL_RELATIVE_PATH
|
||||
"Relative path from LLDB executable to Python DLL directory (Windows only)")
|
||||
set(cachestring_LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME
|
||||
"Filename of Python runtime library to search for, e.g. python311.dll (Windows only)")
|
||||
|
||||
if (LLDB_ENABLE_PYTHON_LIMITED_API)
|
||||
set(stable_abi "--stable-abi")
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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.
|
||||
llvm::Error SetupPythonRuntimeLibrary();
|
||||
|
||||
#endif // LLDB_SOURCE_HOST_PYTHONPATHSETUP_H
|
||||
@@ -65,6 +65,7 @@ add_host_subdirectory(posix
|
||||
)
|
||||
|
||||
if (CMAKE_SYSTEM_NAME MATCHES "Windows")
|
||||
add_subdirectory(windows/PythonPathSetup)
|
||||
add_host_subdirectory(windows
|
||||
windows/ConnectionGenericFileWindows.cpp
|
||||
windows/FileSystem.cpp
|
||||
|
||||
13
lldb/source/Host/windows/PythonPathSetup/CMakeLists.txt
Normal file
13
lldb/source/Host/windows/PythonPathSetup/CMakeLists.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
add_lldb_library(lldbHostPythonPathSetup STATIC
|
||||
PythonPathSetup.cpp
|
||||
|
||||
LINK_LIBS
|
||||
LLVMSupport
|
||||
)
|
||||
|
||||
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()
|
||||
92
lldb/source/Host/windows/PythonPathSetup/PythonPathSetup.cpp
Normal file
92
lldb/source/Host/windows/PythonPathSetup/PythonPathSetup.cpp
Normal file
@@ -0,0 +1,92 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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;
|
||||
|
||||
#ifdef LLDB_PYTHON_DLL_RELATIVE_PATH
|
||||
/// Returns the full path to the lldb.exe executable.
|
||||
static std::wstring GetPathToExecutableW() {
|
||||
std::vector<WCHAR> buffer(MAX_PATH);
|
||||
while (buffer.size() <= PATHCCH_MAX_CCH) {
|
||||
DWORD len = GetModuleFileNameW(NULL, buffer.data(), buffer.size());
|
||||
if (len == 0)
|
||||
return L"";
|
||||
if (len < buffer.size())
|
||||
return std::wstring(buffer.data(), len);
|
||||
if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER)
|
||||
buffer.resize(buffer.size() * 2);
|
||||
}
|
||||
return L"";
|
||||
}
|
||||
|
||||
bool AddPythonDLLToSearchPath() {
|
||||
std::wstring modulePath = GetPathToExecutableW();
|
||||
if (modulePath.empty())
|
||||
return false;
|
||||
|
||||
SmallVector<char, MAX_PATH> utf8Path;
|
||||
if (sys::windows::UTF16ToUTF8(modulePath.c_str(), modulePath.length(),
|
||||
utf8Path))
|
||||
return false;
|
||||
sys::path::remove_filename(utf8Path);
|
||||
sys::path::append(utf8Path, LLDB_PYTHON_DLL_RELATIVE_PATH);
|
||||
sys::fs::make_absolute(utf8Path);
|
||||
|
||||
SmallVector<wchar_t, 1> widePath;
|
||||
if (sys::windows::widenPath(utf8Path.data(), widePath))
|
||||
return false;
|
||||
|
||||
if (sys::fs::exists(utf8Path))
|
||||
return SetDllDirectoryW(widePath.data());
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME
|
||||
bool IsPythonDLLInPath() {
|
||||
#define WIDEN2(x) L##x
|
||||
#define WIDEN(x) WIDEN2(x)
|
||||
HMODULE h = LoadLibraryW(WIDEN(LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME));
|
||||
if (!h)
|
||||
return false;
|
||||
FreeLibrary(h);
|
||||
return true;
|
||||
#undef WIDEN2
|
||||
#undef WIDEN
|
||||
}
|
||||
#endif
|
||||
|
||||
llvm::Error SetupPythonRuntimeLibrary() {
|
||||
#ifdef LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME
|
||||
if (IsPythonDLLInPath())
|
||||
return Error::success();
|
||||
#ifdef LLDB_PYTHON_DLL_RELATIVE_PATH
|
||||
if (AddPythonDLLToSearchPath() && IsPythonDLLInPath())
|
||||
return Error::success();
|
||||
#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 Error::success();
|
||||
}
|
||||
@@ -16,6 +16,16 @@ if (UNIX AND "${CMAKE_SYSTEM_NAME}" MATCHES "AIX")
|
||||
add_definitions("-D_ALL_SOURCE")
|
||||
endif()
|
||||
|
||||
set(LLDB_DRIVER_LINK_LIBS
|
||||
liblldb
|
||||
lldbHost
|
||||
lldbUtility
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
list(APPEND LLDB_DRIVER_LINK_LIBS lldbHostPythonPathSetup)
|
||||
endif()
|
||||
|
||||
add_lldb_tool(lldb
|
||||
Driver.cpp
|
||||
Platform.cpp
|
||||
@@ -24,9 +34,7 @@ add_lldb_tool(lldb
|
||||
Option
|
||||
Support
|
||||
LINK_LIBS
|
||||
liblldb
|
||||
lldbHost
|
||||
lldbUtility
|
||||
${LLDB_DRIVER_LINK_LIBS}
|
||||
)
|
||||
|
||||
add_dependencies(lldb
|
||||
@@ -34,13 +42,6 @@ add_dependencies(lldb
|
||||
${tablegen_deps}
|
||||
)
|
||||
|
||||
if(DEFINED LLDB_PYTHON_DLL_RELATIVE_PATH)
|
||||
target_compile_definitions(lldb PRIVATE LLDB_PYTHON_DLL_RELATIVE_PATH="${LLDB_PYTHON_DLL_RELATIVE_PATH}")
|
||||
endif()
|
||||
if(DEFINED LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME)
|
||||
target_compile_definitions(lldb PRIVATE LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME="${LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME}")
|
||||
endif()
|
||||
|
||||
if(LLDB_BUILD_FRAMEWORK)
|
||||
# In the build-tree, we know the exact path to the framework directory.
|
||||
# The installed framework can be in different locations.
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "llvm/Support/Windows/WindowsSupport.h"
|
||||
#include "lldb/Host/windows/PythonPathSetup/PythonPathSetup.h"
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
@@ -433,90 +433,6 @@ SBError Driver::ProcessArgs(const opt::InputArgList &args, bool &exiting) {
|
||||
return error;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef LLDB_PYTHON_DLL_RELATIVE_PATH
|
||||
/// Returns the full path to the lldb.exe executable.
|
||||
inline std::wstring GetPathToExecutableW() {
|
||||
// Iterate until we reach the Windows API maximum path length (32,767).
|
||||
std::vector<WCHAR> buffer;
|
||||
buffer.resize(MAX_PATH /*=260*/);
|
||||
while (buffer.size() < 32767) {
|
||||
if (GetModuleFileNameW(NULL, buffer.data(), buffer.size()) < buffer.size())
|
||||
return std::wstring(buffer.begin(), buffer.end());
|
||||
buffer.resize(buffer.size() * 2);
|
||||
}
|
||||
return L"";
|
||||
}
|
||||
|
||||
/// \brief 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() {
|
||||
std::wstring modulePath = GetPathToExecutableW();
|
||||
if (modulePath.empty())
|
||||
return false;
|
||||
|
||||
SmallVector<char, MAX_PATH> utf8Path;
|
||||
if (sys::windows::UTF16ToUTF8(modulePath.c_str(), modulePath.length(),
|
||||
utf8Path))
|
||||
return false;
|
||||
sys::path::remove_filename(utf8Path);
|
||||
sys::path::append(utf8Path, LLDB_PYTHON_DLL_RELATIVE_PATH);
|
||||
sys::fs::make_absolute(utf8Path);
|
||||
|
||||
SmallVector<wchar_t, 1> widePath;
|
||||
if (sys::windows::widenPath(utf8Path.data(), widePath))
|
||||
return false;
|
||||
|
||||
if (sys::fs::exists(utf8Path))
|
||||
return SetDllDirectoryW(widePath.data());
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME
|
||||
/// Returns true if `python3x.dll` can be loaded.
|
||||
bool IsPythonDLLInPath() {
|
||||
#define WIDEN2(x) L##x
|
||||
#define WIDEN(x) WIDEN2(x)
|
||||
HMODULE h = LoadLibraryW(WIDEN(LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME));
|
||||
if (!h)
|
||||
return false;
|
||||
FreeLibrary(h);
|
||||
return true;
|
||||
#undef WIDEN2
|
||||
#undef WIDEN
|
||||
}
|
||||
#endif
|
||||
|
||||
/// Try to setup the DLL search path for the Python Runtime Library
|
||||
/// (python3xx.dll).
|
||||
///
|
||||
/// If `LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME` is set, we first check if
|
||||
/// python3xx.dll is in the search path. If it's not, we try to add it and
|
||||
/// check for it a second time.
|
||||
/// If only `LLDB_PYTHON_DLL_RELATIVE_PATH` is set, we try to add python3xx.dll
|
||||
/// to the search path python.dll is already in the search path or not.
|
||||
void SetupPythonRuntimeLibrary() {
|
||||
#ifdef LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME
|
||||
if (IsPythonDLLInPath())
|
||||
return;
|
||||
#ifdef LLDB_PYTHON_DLL_RELATIVE_PATH
|
||||
if (AddPythonDLLToSearchPath() && IsPythonDLLInPath())
|
||||
return;
|
||||
#endif
|
||||
WithColor::error() << "unable to find '"
|
||||
<< LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME << "'.\n";
|
||||
return;
|
||||
#elif defined(LLDB_PYTHON_DLL_RELATIVE_PATH)
|
||||
if (!AddPythonDLLToSearchPath())
|
||||
WithColor::error() << "unable to find the Python runtime library.\n";
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
std::string EscapeString(std::string arg) {
|
||||
std::string::size_type pos = 0;
|
||||
while ((pos = arg.find_first_of("\"\\", pos)) != std::string::npos) {
|
||||
@@ -821,7 +737,8 @@ int main(int argc, char const *argv[]) {
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
SetupPythonRuntimeLibrary();
|
||||
if (llvm::Error error = SetupPythonRuntimeLibrary())
|
||||
llvm::WithColor::error() << llvm::toString(std::move(error)) << '\n';
|
||||
#endif
|
||||
|
||||
// Parse arguments.
|
||||
|
||||
@@ -2,11 +2,18 @@ set(LLVM_TARGET_DEFINITIONS Options.td)
|
||||
tablegen(LLVM Options.inc -gen-opt-parser-defs)
|
||||
add_public_tablegen_target(LLDBDAPOptionsTableGen)
|
||||
|
||||
set(LLDB_DAP_LINK_LIBS lldbDAP)
|
||||
|
||||
if(WIN32)
|
||||
list(APPEND LLDB_DAP_LINK_LIBS lldbHostPythonPathSetup)
|
||||
list(APPEND LLDB_DAP_LINK_LIBS liblldb)
|
||||
endif()
|
||||
|
||||
add_lldb_tool(lldb-dap
|
||||
lldb-dap.cpp
|
||||
|
||||
LINK_LIBS
|
||||
lldbDAP
|
||||
${LLDB_DAP_LINK_LIBS}
|
||||
)
|
||||
|
||||
add_dependencies(lldb-dap
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
#undef GetObject
|
||||
#include <io.h>
|
||||
typedef int socklen_t;
|
||||
#include "lldb/Host/windows/PythonPathSetup/PythonPathSetup.h"
|
||||
#else
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
@@ -522,6 +523,11 @@ int main(int argc, char *argv[]) {
|
||||
"~/Library/Logs/DiagnosticReports/.\n");
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
if (llvm::Error error = SetupPythonRuntimeLibrary())
|
||||
llvm::WithColor::error() << llvm::toString(std::move(error)) << '\n';
|
||||
#endif
|
||||
|
||||
llvm::SmallString<256> program_path(argv[0]);
|
||||
llvm::sys::fs::make_absolute(program_path);
|
||||
DAP::debug_adapter_path = program_path;
|
||||
|
||||
Reference in New Issue
Block a user