Labels

lego (12) Linux (39) pi (20) Thinkpads (4)

Friday, 7 March 2014

Debugging XBMC Plugins

I've been learning XBMC plugin development over the past few months.  I thought it would be a good time to review my remote debugging configuration.  When I had started setting up a debugging environment, I discovered the information available was fragmented and obsolete.

A helpful source is HOW-TO:Debug Python Scripts with Eclipse.  I will refer to it throughout.

Development Environment (IDE)


You can do a lot with just using gedit (with it's python syntax highlighting).  But when things get more complicated, you'll need a place to debug.  An IDE that I've used before, on Java and Perl projects, was Eclipse.  Eclipse has a PyDev plugin available, that can be easily installed through the Updates (Help...Install New Software), which is required to add Python integrated functionality to Eclipse.  Because I didn't have Eclipse installed on my particular current system, I decided to opt for downloading LiClipse instead.  It is "lightweight" and has PyDev already installed. You'll need a Python interpreter installed -- not an issue on most Linux systems.  XBMC also uses your native Linux Python interpreter.

Refer to section 2 in HOW-TO:Debug Python Scripts with Eclipse for setting up PyDev within XBMC.

Setup Workspace

I have all my XBMC plugins located in a particular development folder named development/xbmc.  I simply setup my workspace to this folder.  For each plugin, represented by single subfolder for each (such as XBMC-pluginname), I simply go to File -> New, PyDev Project.  Give the project the appropriate name (XBMC-pluginname), select Python for Project type.  Select Grammar Version 2.7.  For Interpreter, select Default. Click on the "Click here to configure an interpreter not listed".  In the upper right pane, click the Quick Auto-Config, which will configure an interpreter for you.  If you have multiple Python Interpreters installed, repeat until the required version is created.

Before clicking the Finish button, change the radio button to "Don't configure PYTHONPATH (to be done manually later on)".


Refer to section 3 in HOW-TO:Debug Python Scripts with Eclipse for more assistance.  This part of the Wiki is out-of-date, however.

Setup Pysrc (for remote-debugging)

If you want to remote-debug your plugin (that is step through your code while running), you will need to do some further setup.  First, you need to locate the pysrc library files that came with your PyDev install.  If you do a (find . | grep pysrc) from within your Eclipse install, you should find them located in plugins org.python.pydev_3... folder.  Mine were located at ./plugins/org.python.pydev_3.3.3.201401272005/pysrc/.

Next, you'll need to find the global library location for you Python interpreter.   You can do so by running the following:

python -c "from distutils.sysconfig import *; print(get_python_lib())"
My path was /usr/lib/python2.7/dist-packages.  Copy the pysrc folder into this noted folder (you'll need to be root).  

You'll also need to create an empty file called __init__.py within this pysrc folder ( /usr/lib/python2.7/dist-packages/pysrc).  This will allow XBMC transverse into it.

Modify Your XBMC Plugin

To enable remote-debugging to your application, you will need to add some code to your plugin (say into your default.py, below the import statements).  Code I've put in mine resemble this:

try:
    remote_debugger = addon.getSetting('remote_debugger')
    remote_debugger_host = addon.getSetting('remote_debugger_host')

    # append pydev remote debugger
    if remote_debugger == 'true':
        # Make pydev debugger works for auto reload.
        # Note pydevd module need to be copied in XBMC\system\python\Lib\pysrc
        import pysrc.pydevd as pydevd
        # stdoutToServer and stderrToServer redirect stdout and stderr to eclipse console
        pydevd.settrace(remote_debugger_host, stdoutToServer=True, stderrToServer=True)
except ImportError:
    sys.stderr.write("Error: " + "You must add org.python.pydev.debug.pysrc to your PYTHONPATH.")
    sys.exit(1)
except :
    pass
The code will look for the parameter "remote_debugger" and "remote_debugger_host" in your settings.xml file.  If neither is found, an exception will be thrown, and the debugging will be disabled.  This will allow you to maintain one version of your code.  You could use a constant variable instead, but then you'd need to set it somewhere.  I see others implementing a variable like REMOTE_DEBUG and then setting it True or False in the same class, but if you forgot to switch it to False, and push your code out, it'll fail if someone deploys it.  I found my approach elegant, as the debugger code will be inactive unless the user adds the following two lines to their settings.xml:

    <setting id="remote_debugger" value="true" />
    <setting id="remote_debugger_host" value="localhost" />

The remote_debugger_host allows you to use a remote system for debugging, rather than using the same machine.  This allows you to debug your plugin on a Raspberry Pi and debug it using your laptop.  If you are debugging on the same device (laptop running XBMC), then you can leave this as localhost.  Otherwise, change it to your IP of your debugging machine.

The above code was adapted from  HOW-TO:Debug Python Scripts with Eclipse .


Raspberry Pi for Debugging


Just like you setup pysrc earlier on your computer, if you want to run your plugin from a device, such as Raspberry Pi, to remote-debug, you'll need to copy the pysrc folder, found earlier, to your Raspberry Pi.  Follow the same steps under Setup Pysrc, copying the source folder from your computer with Eclipse or LiClipse installed, to your device.  In my case, my Raspberry Pi used the same dist-packages folder (so I copied to usr/lib/python2.7/dist-packages/pysrc).

You may need to add port 5678 to your computer's firewall to allow inbound connections from your debugging device.


Adding PyDev Debugger to your View


There are several ways of accomplishing this.  I prefer going to Window -> Customize Perspective, selecting Command Groups Availability and checkboxing "PyDev Debug".  This will add a PyDev menu with the buttons "Start Debug Server" and "Stop Debug Server" to my Eclipse menu.


Actually Doing the Remote-Debugging...


To start the debugger, I flip to Debug Perspective, and then click the Start Debug Server from PyDev menu.  In the Debug Server window, you'll see "Debug Server at port: 5678". 

Now you can open XBMC.  If you have the remote-debugger code added to your plugin AND have the remote_debugger and remote_debugger_host set in settings.xml, if you try to load the plugin in XBMC, it should try to communicate to the Eclipse debugger.  If it fails to connect to the debugger, it'll push a 110 Connection Failed to the xbmc.log file.  If you see a "You must add org.python.pydev.debug.pysrc to your PYTHONPATH" error, that means the pysrc isn't accessible on your XBMC device (did you add the pysrc folder to the dist-packages folder?  did you include an empty __init__.py  file within that directory?).

If it is working, XBMC should "halt" while your debugger is passed control.  In the Debug panel, you should see an unknown with MainThread show up.  This represents the session running on your XBMC device.  You can now step through the code using standard debugging techniques.  You can also simply "Resume" (F8) to continue running to completion the plugin.



Refer to HOW-TO:Debug Python Scripts with Eclipse for further advise on debugging.

Have fun :) 

No comments:

Post a Comment