diff --git a/lldb/bindings/python/CMakeLists.txt b/lldb/bindings/python/CMakeLists.txt --- a/lldb/bindings/python/CMakeLists.txt +++ b/lldb/bindings/python/CMakeLists.txt @@ -23,6 +23,18 @@ ${CMAKE_CURRENT_BINARY_DIR}/lldb.py ) +if (NOT WIN32) +add_custom_command( + OUTPUT ${LLVM_RUNTIME_OUTPUT_INTDIR}/lldb-python + VERBATIM + COMMAND ${CMAKE_COMMAND} -E copy lldb-python ${LLVM_RUNTIME_OUTPUT_INTDIR}/lldb-python + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} +) +add_custom_target(lldb-python-wrapper ALL DEPENDS + ${LLVM_RUNTIME_OUTPUT_INTDIR}/lldb-python +) +endif() + function(create_python_package swig_target working_dir pkg_dir) cmake_parse_arguments(ARG "NOINIT" "" "FILES" ${ARGN}) if(ARG_FILES) @@ -149,6 +161,11 @@ create_relative_symlink(${swig_target} ${LIBLLDB_SYMLINK_DEST} ${lldb_python_target_dir} ${LIBLLDB_SYMLINK_OUTPUT_FILE}) + + if (NOT WIN32) + add_dependencies(${swig_target} lldb-python-wrapper) + endif() + if(NOT LLDB_BUILD_FRAMEWORK) set(LLDB_ARGDUMPER_FILENAME "lldb-argdumper${CMAKE_EXECUTABLE_SUFFIX}") create_relative_symlink(${swig_target} "${LLVM_RUNTIME_OUTPUT_INTDIR}/${LLDB_ARGDUMPER_FILENAME}" diff --git a/lldb/bindings/python/lldb-python b/lldb/bindings/python/lldb-python new file mode 100755 --- /dev/null +++ b/lldb/bindings/python/lldb-python @@ -0,0 +1,19 @@ +#!/usr/bin/env python3 + +import subprocess +import os +import sys + +lldb = os.path.join(os.path.dirname(__file__), 'lldb') + +prefix = subprocess.run([lldb, "--python-prefix"], + check=True, stdout=subprocess.PIPE, encoding='utf8').stdout.strip() + +path = subprocess.run([lldb, "--python-path"], + check=True, stdout=subprocess.PIPE, encoding='utf8').stdout.strip() + +os.environ["PYTHONPATH"]= path + os.path.pathsep + os.environ.get("PYTHONPATH", "") + +python = os.path.join(prefix, "bin", "python3") + +os.execl(python, python, *sys.argv[1:]) diff --git a/lldb/docs/man/lldb.rst b/lldb/docs/man/lldb.rst --- a/lldb/docs/man/lldb.rst +++ b/lldb/docs/man/lldb.rst @@ -238,6 +238,10 @@ Prints out the path to the lldb.py file for this version of lldb. +.. option:: --python-prefix + + Prints out the sys.prefix for the python used by this lldb. + .. option:: -P Alias for --python-path diff --git a/lldb/docs/python_api_enums.rst b/lldb/docs/python_api_enums.rst --- a/lldb/docs/python_api_enums.rst +++ b/lldb/docs/python_api_enums.rst @@ -1291,6 +1291,10 @@ Find Python modules (PYTHONPATH) directory. +.. py:data:: ePathTypePythonPrefix + + Find Python's ``sys.prefix`` path. + .. py:data:: ePathTypeLLDBSystemPlugins System plug-ins directory diff --git a/lldb/include/lldb/lldb-enumerations.h b/lldb/include/lldb/lldb-enumerations.h --- a/lldb/include/lldb/lldb-enumerations.h +++ b/lldb/include/lldb/lldb-enumerations.h @@ -1011,7 +1011,8 @@ ePathTypeGlobalLLDBTempSystemDir, ///< The LLDB temp directory for this ///< system, NOT cleaned up on a process ///< exit. - ePathTypeClangDir ///< Find path to Clang builtin headers + ePathTypeClangDir, ///< Find path to Clang builtin headers + ePathTypePythonPrefix, ///< Find python's sys.prefix path }; /// Kind of member function. diff --git a/lldb/source/API/SBHostOS.cpp b/lldb/source/API/SBHostOS.cpp --- a/lldb/source/API/SBHostOS.cpp +++ b/lldb/source/API/SBHostOS.cpp @@ -63,6 +63,11 @@ case ePathTypePythonDir: #if LLDB_ENABLE_PYTHON fspec = ScriptInterpreterPython::GetPythonDir(); +#endif + break; + case ePathTypePythonPrefix: +#if LLDB_ENABLE_PYTHON + fspec = ScriptInterpreterPython::GetPythonPrefix(); #endif break; case ePathTypeLLDBSystemPlugins: diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h --- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h +++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h @@ -51,6 +51,7 @@ static llvm::StringRef GetPluginNameStatic() { return "script-python"; } static llvm::StringRef GetPluginDescriptionStatic(); static FileSpec GetPythonDir(); + static FileSpec GetPythonPrefix(); static void SharedLibraryDirectoryHelper(FileSpec &this_file); protected: diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp --- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp +++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp @@ -410,6 +410,20 @@ return g_spec; } +FileSpec ScriptInterpreterPython::GetPythonPrefix() { + FileSpec spec; + InitializePythonRAII initialize_guard; + wchar_t *pyhome = Py_GetPrefix(); + if (pyhome) { + char *pyhome8 = Py_EncodeLocale(pyhome, NULL); + if (pyhome8) { + spec.GetDirectory().SetString(pyhome8); + PyMem_Free(pyhome8); + } + } + return spec; +} + void ScriptInterpreterPython::SharedLibraryDirectoryHelper( FileSpec &this_file) { // When we're loaded from python, this_file will point to the file inside the diff --git a/lldb/test/API/functionalities/paths/TestPaths.py b/lldb/test/API/functionalities/paths/TestPaths.py --- a/lldb/test/API/functionalities/paths/TestPaths.py +++ b/lldb/test/API/functionalities/paths/TestPaths.py @@ -5,6 +5,7 @@ import lldb import os +import sys from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * from lldbsuite.test import lldbutil @@ -22,10 +23,12 @@ lldb.ePathTypeSupportExecutableDir, lldb.ePathTypeHeaderDir, lldb.ePathTypePythonDir, + lldb.ePathTypePythonPrefix, lldb.ePathTypeLLDBSystemPlugins, lldb.ePathTypeLLDBUserPlugins, lldb.ePathTypeLLDBTempSystemDir, - lldb.ePathTypeClangDir] + lldb.ePathTypeClangDir, + lldb.ePathTypePythonPrefix] for path_type in dir_path_types: f = lldb.SBHostOS.GetLLDBPath(path_type) @@ -42,6 +45,10 @@ self.assertTrue(any([os.path.exists(os.path.join(shlib_dir, f)) for f in filenames]), "shlib_dir = " + shlib_dir) + @no_debug_info_test + def test_prefix(self): + prefix = lldb.SBHostOS.GetLLDBPath(lldb.ePathTypePythonPrefix).GetDirectory() + self.assertEqual(os.path.realpath(sys.prefix), os.path.realpath(prefix)) @no_debug_info_test def test_directory_doesnt_end_with_slash(self): diff --git a/lldb/test/Shell/Driver/TestHelp.test b/lldb/test/Shell/Driver/TestHelp.test --- a/lldb/test/Shell/Driver/TestHelp.test +++ b/lldb/test/Shell/Driver/TestHelp.test @@ -63,5 +63,6 @@ CHECK: SCRIPTING CHECK: -l CHECK: --python-path +CHECK: --python-prefix CHECK: -P CHECK: --script-language diff --git a/lldb/tools/driver/Driver.h b/lldb/tools/driver/Driver.h --- a/lldb/tools/driver/Driver.h +++ b/lldb/tools/driver/Driver.h @@ -79,6 +79,7 @@ bool m_source_quietly = false; bool m_print_version = false; bool m_print_python_path = false; + bool m_print_python_prefix = false; bool m_wait_for = false; bool m_repl = false; bool m_batch = false; diff --git a/lldb/tools/driver/Driver.cpp b/lldb/tools/driver/Driver.cpp --- a/lldb/tools/driver/Driver.cpp +++ b/lldb/tools/driver/Driver.cpp @@ -201,6 +201,9 @@ if (args.hasArg(OPT_python_path)) { m_option_data.m_print_python_path = true; } + if (args.hasArg(OPT_python_prefix)) { + m_option_data.m_print_python_prefix = true; + } if (args.hasArg(OPT_batch)) { m_option_data.m_batch = true; @@ -398,6 +401,21 @@ return error; } + if (m_option_data.m_print_python_prefix) { + SBFileSpec python_file_spec = SBHostOS::GetLLDBPath(ePathTypePythonPrefix); + if (python_file_spec.IsValid()) { + char python_path[PATH_MAX]; + size_t num_chars = python_file_spec.GetPath(python_path, PATH_MAX); + if (num_chars < PATH_MAX) { + llvm::outs() << python_path << '\n'; + } else + llvm::outs() << "\n"; + } else + llvm::outs() << "\n"; + exiting = true; + return error; + } + return error; } diff --git a/lldb/tools/driver/Options.td b/lldb/tools/driver/Options.td --- a/lldb/tools/driver/Options.td +++ b/lldb/tools/driver/Options.td @@ -48,6 +48,10 @@ HelpText<"Alias for --python-path">, Group; +def python_prefix: F<"python-prefix">, + HelpText<"Prints out the sys.prefix for the python used by this lldb.">, + Group; + def script_language: Separate<["--", "-"], "script-language">, MetaVarName<"">, HelpText<"Tells the debugger to use the specified scripting language for user-defined scripts.">,