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 @@ -149,6 +149,12 @@ create_relative_symlink(${swig_target} ${LIBLLDB_SYMLINK_DEST} ${lldb_python_target_dir} ${LIBLLDB_SYMLINK_OUTPUT_FILE}) + if (NOT WIN32) + add_custom_command(TARGET ${swig_target} POST_BUILD VERBATIM + COMMAND ${CMAKE_COMMAND} -E "create_symlink" "lldb" "lldb-python" + WORKING_DIRECTORY ${LLVM_RUNTIME_OUTPUT_INTDIR}) + 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/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 @@ -43,7 +43,7 @@ #include #include -// Includes for pipe() +// Includes for pipe(), execv() #if defined(_WIN32) #include #include @@ -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; } @@ -867,7 +885,49 @@ return llvm::None; } -int main(int argc, char const *argv[]) { +static bool should_exec_python(llvm::StringRef argv0) { +#if defined(_WIN32) + return false; +#else + return argv0 == "lldb-python" || argv0.endswith("/lldb-python"); +#endif +} + +static void exec_python(int argc, char *argv[]) { +#if !defined(_WIN32) + SBFileSpec pathspec = SBHostOS::GetLLDBPythonPath(); + if (!pathspec.IsValid()) { + llvm::errs() << "could not find python path.\n"; + exit(1); + } + std::string pythonpath = pathspec.GetDirectory(); + const char *oldpath = ::getenv("PYTHONPATH"); + if (oldpath) + pythonpath = pythonpath + ":" + oldpath; + ::setenv("PYTHONPATH", pythonpath.c_str(), true); + SBFileSpec spec = SBHostOS::GetLLDBPath(ePathTypePythonPrefix); + if (!spec.IsValid()) { + llvm::errs() << "could not find python prefix.\n"; + exit(1); + } + spec.AppendPathComponent("bin"); + spec.AppendPathComponent("python3"); + char buf[PATH_MAX]; + size_t num_chars = spec.GetPath(buf, PATH_MAX); + if (num_chars >= PATH_MAX) { + llvm::errs() << "path too long.\n"; + exit(1); + } + char *python_exe = buf; + argv[0] = python_exe; + ::execv(python_exe, argv); + llvm::errs() << "could not exec python.\n"; + exit(1); +#endif +} + +int main(int argc, char *argv[]) { + // Editline uses for example iswprint which is dependent on LC_CTYPE. std::setlocale(LC_ALL, ""); std::setlocale(LC_CTYPE, ""); @@ -877,17 +937,19 @@ llvm::InitLLVM IL(argc, argv, /*InstallPipeSignalExitHandler=*/false); // Parse arguments. - LLDBOptTable T; - unsigned MissingArgIndex; - unsigned MissingArgCount; - ArrayRef arg_arr = makeArrayRef(argv + 1, argc - 1); - opt::InputArgList input_args = - T.ParseArgs(arg_arr, MissingArgIndex, MissingArgCount); llvm::StringRef argv0 = llvm::sys::path::filename(argv[0]); - - if (input_args.hasArg(OPT_help)) { - printHelp(T, argv0); - return 0; + bool will_exec_python = should_exec_python(argv0); + unsigned MissingArgIndex = 0; + unsigned MissingArgCount = 0; + ArrayRef arg_arr = makeArrayRef(argv + 1, argc - 1); + opt::InputArgList input_args; + if (!will_exec_python) { + LLDBOptTable T; + input_args = T.ParseArgs(arg_arr, MissingArgIndex, MissingArgCount); + if (input_args.hasArg(OPT_help)) { + printHelp(T, argv0); + return 0; + } } // Check for missing argument error. @@ -920,6 +982,9 @@ } SBHostOS::ThreadCreated(""); + if (will_exec_python) + exec_python(argc, argv); + signal(SIGINT, sigint_handler); #if !defined(_MSC_VER) signal(SIGPIPE, SIG_IGN); 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.">,