From 5c47969350e9d90dc900672fe0e996f8262e2c63 Mon Sep 17 00:00:00 2001 From: Enrico Granata Date: Wed, 19 Jun 2013 03:05:52 +0000 Subject: [PATCH] Improvements to "command script import" to better support reloading in Xcode Xcode spawns a new LLDB SBDebugger for each debug session, and this was causing the reloading of python modules to fail across debug sessions (long story short: the module would not be loaded in the current instance of the ScriptInterpreter, but would still be present in sys.modules, hence the import call would just make a copy of it and not run it again Greg's new decorator uncovered the issue since it relies on actually loading the module's code rather than using __lldb_init_module as the active entity) This patch introduces the notion of a local vs. global import and crafts an appropriate command to allow reloading to work across debug sessions llvm-svn: 184279 --- .../Interpreter/ScriptInterpreterPython.cpp | 34 ++++++++++++++----- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/lldb/source/Interpreter/ScriptInterpreterPython.cpp b/lldb/source/Interpreter/ScriptInterpreterPython.cpp index 7242e182c245..cc40bea9784c 100644 --- a/lldb/source/Interpreter/ScriptInterpreterPython.cpp +++ b/lldb/source/Interpreter/ScriptInterpreterPython.cpp @@ -2670,14 +2670,25 @@ ScriptInterpreterPython::LoadScriptingModule (const char* pathname, // check if the module is already import-ed command_stream.Clear(); - command_stream.Printf("sys.getrefcount(%s)",basename.c_str()); + command_stream.Printf("sys.modules.__contains__('%s')",basename.c_str()); + bool does_contain = false; int refcount = 0; - // this call will fail if the module does not exist (because the parameter to it is not a string - // but an actual Python module object, which is non-existant if the module was not imported before) - bool was_imported = (ExecuteOneLineWithReturn(command_stream.GetData(), - ScriptInterpreterPython::eScriptReturnTypeInt, - &refcount, - ScriptInterpreter::ExecuteScriptOptions().SetEnableIO(false).SetSetLLDBGlobals(false)) && refcount > 0); + // this call will succeed if the module was ever imported in any Debugger in the lifetime of the process + // in which this LLDB framework is living + bool was_imported_globally = (ExecuteOneLineWithReturn(command_stream.GetData(), + ScriptInterpreterPython::eScriptReturnTypeBool, + &does_contain, + ScriptInterpreter::ExecuteScriptOptions().SetEnableIO(false).SetSetLLDBGlobals(false)) && does_contain); + // this call will fail if the module was not imported in this Debugger before + command_stream.Clear(); + command_stream.Printf("sys.getrefcount(%s)",basename.c_str()); + bool was_imported_locally = (ExecuteOneLineWithReturn(command_stream.GetData(), + ScriptInterpreterPython::eScriptReturnTypeInt, + &refcount, + ScriptInterpreter::ExecuteScriptOptions().SetEnableIO(false).SetSetLLDBGlobals(false)) && refcount > 0); + + bool was_imported = (was_imported_globally || was_imported_locally); + if (was_imported == true && can_reload == false) { error.SetErrorString("module already imported"); @@ -2686,10 +2697,17 @@ ScriptInterpreterPython::LoadScriptingModule (const char* pathname, // now actually do the import command_stream.Clear(); + if (was_imported) - command_stream.Printf("reload(%s)",basename.c_str()); + { + if (!was_imported_locally) + command_stream.Printf("import %s ; reload(%s)",basename.c_str(),basename.c_str()); + else + command_stream.Printf("reload(%s)",basename.c_str()); + } else command_stream.Printf("import %s",basename.c_str()); + bool import_retval = ExecuteMultipleLines(command_stream.GetData(), ScriptInterpreter::ExecuteScriptOptions().SetEnableIO(false).SetSetLLDBGlobals(false).SetMaskoutErrors(false)); PyObject* py_error = PyErr_Occurred(); // per Python docs: "you do not need to Py_DECREF()" the return of this function -- 2.34.1