Building XULRunner with Python

This page describes how to build and use XULRunner with the Python extension on Windows and while generally useful it is written based on experiences with accessibility projects. See also XULRunner. Or, if you are interested in working with XULRunner with Python on Linux, see Mark Lise's Post

With the Python extensions enabled XULRunner provides python script access to the DOM and XPCOM in addition to the usual Java Script. This gives access to Python features and modules and builds on Mark Hammond's pyXPCOM work from Active State. XPCOM components can also be created in Python.

Currently (Mar 07) Python is not enabled by default so a custom build of Mozilla is needed. This page provides instructions in the hope of eliminating much trial and error. You should also read the the developer documentation on source code and building as wells as PyXPCOM

XULRunner with Python promises to be a good platform for accessibility projects and both Jambu Alternative Input and the IAccessible2 test tool are using it. Of particular interested is access to MSAA and IAccessible2 via the Python comtypes package.

Development Machine Setup

First a word of warning that ZoneAlarm has exhibited memory leaks that cause build machines to crash with rather spurious errors. You may want to uninstall it if you suspect this to be a problem. You will also want to disable any virus scanner resident monitoring as that will slow builds.

Ensure the PC is running XP with all the latest Service Packs and patches applied.

Microsoft C++ compiler is required and whilst the current free version is Visual Studio 8 Express (MSVC8) you will almost certainly want to use Visual Studio .NET 2003 (MSVC71) which is not longer officially available. The issue is that XULRunner must be built with the same version of C as Python and with Python 2.5 that is MSVC71. Both must use the same version of the C runtime library MSVCRT?.DLL or crashes will ensue. The alternative is to build Python with MSVC8 as well asMozilla, but that may be problematic. It might also be possible to use the Open Source MinGW compiler with the correct MSVC run time but that is apparently not recommended. Apply any Service Packs and for MSVC71 SP 1 is available. The matching platform SDK is also needed and for MSVC71 that is .NET Framework SDK 1.1.

The latest Mozilla Build system is easy to use. Install the included Python distro usingpython25\python-2.5.msi. It doesn't need to be installed for the build but will be useful later when installing Python packages which look for entries in the Windows' registry.

Building

The batch filestart-msvc71.bat is used to launch the build console (MSys from the MinGw project ). If you plan to checkout often into empty folders you could modify it to set the CVSROOT environment variable.

set CVSROOT=:pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot

Having created amozilla project directory (e.g.C:\projects\mozilla or/c/projects/mozilla in msys) create the following .mozconfig file. Note this is complete and does not require the checkout of any other project specific .mozconfig files as sometimes shown. It effectively specifies a release build that is not particularly suitable for debugging XULRunner itself. It uses the trunk (or latest) code in CVS so may be unstable.

mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/../obj-xulrunner
mk_add_options MOZ_CO_PROJECT=xulrunner
ac_add_options --enable-application=xulrunner
ac_add_options --enable-extensions=python,default
ac_add_options --disable-javaxpcom
ac_add_options --disable-activex
ac_add_options --disable-activex-scripting
ac_add_options --disable-tests
ac_add_options --enable-optimize

To check out all the required source code and build it the first time with no local client.mk file, execute

cd /c/projects
cvs -d :pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot co mozilla/client.mk
cd mozilla
make -f client.mk

For subsequent updates from CVS followed by a build, use

cd /c/projects/mozilla
make -f client.mk

which will also checkout client.mk itself

For build only, without checkouts, use

make -f client.mk build

and see client.mk for other options.

The built XULRunner can then be found asc:\projects\obj-xulrunner\dist\bin\xulrunner.exe.

Using Python in XUL applications

Add the following to yourprefs.js during development

pref("browser.dom.window.dump.enabled", true);
pref("javascript.options.showInConsole", true);
pref("javascript.options.strict", true);
pref("nglayout.debug.disable_xul_cache", true);
pref("nglayout.debug.disable_xul_fastload", true);

HTML <script> tags specify that Python is used withtype="application/x-python" attribute. DOM scripting is pretty much as with Java Script. For example

def onLoad():
    btnTest = document.getElementById("btnTest")
    btnTest.addEventListener('command', onTest, False)

def onTest():
    window.alert('Button activated')

window.addEventListener('load', onLoad, False)

One possible gotcha is that the default python path used to find modules that areimported explicitly includes the xulrunner executable directory and the directory that is current when XULRunner launches. However it does not include any path related to the XUL application being run. Some work around will need to be found.

Unhandled exceptions are displayed in the JavaScript Error Console which can be opened usingxulrunner -jsconsole. One solution is to puttry .... except: print_exc() round any event handler to print tracebacks to stdout and use a python console to catch that output. The JSconsole can also be open and used from code, for example (in Javascript)

function openJavaScriptConsole() {
   var wwatch = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
                         .getService(Components.interfaces.nsIWindowWatcher);
   wwatch.openWindow(null, "chrome://global/content/console.xul", "_blank",
                    "chrome,dialog=no,all", null);
}


// dump to the js console (xulrunner -jsconsole)
function jsdump(str)
{
  Components.classes['@mozilla.org/consoleservice;1']
            .getService(Components.interfaces.nsIConsoleService)
            .logStringMessage(str);
}

function jserror(str)
{
    Components.utils.reportError(str);
}

A final tip is to use task manager to check for a zombie xulrunner process after a crash. A zombie will keep old code open and cause confusion when you make changes and run xulrunner again.

Deploying

Python must be installed on the target machine. Perhaps eventually a XULRunner with a minimal Python installation can be generated with something like py2exe or pyInstaller. Untill then simply deploy thedist\bin folder and the XUL application. Don't copy any.pyo files that exist for python modules in the application or errors will occur on the target machine.

It is possible to test for python in a batch file using something like

rem Check Python 2.5 installed
reg query "HKLM\SOFTWARE\Python\PythonCore\2.5" > nul 2>&1 || reg query "HKCU\SOFTWARE\Python\PythonCore\2.5" > nul 2>&1
if errorlevel 1 (
    echo Python 2.5 was not found. Please install it.
    echo Exiting...
    pause
    exit /b 1
    )

start "XULRunner with Python" "%moz_bin%\xulrunner.exe" -app application.ini %opts%
exit /b 0

See XULRunner:Deploying_XULRunner_1.8 for general information.

Sample

A sample XULRunner application with these Python features is available. This includes the pyXPCOM tests and a basic Python console from Alex Badea