×
Namespaces

Variants
Actions

Archived:Python on Symbian/13. Extending Python on Symbian

From Nokia Developer Wiki
Jump to: navigation, search

Archived.pngAquivado: Este artigo foi arquivado, pois o conteúdo não é mais considerado relevante para se criar soluções comerciais atuais. Se você achar que este artigo ainda é importante, inclua o template {{ForArchiveReview|escreva a sua justificativa}}.

All PySymbian articles have been archived. PySymbian is no longer maintained by Nokia and is not guaranteed to work on more recent Symbian devices. It is not possible to submit apps to Nokia Store.

Article Metadata
Code ExampleArticle
Created: hamishwillee (30 Nov 2010)
Last edited: hamishwillee (08 May 2013)

Original Author: User:Mike.Jipping

This chapter provides a brief overview of how Python on Symbian can be extended using C++. It also touches on the mechanisms to call Python from within Symbian C++ code.

Contents

Introduction

Python is a rich and flexible programming language. Its core modules provide access to most of the functionality expected in a modern programming language, including support for adding and extending Python using Python itself (using classes and modules, as we discussed in Chapter 2).

Python for Symbian extends the core Python offering by giving access to many useful Symbian platform C++ APIs, which are encapsulated in developer-friendly Python APIs. To access new or different platform functionality, you are free to write your own extensions, or you can simply add code to optimize functionality that runs faster if written in C++.

This chapter provides a taste of what is needed to write C++ extensions, and provides references to where you can find more information. A full explanation is beyond the scope of this book because it requires a fairly deep understanding of Symbian C++, which is a variant of C++ that uses its own idioms and introduces new data types and objects.

In this chapter, we also provide a very shallow introduction to the converse approach of accessing Python functionality from a Symbian C++ application. This approach is useful if Python code accesses a C++ API that uses callbacks (since the C++ code must call back into Python).

Using C++ from Python

This section describes how Python functionality can be enhanced by incorporating C++ code into a Python program. This is referred to as extending Python.

Why Use Python Extensions?

There are a number of reasons why C++ code should be used by Python. One is performance. The Python interpreter on a Symbian device runs very quickly but, when performance is important, C++ code is typically faster than comparable Python code (because Python is interpreted by a software layer while C++ code runs directly on the phone processor).

As an example, consider an implementation of a C++ module called "mymath" that implements a cosine computation. The following Python code uses this computation and tests it against the Python cosine implementation:

import time, math
import mymath
 
start = time.time()
for x in range(360):
r = mymath.docos(x)
print time.time()-start
 
start = time.time()
for x in range(360):
r = math.cos(x)
print time.time()-start

This code compares the two cosine computations, and the C++ implementation runs 23% faster than the Python implementation.

Another reason to use C++ code from Python is to access hardware features of the phone that are not built into a Python module. This applies to new hardware features or to hardware features you want to use in a different way than is available through standard Python interfaces. For example, you may need to access new buttons on a device before access to them is provided in a Python module. Since C++ is the system programming langage for the Symbian platform, it is the first language to have access to all phone features and functionality. While the Python interface to the operating system is quite extensive, there are likely to be system calls that you need to be accessed in a new or different way. Extending Python is an easy way to make this happen.

Writing and Using a C++ Extension

Let's continue the cosine example from the previous subsection. Here is the C++ code to implement the docos() cosine computation:

#include "Python.h"
#include <math.h>
 
static PyObject *
docos(PyObject *self, PyObject *args)
{
double value, result;
 
if (!PyArg_ParseTuple(args, "d", &value)) return NULL;
 
result = cos(value);
return Py_BuildValue("d", result);
}
 
static PyMethodDef mymath_methods[] = {
{"docos", docos, METH_VARARGS},
{0, 0}
};
 
/* module entry-point (module-initialization) function */
PyMODINIT_FUNC
initmymath(void)
{
/* Create the module and add the functions */
PyObject *m = Py_InitModule("mymath", mymath_methods);
}

Note that we are not very clever in the docos() implementation: we simply call the cosine function built into the C/C++ math library.

Let's point out some elements of the definition of the docos() function:

  • The definition requires a reference to the object defining it and to function parameters. These are required for Python functions and are also present in the previous code, where all the parameters are contained in the args C++ parameter.
  • Note that the return is a tuple, built by a C++ function call.
  • Note that multiple use of PyObject objects. These objects are Python tuples formatted so that Python can work with them. C++ works with these objects and tuples through special functions that can interpret and build them.

This last element is at the core of Python extensions. PyObject objects represent data and class objects in Python. Any communication between C++ and Python happens using PyObject objects.

The code that implements a C++ extension must pay attention to several constraints:

  • It must start with
#include "Python.h"

The #include directive includes redefinition of some C++ structures and must be used before all others.

  • The C++ code should take care to convert Python objects. This includes the data objects we discussed previously as well as Python exceptions (not discussed here). Python exceptions should be used to represent all error conditions, including those generated by the operating system, as well as the implementation code.
  • The C++ code must include a method table. This table is a C++ array that holds PyMethodDef structs. These structs inform the Python runtime system which methods are implemented by the C++ code. For example, in the previous cosine implementation, we would declare the following table:
static PyMethodDef mymath_methods[] = {
{"docos", docos, METH_VARARGS},
{0, 0}
};
The PyMethodDef struct declares the name of the function, the implementation that name refers to, and the type of parameters used with the function. The typical method is METH_VARARGS, which indicates the Python style used in the example, but other methods exist, such as METH_NOARGS, where no parameters are used, and METH_KEYWORDS, where keywords are used for positional parameter assignment.
  • Finally, the function implementation needs an entry point, a kind of constructor used to initialize the implementation. The initialization is performed through a call to Py_InitModule, which creates a PyObject representation of the class to which the function belongs.

Note.pngNote: Names are important in the code that implements the C++ extension. The method table must be named "module_methods", where module is replaced by the name of the module you are implementing. Likewise, the entry point function must be named "initmodule", where module is replaced by the name of the module you are implementing.

The DLL must be given the platform security capabilities of all the applications that might attempt to use it - in practice this means that you need to give it as many capabilities as possible. This is done in the C++ project's MMP file, as shown in the following section. You should also take care to document any capabilities that are needed by users of your module. If you're unfamiliar with the topic, platform security is discussed further in Chapter 15).

When the extension code is complete, it is compiled into a dynamically loaded library (DLL). Compilation can be performed either from the command line of an operating system shell or through the Carbide.c++ Integrated Development Environment (IDE). Details on using Carbide.c++ are provided later in this chapter.

The extension DLL must be bundled with the Python programs that use it. Python extension users do not need to think about this process, they simply package their application as described in Chapter 16 and the application packager automatically includes any DLLs that have been referenced in the module and that are included in the application packager module repository. As an extension developer however, you need to ensure that the DLL is copied to the right place in the application packager - this is discussed in the reference documentation: http://pys60.garage.maemo.org/doc/s60/modulerepo.html.

It is important to note that extension modules bundled with a Python program are not available to other Python applications on the device. A unique copy of the extension module is made available for every application that bundles it (named using the application UID).

Using Carbide.c++

Developing the C++ code necessary for Python extension is a fairly straightforward process. Deploying this code, however, can be complicated and involves several configuration files. While the compilation and deployment of this library can be done from the command line, it is much more easily done through the Carbide.c++ IDE. This subsection will briefly walk through the steps necessary.

To use Symbian C++ for Python extension, you must install kits for Symbian C++ development. Find the "Symbian C++ tools" page on the Nokia Developer website (at http://www.developer.nokia.com/Develop/Other_Technologies/Symbian_C++/Tools/). You must install both the Application Development Toolkit and the Symbian C++ SDK. Then you must find the Python overlay for the C++ SDK and overlay that code on the SDK installation.

Once you have the proper installation environment, follow these steps using Carbide.c++:

  1. Begin by creating a new project. This should be a "Symbian OS C++ Project" found under the "File > New" menu. Selecting that menu option will bring up the new project dialog window shown in Figure 13.1:
    PythonOnSymbian Step1a.png
    In this window, select "Basic dynamically linked library (DLL)". Give the project a name in the next dialog window and select the SDK in the next window. Then click the "Finish" button. Carbide.c++ will create a project for you containing template code.
  2. Using the descriptions in this chapter, design and implement the code you need for your Python extension.
  3. When your code is to the point where you need to make the DLL, start with the MMP file. This is found under the "group" folder in the Project Explorer (see Figure 13.2):
    PythonOnSymbian Step3a.png
    You must add specifiers to the basic MMP file generated for you. You may select the provided links in Carbide.c++ or you can simply find the source (select the name of the MMP file on the bottom of the editor) and type in a few statements yourself.
    The MMP file for the "mymath" example is shown as follows:
    /*
    ============================================================================
    Name  : mymath.mmp
    Author  :
    Copyright  : Your copyright notice
    Description : This is the project specification file for mymath.
    ============================================================================
    */
     
    TARGET kf_mymath.pyd
    TARGETTYPE DLL
     
    USERINCLUDE ..\inc
    SYSTEMINCLUDE \epoc32\include
    SYSTEMINCLUDE \epoc32\include\stdapis
    SYSTEMINCLUDE \epoc32\include\python25
     
    SOURCEPATH ..\src
    SOURCE mymath.cpp
     
    CAPABILITY LocalServices NetworkServices ReadUserData UserEnvironment WriteUserData
    LIBRARY python25.lib
    LIBRARY estlib.lib
     
    EPOCALLOWDLLDATA
     
    NOSTRICTDEF
    DEFFILE mymath.def
    • Note the inclusion of more system include files as well as the EPOCALLOWDLLDATA specifier, the definition file additions, and the new library specifications (the "mymath" example needs the "estlib.lib" library for the "cos()" function). The TARGETTYPE should be DLL. Also note the name: "kf_module.pyd", where module is replaced by the name of the module you are implementing.
    • Note also that this DLL has been given all the user capabilities (using the CAPABILITY keyword). As discussed in the preceding section, in practice you'd seek to give it as many capabilities as possible.
  4. Once the MMP file is in place, you can build the C++ library file. When you are ready, you can build for the release target on the phone for which you are building. You will be able to find this in the SDK installation directory under "epoc32\release\gcce\urel".
  5. Now you need to place the library where the bundling software can find it. This place is located in the installation directory under the "module-repo\dev-modules" directory. In this directory, you need to create a folder with the name of your module. For the "mymath" example, this is the directory "C:\Program Files\PythonForS60-2.0\module-repo\dev-modules\mymath". In this new directory, place two files. The first is the library file ("kf_mymath.pyd" for our example). The second is a configuration file called "module_config.cfg", which needs to contain a single line, as follows:
    {'type': 'repo', 'deps': []}
  6. The final step is use the application packager to bundle the Python code with the library file you created.

Using Python from C++

While the typical way for Python and C++ to interact is to extend Python functionality, another way to mix the two languages is to use Python as part a larger application. This technique is referred to as embedding Python in an application. The difference between extending and embedding is that when you extend Python, the main components of the application is the Python interpreter and runtime environment, while if you embed Python, the main component may occasionally call the Python interpreter to run some Python code. The process of embedding Python is less straightforward than implementing an extension. However, many ideas and skills developed extending Python with C++ are useful when embedding Python.

At a very high level, embedding Python in C++ uses a very high level interface. This high level embedding is intended to execute a Python script that does not interact with the application directly. Consider the following simple code:

#include <Python.h>
 
int main(int argc, char *argv[])
{
Py_Initialize();
PyRun_SimpleString("from time import time,ctime\n"
"print 'Today is',ctime(time())\n");
Py_Finalize();
return 0;
}

This code starts by initializing the Python interpreter with Py_Initialize(). It then executes a Python script that is contained in a single string by calling PyRun_SimpleString(). The call to Py_Finalize() terminates the Python interpreter.

Obviously, this is a simple and contrived introduction to interacting with Python from C++. There are many other ways to interact at this high level, such as getting the Python code from a file with PyRun_SimpleFile() or compiling Python code with Py_CompileString(). The most effective interactions, however, come from deeper, more intimate collaborations with the Python runtime; there are many ways to work with a Python interpreter.

There are several reasons to embed Python in a C++ application. Providing scripting layers that allow the user write Python scripts to automate common tasks or extend a feature set is a common use. Allowing users to tailor an application to their needs by writing some scripts in Python is useful if some of the functionality can be written in Python more easily than in some other configuration language. Another use of embedding is as a configuration medium for an application. Sometimes complication configurations are better handled by languages that already exist and might be more familiar to a user.

Documentation on C++ interfaces to Python can be found from links outlined in the next section.

Further Reading

For further reading into combining Python with C++, here are some places to start:

Summary

This chapter provides a look at what is needed to write C++ extensions, the use of C++ code from Python. It also briefly introduces the idea of embedding Python into C++ code.

We provide a small example of how to create a C++ extension, including how to use the Carbide.c++ integrated development environment to accomplish this: File:PythonOnSymbianBookExampleCode ExtendingPython.zip

Licence icon cc-by-sa 3.0-88x31.png© 2010 Symbian Foundation Limited. Portions copyright Bogdan Galiceanu, Hamish Willee, Marcelo Barros de Almeida, Mike Jipping, Pankaj Nathani and others in wiki document history list. This document is licensed under the Creative Commons Attribution-Share Alike 2.0 license. See http://creativecommons.org/licenses/by-sa/2.0/legalcode for the full terms of the license.
Note that this content was originally hosted on the Symbian Foundation developer wiki.

This page was last modified on 8 May 2013, at 08:51.
51 page views in the last 30 days.

Was this page helpful?

Your feedback about this content is important. Let us know what you think.

 

Thank you!

We appreciate your feedback.

×