diff --git a/lldb/CMakeLists.txt b/lldb/CMakeLists.txt --- a/lldb/CMakeLists.txt +++ b/lldb/CMakeLists.txt @@ -31,24 +31,28 @@ endif() if (LLDB_ENABLE_PYTHON) - if (NOT CMAKE_CROSSCOMPILING) - execute_process( - COMMAND ${Python3_EXECUTABLE} - -c "import distutils.sysconfig; print(distutils.sysconfig.get_python_lib(True, False, ''))" - OUTPUT_VARIABLE LLDB_PYTHON_DEFAULT_RELATIVE_PATH - OUTPUT_STRIP_TRAILING_WHITESPACE) - - file(TO_CMAKE_PATH ${LLDB_PYTHON_DEFAULT_RELATIVE_PATH} LLDB_PYTHON_DEFAULT_RELATIVE_PATH) - else () - if ("${LLDB_PYTHON_RELATIVE_PATH}" STREQUAL "") - message(FATAL_ERROR - "Crosscompiling LLDB with Python requires manually setting - LLDB_PYTHON_RELATIVE_PATH.") - endif () - endif () - - set(LLDB_PYTHON_RELATIVE_PATH ${LLDB_PYTHON_DEFAULT_RELATIVE_PATH} - CACHE STRING "Path where Python modules are installed, relative to install prefix") + set(cachestring_LLDB_PYTHON_RELATIVE_PATH + "Path where Python modules are installed, relative to install prefix") + set(cachestring_LLDB_PYTHON_EXE_RELATIVE_PATH + "Path to python interpreter exectuable, relative to install prefix") + + foreach(var LLDB_PYTHON_RELATIVE_PATH LLDB_PYTHON_EXE_RELATIVE_PATH) + if(NOT DEFINED ${var} AND NOT CMAKE_CROSSCOMPILING) + execute_process( + COMMAND ${Python3_EXECUTABLE} + ${CMAKE_CURRENT_SOURCE_DIR}/bindings/python/get-python-config.py + ${var} + OUTPUT_VARIABLE value + OUTPUT_STRIP_TRAILING_WHITESPACE) + file(TO_CMAKE_PATH "${value}" value) + set(${var} ${value} CACHE STRING ${cachestring_${var}}) + else() + if ("${${var}}" STREQUAL "") + message(FATAL_ERROR + "Crosscompiling LLDB with Python requires manually setting ${var}.") + endif() + endif() + endforeach() endif () if (LLDB_ENABLE_LUA) diff --git a/lldb/bindings/python/get-python-config.py b/lldb/bindings/python/get-python-config.py new file mode 100755 --- /dev/null +++ b/lldb/bindings/python/get-python-config.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 + +import os +import sys +import argparse +import sysconfig +import distutils.sysconfig + + +def relpath_nodots(path, base): + rel = os.path.normpath(os.path.relpath(path, base)) + assert not os.path.isabs(rel) + parts = rel.split(os.path.sep) + if parts and parts[0] == '..': + raise ValueError(f"{path} is not under {base}") + return rel + +def main(): + parser = argparse.ArgumentParser(description="extract cmake variables from python") + parser.add_argument("variable_name") + args = parser.parse_args() + if args.variable_name == "LLDB_PYTHON_RELATIVE_PATH": + print(distutils.sysconfig.get_python_lib(True, False, '')) + elif args.variable_name == "LLDB_PYTHON_EXE_RELATIVE_PATH": + tried = list() + exe = sys.executable + while True: + try: + print(relpath_nodots(exe, sys.prefix)) + break + except ValueError: + tried.append(exe) + if os.path.islink(exe): + exe = os.path.join(os.path.dirname(exe), os.readlink(exe)) + continue + else: + print("Could not find a relative path to sys.executable under sys.prefix", file=sys.stderr) + for e in tried: + print("tried:", e, file=sys.stderr) + print("sys.prefix:", sys.prefix, file=sys.stderr) + sys.exit(1) + + else: + parser.error(f"unknown variable {args.variable_name}") + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt b/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt --- a/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt +++ b/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt @@ -3,6 +3,12 @@ endif() add_definitions(-DLLDB_PYTHON_RELATIVE_LIBDIR="${LLDB_PYTHON_RELATIVE_PATH}") +if(NOT LLDB_PYTHON_EXE_RELATIVE_PATH) + message(FATAL_ERROR "LLDB_PYTHON_EXE_RELATIVE_PATH is not set.") +endif() +add_definitions(-DLLDB_PYTHON_EXE_RELATIVE_PATH="${LLDB_PYTHON_EXE_RELATIVE_PATH}") + + if (LLDB_ENABLE_LIBEDIT) list(APPEND LLDB_LIBEDIT_LIBS ${LibEdit_LIBRARIES}) endif() 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,30 +410,31 @@ return g_spec; } +static const char GetInterpreterInfoScript[] = R"( +import os +import sys + +def main(lldb_python_dir, python_exe_relative_path): + info = { + "lldb-pythonpath": lldb_python_dir, + "language": "python", + "prefix": sys.prefix, + "executable": os.path.join(sys.prefix, python_exe_relative_path) + } + return info +)"; + +static const char python_exe_relative_path[] = LLDB_PYTHON_EXE_RELATIVE_PATH; + StructuredData::DictionarySP ScriptInterpreterPython::GetInterpreterInfo() { GIL gil; FileSpec python_dir_spec = GetPythonDir(); if (!python_dir_spec) return nullptr; - PythonString python_dir(python_dir_spec.GetPath()); - PythonDictionary info(PyInitialValue::Empty); - llvm::Error error = info.SetItem("lldb-pythonpath", python_dir); - if (error) - return nullptr; - static const char script[] = R"( -def main(info): - import sys - import os - name = 'python' + str(sys.version_info.major) - info.update({ - "language": "python", - "prefix": sys.prefix, - "executable": os.path.join(sys.prefix, "bin", name), - }) - return info -)"; - PythonScript get_info(script); - auto info_json = unwrapIgnoringErrors(As(get_info(info))); + PythonScript get_info(GetInterpreterInfoScript); + auto info_json = unwrapIgnoringErrors( + As(get_info(PythonString(python_dir_spec.GetPath()), + PythonString(python_exe_relative_path)))); if (!info_json) return nullptr; return info_json.CreateStructuredDictionary(); 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 @@ -51,8 +51,6 @@ stream = lldb.SBStream() self.assertTrue(info_sd.GetAsJSON(stream).Success()) info = json.loads(stream.GetData()) - if os.name == 'nt': #FIXME - return prefix = info['prefix'] self.assertEqual(os.path.realpath(sys.prefix), os.path.realpath(prefix)) self.assertEqual(