faqts : Computers : Programming : Languages : Python : Common Problems

+ Search
Add Entry AlertManage Folder Edit Entry Add page to http://del.icio.us/
Did You Find This Entry Useful?

50 of 62 people (81%) answered Yes
Recently 10 of 10 people (100%) answered Yes

Entry

Embedding the Python interpreter in a Windows app

Aug 13th, 2000 05:20
unknown unknown, Edward K. Ream, David Bolen


Embedding the Python interpreter in a Windows app can be summarized as
follows:
1. Do _not_ build Python into your .exe file directly.  On Windows,
Python must be a DLL to handle importing modules that are themselves
DLL's.  (This is the first key undocumented fact.) Instead, link to
python15.dll; it is typically installed in c:\Windows\System.  
You can link to Python statically or dynamically.  Linking statically
means linking against python15.lib The drawback is that your app won't
run if python15.dll does not exist on your system.
General note: python15.lib is the so-called "import lib" corresponding
to python.dll.  It merely defines symbols for the linker.
Borland note: convert python15.lib to OMF format using Coff2Omf.exe
first.
Linking dynamically greatly simplifies link options; everything happens
at run time.  Your code must load python15.dll using the Windows
LoadLibraryEx routine.  The code must also use access routines and data
in python15.dll (that is, Python's C API's) using pointers obtained by
the Windows GetProcAddress routine.  Macros can make using these
pointers transparent to any C code that calls routines in Python's C
API.
2. If you use SWIG, it is easy to create a Python "extension module"
that will make the app's data and methods available to Python.  SWIG
will handle just about all the grungy details for you.  The result is C
code that you link _into your .exe file_ (!)  You do _not_ have to
create a DLL file, and this also simplifies linking.
3.  SWIG will create an init function (a C function) whose name depends
on the name of the extension module.  For example, if the name of the
module is leo, the init function will be called initleo().  If you use
SWIG shadow classes, as you should, the init function will be called
initleoc().  This initializes a mostly hidden helper class used by the
shadow class.
The reason you can link the C code in step 2 into your .exe file is that
calling the initialization function is equivalent to importing the
module into Python! (This is the second key undocumented fact.)
4. In short, you can use the following code to initialize the Python
interpreter with your extension module.
    #include "python.h"
    ...
    Py_Initialize();  // Initialize Python.
    initmyAppc();  // Initialize (import) the helper class. 
    PyRun_SimpleString("import myApp") ;  // Import the shadow class.
5. There are two problems with Python's C API which will become apparent
if you use a compiler other than MSVC, the compiler used to build
python15.dll.
Problem 1: The so-called "Very High Level" functions that take FILE *
arguments will not work in a multi-compiler environment; each compiler's
notion of a struct FILE will be different.  Warnings should be added to
the Python documentation!  From an implementation standpoint these are
very _low_ level functions.
Problem 2: SWIG generates the following code when generating wrappers to
void functions:
    Py_INCREF(Py_None);
    _resultobj = Py_None;
    return _resultobj;
Alas, Py_None is a macro that expands to a reference to a complex data
structure called _Py_NoneStruct inside python15.dll.  Again, this code
will fail in a mult-compiler environment.  Replace such code by:
        return Py_Build("");
It may be possible to use SWIG's %typemap command to make the change
automatically, though I have not been able to get this to work (I'm a
complete SWIG newbie.)
6. Using a Python shell script to put up a Python interpreter window
from inside your Windows app is not a good idea; the resulting window
will be independent of your app's windowing system.  Rather, you (or the
wxPythonWindow class) should create a "native" interpreter window.  It
is easy to connect that window to the Python interpreter.  You can
redirect Python's i/o to _any_ object that supports read and write, so
all you need is a Python object (defined in your extension module) that
contains read and write methods.
------Comments by David Bolen---------
Just a few incomplete thoughts:
* I actually found the Extending and Embedding documentation
  reasonably good - at least enough to let me construct a project I
  needed when I first started with Python - so I'm not sure about the
  undocumented comments.  Yes, embedding is only afforded a small
  amount of space per-se, but aside from interpreter initialization,
  it's almost identical to extending so you can look at the
  documentation in that light.  Of course more info can never hurt, so
  I think your efforts are definitely in the right direction,
  particularly where they highlight issues for cross-compiler
  compatibility.
  To be honest, in my own embedding work, what I missed up front was
  more information about creating objects in C that worked like
  built-in types or classes.  It seems to me you really have to look
  at the Python source itself to get a better handle on that process.
  Then again maybe I'm just wierd - unintentionally, it turned out my
  first use of Python was to embed it within a multi-threaded C
  application, with real-time communication between the Python and
  native C threads.  At the time I definitely ran into some
  uncertainties with respect to the global interpreter thread lock and
  so on, but it was only later that I realized I probably started at
  the wrong end of the curve :-)
* I don't know about anyone else but I find your use of the terms
  "static" and "dynamic" with respect to linking a bit unintuitive.
  To my mind (and when I typically see them used), static linking is
  just that - it statically binds the library code into your
  executable.  So if you were going to statically link Python into
  your executable you would directly bring the Python interpreter in,
  and would have no dependence on python15.dll.  E.g., it would be
  akin to 'freeze'ing Python.  You are right, it would prevent
  dynamically loading other extension modules that depended on the
  DLL, but it's still one possible approach if you really want to have
  no dependency on external DLLs and you know which modules your
  embedded Python scripts need access to.
  On the other hand, dynamic linking is when you link against an
  import library (e.g., python15.lib) in order to reference an
  external DLL at runtime.  You are dynamically linked to the DLL.
  Dynamically "loading" a DLL at run-time is an entirely different
  beast, and isn't a link time "term" at all, since the linking stage
  has no knowledge of the DLL access at all.
  Note also that your comment about "Linking dynamically" (run time
  loading) greatly simplifying link options is certainly true, since
  there aren't any link options involved :-)  But it does make life
  more complicated for the code that has to dynamically load and
  locate the functions to be used.  Even with macros it's a bit of
  work, since you have to deal with potential error conditions that
  can't exist in the other cases (e.g., the inability to even locate
  the function at hand).
  I guess the more recent MS "delay loading" support starts to blur
  the line between these approaches even further (I haven't tried
  delay-loading the Python DLL myself yet).
* While run-time loading would permit your application to run without
  a python DLL on the system, if using the Python interpreter is a key
  part of your application, what's the point?  So in general, unless
  the ability to run without Python is crucial, I'd suggest just going
  with the standard dynamic linking approach as the suggested method.
* On points 2-4, while going the SWIG route is certainly doable, it's
  probably also worth noting that for a simple embedded application
  (in my case I really only offered about 6-12 methods, a bunch of
  fixed constant objects and stdout/stderr objects to reroute the
  Python output to my application) it's not really necessary.  It's
  pretty easy to just define your own function table and write your
  functions, particularly if they aren't pre-existing and the reason
  you are writing them is just to interface to Python.  SWIG is fine
  too, but for simple stuff it's just an extra tool to have to have
  around (and it does create some issues by default, as you noted with
  the Py_None return template it uses).
* You've definitely got a point about the FILE structure - it might be
  interesting to see if there was any way to create a shim module that
  might help out (e.g., a DLL built with MSC to work with with Python
  DLL but exporting the typical C RTL functions that use FILE *).
* For Py_None, should that be Py_BuildValue("") and not Py_Build("")?