[cig-commits] r6454 - in cs: . pyrexembed pyrexembed/trunk pyrexembed/trunk/examples pyrexembed/trunk/examples/fltk pyrexembed/trunk/scripts

leif at geodynamics.org leif at geodynamics.org
Wed Mar 28 17:39:37 PDT 2007


Author: leif
Date: 2007-03-28 17:39:37 -0700 (Wed, 28 Mar 2007)
New Revision: 6454

Added:
   cs/pyrexembed/
   cs/pyrexembed/trunk/
   cs/pyrexembed/trunk/BUGS
   cs/pyrexembed/trunk/CHANGELOG
   cs/pyrexembed/trunk/COPYING
   cs/pyrexembed/trunk/CREDITS
   cs/pyrexembed/trunk/INSTALL
   cs/pyrexembed/trunk/README
   cs/pyrexembed/trunk/examples/
   cs/pyrexembed/trunk/examples/fltk/
   cs/pyrexembed/trunk/examples/fltk/README
   cs/pyrexembed/trunk/examples/fltk/pyfltklite.pyxe
   cs/pyrexembed/trunk/examples/fltk/setup.py
   cs/pyrexembed/trunk/examples/fltk/test.py
   cs/pyrexembed/trunk/pyrexembed.py
   cs/pyrexembed/trunk/scripts/
   cs/pyrexembed/trunk/scripts/pyrexembed
   cs/pyrexembed/trunk/setup.py
Log:
Imported pyrexembed 0.1.1.


Added: cs/pyrexembed/trunk/BUGS
===================================================================
--- cs/pyrexembed/trunk/BUGS	2007-03-28 23:21:42 UTC (rev 6453)
+++ cs/pyrexembed/trunk/BUGS	2007-03-29 00:39:37 UTC (rev 6454)
@@ -0,0 +1,7 @@
+- within #embed{ blocks, the function declaration must be
+  on one line, which can be annoying if the function has a long
+  name or takes a lot of arguments
+
+- most likely a lot more bugs
+
+

Added: cs/pyrexembed/trunk/CHANGELOG
===================================================================
--- cs/pyrexembed/trunk/CHANGELOG	2007-03-28 23:21:42 UTC (rev 6453)
+++ cs/pyrexembed/trunk/CHANGELOG	2007-03-29 00:39:37 UTC (rev 6454)
@@ -0,0 +1,9 @@
+2005-11-09
+
+    Added support for setting the filetype of the generated shim
+    file (which defaults to .cpp)
+
+2005-11-08
+
+    First release
+    

Added: cs/pyrexembed/trunk/COPYING
===================================================================
--- cs/pyrexembed/trunk/COPYING	2007-03-28 23:21:42 UTC (rev 6453)
+++ cs/pyrexembed/trunk/COPYING	2007-03-29 00:39:37 UTC (rev 6454)
@@ -0,0 +1,5 @@
+
+This software package is released under the terms of the
+GNU Lesser General Public License, the full text of which
+is available from the GNU website, http://www.gnu.org
+

Added: cs/pyrexembed/trunk/CREDITS
===================================================================
--- cs/pyrexembed/trunk/CREDITS	2007-03-28 23:21:42 UTC (rev 6453)
+++ cs/pyrexembed/trunk/CREDITS	2007-03-29 00:39:37 UTC (rev 6454)
@@ -0,0 +1,4 @@
+
+pyrexembed was written by David McNab,
+david at freenet.org.nz
+

Added: cs/pyrexembed/trunk/INSTALL
===================================================================
--- cs/pyrexembed/trunk/INSTALL	2007-03-28 23:21:42 UTC (rev 6453)
+++ cs/pyrexembed/trunk/INSTALL	2007-03-29 00:39:37 UTC (rev 6454)
@@ -0,0 +1,18 @@
+
+To install pyrexembed, you need to:
+
+1.  Have Python installed, version 2.3 or later
+
+2.  Ensure you have a recent version of Pyrex installed.
+
+    You can get Pyrex from:
+        - http://www.cosc.canterbury.ac.nz/~greg/python/Pyrex/
+
+3.  cd into the toplevel pyrexembed directory (where this INSTALL
+    file is), become root, and type 'python setup.py install'.
+
+    This will install the supporting pyrexembed.py module into
+    your python site-packages library
+
+4.  For more information, refer to the README file
+

Added: cs/pyrexembed/trunk/README
===================================================================
--- cs/pyrexembed/trunk/README	2007-03-28 23:21:42 UTC (rev 6453)
+++ cs/pyrexembed/trunk/README	2007-03-29 00:39:37 UTC (rev 6454)
@@ -0,0 +1,226 @@
+README file for pyrexembed package
+
+1. What is pyrexembed?
+
+    pyrexembed is a scheme which eliminates a lot of
+    the effort needed when writing Pyrex extensions to
+    wrap C++ libraries
+
+1.1. What is Pyrex?
+
+    Pyrex is a brilliant fusion of Python and straight C,
+    that allows Python C extensions to be written in clean
+    simple code.
+
+    It takes most of the pain out of writing
+    Python extensions, and to a large extent, gives you
+    the best of both the Python and C worlds.
+
+    http://www.cosc.canterbury.ac.nz/~greg/python/Pyrex/
+
+2. Why did you write pyrexembed?
+
+    As good as Pyrex is, it cannot be used out of the box
+    to wrap C++ code. The Pyrex author is very busy, so
+    there's no telling when (or if) he'll be able to
+    get around to implementing C++ support in Pyrex.
+
+    The usual way to wrap C++ code in Pyrex is to write
+    a set of C 'shim' functions which wrap all needed C++
+    code in a pure-C interface, then call these functions
+    from within your Pyrex code.
+
+    The problem is that this ends up being very labour-intensive
+    and prone to errors from maintenance oversights, because one
+    needs to declare, define, import or invoke these shim functions
+    in four different places:
+        - C header file, used in pyrex module
+        - C++ source file, defining the shim function
+        - Pyrex source file, within an 'cdef extern from' block
+        - Pyrex source file, in the invocation
+    This makes for quite some pain in keeping the four areas in sync.
+
+    I wanted a much easier way to do it.
+
+    pyrexembed gives the solution, because it eliminates most of
+    the labour involved and makes your coding hours a lot easier.
+    You'll be able to wrap a C++ library in a fraction of the time
+    with far less pain.
+
+    You only write the shim code once - as C++ markup inside your
+    pyrex file - right near where your invoke it.
+
+3. What's the basic idea of pyrexembed?
+
+    pyrexembed is a scheme which allows you to embed C++ code
+    into Pyrex sources using a simple markup syntax.
+
+    Using pyrexembed markup, you can do all your C++ things,
+    including writing shim functions on the fly, and use
+    these casually from within your Pyrex code.
+
+    pyrexembed processes your pyrex file (say, 'myfile.pyxe'
+    (note - your file must have a .pyxe extension), extracts
+    the markup, and creates three files:
+        - myfile.pyx
+            - a syntactically-valid pyrex file with all the
+              needed extern cdefs automatically inserted
+        - myfile_embed.cpp
+            - a C++ source file, containing all the C++
+              code extracted from the markups in myfile.pyxe,
+              with all embedded wrap functions declared as
+              'extern "C"'.
+        - myfile_embed.h
+            - a C header file, containing 'extern' defs of
+              all embedded C-wrapped C++ functions
+
+4. How do I use it?
+
+    Follow these steps:
+
+        1. Ensure you have Pyrex installed
+
+        2. Type (as root) 'python setup.py install' in the
+           toplevel directory of the pyrexembed package, to
+           install the pyrexembed.py module and its invocation
+           script
+
+        3. Consult the simple example code to see what is involved
+           in actual usage. The example does a partial wrap-job
+           of the C++ 'FLTK' gui widgets library.
+
+        4. Within examples/fltk:
+
+            - type 'python setup.py install' (as root) to build
+              and install the example extension
+
+            - type 'python test.py' to see the extension module
+              you've created in action
+
+            - look in pyfltklite.pyxe, examine the markups, then
+              compare that file with the newly generated files
+              pyfltklite.pyx, pyfltklite_embed.cpp and 
+              pyfltklite_embed.h, and you'll see what's going on
+
+    There are two ways to invoke pyrexembed to generate the .pyx,
+    .c[pp] and .h files from your .pyxe file:
+
+        1. As done in setup.py in the example - import pyrexembed,
+           then invoke pyrexembed.process(pyxefile, filetype), or
+        2. Run pyrexembed as a command, giving the pyxe filename
+           and optionally the shim filetype (default '.cpp') as
+           arguments
+
+5. Markups syntax summary
+
+5.1. #header{
+
+    This markup indicates the start of a block of code which should
+    be copied verbatim into the generated 'somefile_embed.cpp'
+    source file.
+
+    In the code block, you can do anything that's valid in C++,
+    including:
+        - pull in include files ('#include ...')
+        - do #defines
+        - declare data structures, functions, even classes
+
+    Note that any functions you declare in a #header{ block will
+    not be visible to your pyrex code
+
+    To end a #header{ block, put a #}header on a line by itself.
+
+    You can have as many #header{ ... #}header blocks in your .pyxe
+    file as you want. They will be concatenated together at the
+    top of the generated .cpp file.
+
+    Example:
+
+        #header{
+        #include <stdio.h>
+        #define FOO "bar"
+        #}header
+
+    or:
+
+        #header{
+        void some_private_function(int arg1, char *arg2)
+        {
+            ... body of function
+        }
+        #}header
+
+5.2. #embed{
+
+    This markup provides a convenient means of defining
+    a C 'shim' function which you want to access from your
+    Pyrex code.
+
+    The syntax is:
+
+        #embed{  <c function declaration>
+
+            <body of C function, C++ code is ok>
+
+        #}embed
+
+    Note that you will not need the usual enclosing braces
+    around the function body, because these will be added
+    automatically.
+
+    An #embed{ tag does several things:
+        - adds the c func declaration to the generated
+          'myfile_embed.h' file as a pure extern def
+        - adds the c func declaration (as 'extern "C"'), along
+          with the code body enclosed in braces, to the
+          generated 'myfile_embed.cpp' file
+        - adds the declaration to the generated 'myfile.pyx'
+          pyrex file within a 'cdef extern from "myfile_embed.h"'
+          block
+
+    You should terminate a #embed{ tag with #}embed
+
+    Note that you can place #embed{ ... #}embed blocks anywhere
+    within your .pyxe file, even in the middle of function
+    and method definitions!
+
+    Note - within #embed{ functions, you should not use any
+    fancy data types. Limit yourself to:
+        - core C types (eg 'int', 'float')
+        - void*
+        - char*
+    For other types, such as C++ class instances, use casts to
+    move them to and from opaque (void*) pointers.
+
+    IMPORTANT - the C declaration must be given in full on only
+    one line, the same line as the '#embed{'. You cannot wrap it
+    onto several lines. You cannot use backslashes to line-wrap it!!
+
+    Example:
+
+        cdef class MyClass:
+
+            cdef void *thisptr
+
+        def __init__(self, arg):
+
+            # create constructor shim func
+            #embed{ void *MyClass_init(int arg)
+
+                return (void *)(new MyClass(arg));
+
+            #}embed
+
+            self.thisptr = MyClass_init(arg)
+
+        def dosomething(self, arg):
+
+            # create shim for method 'dosomething'
+            #embed{ int MyClass_dosomething(void *obj, float arg)
+
+                return ((MyClass *)obj)->dosomething(arg);
+
+            #}embed
+
+            return MyClass_dosomething(self.thisptr, arg)
+

Added: cs/pyrexembed/trunk/examples/fltk/README
===================================================================
--- cs/pyrexembed/trunk/examples/fltk/README	2007-03-28 23:21:42 UTC (rev 6453)
+++ cs/pyrexembed/trunk/examples/fltk/README	2007-03-29 00:39:37 UTC (rev 6454)
@@ -0,0 +1,12 @@
+#@+leo-ver=4
+#@+node:@file examples/fltk/README
+#@@nocolor
+
+This example implements a partial wrapping of the FLTK
+gui library.
+
+The setup.py script might need some tweaks to get it working
+right in your build environment.
+
+#@-node:@file examples/fltk/README
+#@-leo

Added: cs/pyrexembed/trunk/examples/fltk/pyfltklite.pyxe
===================================================================
--- cs/pyrexembed/trunk/examples/fltk/pyfltklite.pyxe	2007-03-28 23:21:42 UTC (rev 6453)
+++ cs/pyrexembed/trunk/examples/fltk/pyfltklite.pyxe	2007-03-29 00:39:37 UTC (rev 6454)
@@ -0,0 +1,128 @@
+#@+leo-ver=4
+#@+node:@file examples/fltk/pyfltklite.pyxe
+"""
+Simple demo of Pyrex C++ Embedding
+
+Requires FLTK1.1, libs and headers, to be installed
+"""
+
+
+#header{
+
+// header files
+#include <Python.h>
+#include <stdio.h>
+#include <FL/Fl.h>
+#include <FL/Fl_Window.h>
+#include <FL/Fl_Button.h>
+
+// declare a global callback invoker, that
+// extracts python callable and its args from
+// fltk callback data then invokes
+void invoke_python_callback(Fl_Widget *wid, void *data)
+{
+    //printf("callback: entered, wid=%lx data=%lx\n", wid, data);
+
+    PyObject *p = (PyObject *)data;
+
+    // extract callable and args tuple
+    PyObject *func = PyTuple_GetItem(p, 0);
+    PyObject *args = PyTuple_GetItem(p, 1);
+    PyObject *kw = PyTuple_GetItem(p, 2);
+
+    //printf("callback: func=%lx args=%lx kw=%lx\n", func, args, kw);
+    //PyObject_Print(p, stdout, Py_PRINT_RAW);
+    //PyObject_Print(func, stdout, Py_PRINT_RAW);
+    //PyObject_Print(args, stdout, Py_PRINT_RAW);
+    //PyObject_Print(kw, stdout, Py_PRINT_RAW);
+    //printf("callback: printed?\n");
+
+    PyObject_Call(func, args, kw);
+}
+
+#}header
+
+
+
+cdef class Widget:
+    """
+    base widget class
+    """
+    cdef void *thisptr
+
+    def callback(self, func, *args, **kw):
+
+        #embed{ void addCallback(void *wid, void *args)
+            PyObject *p = (PyObject *)args;
+            Py_INCREF(p);
+            ((Fl_Widget *)wid)->callback(invoke_python_callback, (void *)p);
+        #}embed
+
+        cdef void *cargs
+        allargs = (func, (self,)+args, kw)
+        #print "allargs=%s" % repr(allargs)
+        cargs = <void *>allargs
+
+        # now invoke this embedded shim function
+        addCallback(self.thisptr, cargs)
+
+    def label(self, lbl):
+        
+        #embed{ void Fl_Widget_label(void *wid, char *label)
+            ((Fl_Widget *)wid)->label(label);
+        #}embed
+
+        Fl_Widget_label(self.thisptr, lbl)
+
+
+cdef class Window(Widget):
+
+    def __init__(self, x, y, w, h, title):
+
+        #embed{ void *Fl_Window___init__(int x, int y,int w, int h, char *t)
+            return (void *)(new Fl_Window(x,y,w,h,t));
+        #}embed
+
+        self.thisptr = Fl_Window___init__(x, y, w, h, title)
+
+    def show(self):
+        
+        #embed{ void Fl_Window_show(void *w)
+            ((Fl_Window *)w)->show();
+        #}embed
+
+        Fl_Window_show(self.thisptr)
+
+    def end(self):
+        
+        #embed{ void Fl_Window_end(void *w)
+            ((Fl_Window *)w)->end();
+        #}embed
+
+        Fl_Window_end(self.thisptr)
+
+
+cdef class Button(Widget):
+    
+    def __init__(self, x, y, w, h, title):
+        
+        #embed{ void *Fl_Button___init__(int x, int y,int w, int h, char *t)
+            return (void *)(new Fl_Button(x,y,w,h,t));
+        #}embed
+
+        self.thisptr = Fl_Button___init__(x, y, w, h, title)
+
+def run():
+
+    #embed{ void Fl_run()
+        Fl::run();
+    #}embed
+    
+    Fl_run()
+
+cdef class Window1(Window):
+    
+    pass
+
+#@-node:@file examples/fltk/pyfltklite.pyxe
+#@-leo

Added: cs/pyrexembed/trunk/examples/fltk/setup.py
===================================================================
--- cs/pyrexembed/trunk/examples/fltk/setup.py	2007-03-28 23:21:42 UTC (rev 6453)
+++ cs/pyrexembed/trunk/examples/fltk/setup.py	2007-03-29 00:39:37 UTC (rev 6454)
@@ -0,0 +1,89 @@
+#@+leo-ver=4
+#@+node:@file examples/fltk/setup.py
+# remove this statement when you're happy with your settings
+
+raise Exception("Please tweak this setup script for your environment")
+
+
+# python imports
+import sys
+
+
+# usual Pyrex imports
+
+from distutils.core import setup, Extension
+from Pyrex.Distutils import build_ext
+
+
+# grab our pyrexembed processor
+
+import pyrexembed
+
+
+# the sources going into the extension
+# note that you're including pyfltklite.pyx, not pyfltklite.pyxe
+
+sources = ['pyfltklite.pyx', 'pyfltklite_embed.cpp']
+
+
+# grotty platform-specifics - you may need to tweak these
+
+if sys.platform.lower().find("linux") >= 0:
+
+    # linux compilation - hack distutils to use 'g++' for link
+    # instead of gcc - otherwise loading the extension might
+    # fail with an '_Znwj unresolved symbol'
+    pyrexembed.linkwithgplusplus()
+
+if '--compiler=mingw32' in sys.argv:
+    mingw = True
+else:
+    mingw = False
+
+incDirs = []
+libs = []
+libDirs = []
+runtimeLibDirs = []
+cMacros = []
+
+extraLinkArgs = [] # shared
+
+if sys.platform == 'win32':
+    libs = []
+    extraLinkArgs = ['libfltk.a']
+else:
+    # non-windows
+    libs = ['X11', 'fltk']
+    libDirs = ['/usr/lib', '/usr/local/lib', '/usr/X11R6/lib']
+
+
+# spec out the extension module
+
+pyfltkLite = Extension('pyfltklite',
+                        sources,
+                        define_macros=cMacros,
+                        include_dirs=incDirs,
+                        libraries=libs,
+                        library_dirs=libDirs,
+                        runtime_library_dirs=runtimeLibDirs,
+                        extra_compile_args=['-g'],
+                        extra_link_args=extraLinkArgs
+                        )
+
+
+# process the .pyxe file
+
+pyrexembed.process("pyfltklite.pyxe")
+
+
+# and build the extension
+
+setup(name = 'pyfltklite',
+      version = '1.0',
+      description = 'Hand-written FLTK wrapper',
+      ext_modules = [pyfltkLite],
+      cmdclass = {'build_ext': build_ext},
+      )
+
+#@-node:@file examples/fltk/setup.py
+#@-leo

Added: cs/pyrexembed/trunk/examples/fltk/test.py
===================================================================
--- cs/pyrexembed/trunk/examples/fltk/test.py	2007-03-28 23:21:42 UTC (rev 6453)
+++ cs/pyrexembed/trunk/examples/fltk/test.py	2007-03-29 00:39:37 UTC (rev 6454)
@@ -0,0 +1,31 @@
+#@+leo-ver=4
+#@+node:@file examples/fltk/test.py
+# simple demo which uses our demo embedded pyrex extension
+
+import pyfltklite as fl
+
+# create a window
+w = fl.Window1(100, 200, 300, 200, "Hello, there")
+
+# add a button, and label it
+b = fl.Button(9,20,180,50, "Press Me!")
+
+# define a callback function
+def on_buttonPress(*args, **kw):
+    print "b_callback: args=%s kw=%s" % (args, kw)
+
+# install the callback
+b.callback(
+    on_buttonPress,
+    "some callback data", 232,  # some arbitrary args
+    fred=123, mary=['a', 22]    # some arbitrary keywords
+    )
+
+# terminate the window creation
+w.end()
+
+# all done, now show the window and enter the main loop
+w.show()
+fl.run()
+#@-node:@file examples/fltk/test.py
+#@-leo

Added: cs/pyrexembed/trunk/pyrexembed.py
===================================================================
--- cs/pyrexembed/trunk/pyrexembed.py	2007-03-28 23:21:42 UTC (rev 6453)
+++ cs/pyrexembed/trunk/pyrexembed.py	2007-03-29 00:39:37 UTC (rev 6454)
@@ -0,0 +1,410 @@
+#! /usr/bin/env python
+#@+leo-ver=4
+#@+node:@file pyrexembed.py
+#@@first
+
+# written by David McNab (david at freenet.org.nz)
+# copyright (C) 2005 by David McNab, all rights reserved
+# released under the GNU Lesser General Public License
+
+"""
+pyrexembed.py
+
+Utility to extract embedded C++ code elements from specially
+marked-up Pyrex files, collate them and generate:
+    - correctly-formatted pyrex file
+    - C++ source file, containing the embedded code
+    - C header file, which is included into the generated
+      pyrex file
+
+Marked-up pyrex files must have a .pyxe extension. A file called
+fred.pyxe will be processed with the outputs:
+    - fred.pyx
+    - fred_embed.cpp
+    - fred_embed.h
+
+There are only two kinds of markup - header and embed.
+
+Header markup does not need to an embedded function,
+and will typically contain #include statements, #defines etc. Everything
+inside a header markup will be copied literally to the generated .cpp file,
+but not the generated .h file.
+
+A header markup section commences with a line starting with
+'#header{', and ends with a line starting with '#}header', for example::
+
+    #header{
+    #include <someheader.h>
+    #define ENABLE_SOME_FEATURE 1
+    #}header
+
+Embedding markup allows for convenient declaration of 'shim' functions
+which can be called from within Pyrex code, since they will be written to
+the generated .cpp file as 'extern "C"'.
+
+Embedded markup takes the form::
+
+    #embed{    <c function declaration>
+        <body of c function, containing C++ code if desired>
+    #}embed
+
+The C function declaration will be extracted and written to:
+    - the generated pyrex .pyx file, within a
+      'cdef extern from <myfile_embed.h>:' block
+    - the generated .h file, verbatim
+    - the generated .cpp file, along with the function body,
+      with an 'extern "C"' specifier
+
+For example::
+
+    cdef class MyExtension:
+
+        cdef void *thisptr
+
+        def __init__(self, size):
+
+            #embed{    void *Fred_new(int size)
+                Fred *obj = new Fred(size);
+                return (void *)obj;
+            #}embed
+
+            self.thisptr = Fred_new(size)
+
+        def onemethod(self, arg1):
+            "Some method of my pyrex extension class"
+
+            #embed{    int Fred_onemethod(void *fredobj, long arg1)
+               int result = ((Fred *)fredobj)->onemethod(arg1);
+                   return result;
+            #}embed
+
+            # try to convert arg to int
+            arg1int = int(arg1)
+            
+            # now run the shim func
+            return Fred_onemethod(self.thisptr, arg1int)
+
+"""
+
+#@+others
+#@+node:imports
+import sys, os, re
+
+#@-node:imports
+#@+node:globals
+argv = sys.argv
+argc = len(argv)
+progname = argv[0]
+
+#@-node:globals
+#@+node:class PyrexEmbedder
+class PyrexEmbedder:
+    """
+    Processes .pyxe files (Pyrex files with C++ code inside markups)
+    into valid Pyrex (.pyx) files, plus accompanying .cpp and .h files
+
+    Refer to module docstring for usage information
+    """
+    #@    @+others
+    #@+node:process
+    def process(self, pathname, filetype=".cpp"):
+        """
+        Perform the processing. Argument must be an absolute or
+        relative pathname of the input file, which must exist and have
+        a .pyxe extension.
+    
+        For further information, refer class and module docstrings.
+    
+        Arguments:
+            - pathname - path of .pyxe input file
+            - filetype - type of generated shim file, default '.cpp'
+        """
+        # barf if no such file
+        if not os.path.isfile(pathname):
+            raise Exception("No such file: '%s'" % pathname)
+    
+        # break up pathname into component parts
+        filebase, ext = os.path.splitext(pathname)
+        filename = os.path.split(pathname)[1]
+    
+        # barf if not a .pyxe file
+        if ext != ".pyxe":
+            raise Exception("File '%s' should have a .pyxe extension" % pathname)
+    
+        # derive and save file names
+        self.pathIn = pathname
+        self.pathPyrex = filebase + ".pyx"
+        self.pathCpp = filebase + "_embed" + filetype
+        self.pathH = filebase + "_embed.h"
+        self.pathInFile = filename + ".pyxe"
+    
+        # open input and track the line number
+        self.fileIn = file(pathname)
+        self.lineNum = 0
+    
+        # set up working data structures
+        self.pyrexLines = []
+        self.pyrexHeaderLines = []
+        self.cppHeaderLines = []
+        self.embedFuncs = []
+    
+        # process, initially as Pyrex code
+        self.processPyrex()
+    
+        # now generate the output
+        self.generateFiles()
+    
+    #@-node:process
+    #@+node:processPyrex
+    def processPyrex(self):
+        """
+        Reads and processes pure pyrex code from input
+        """
+        while True:
+            # get next line from .pyxi
+            line = self.readline()
+    
+            # bail if we're finished processing
+            if line == None:
+                break
+    
+            # break it up
+            parts = re.split("\\s+", line.strip(), 1)
+            firstbit = parts[0]
+    
+            # detect markups
+            if firstbit == "#header{":
+                # grab header stuff
+                self.processHeader()
+            elif firstbit == "#embed{":
+                # barf if no C funcdec
+                if len(parts) < 2:
+                    self.error("'#embed{' declaration must have C function declarator")
+                # ok, get declarator
+                decl = parts[1] # fixme - this mandates that the whole dec fit on one line
+                self.processEmbed(decl)
+            elif firstbit == '#}embed':
+                self.error("Not in a '#embed{' block")
+            elif firstbit == '#}header':
+                self.error("Not in a '#header{' block")
+            else:
+                # normal pyrex source line - save it
+                self.pyrexLines.append(line)
+    #@-node:processPyrex
+    #@+node:processHeader
+    def processHeader(self):
+        """
+        Reads and process header code from input
+    
+        Expect this to end with a '#}header'
+        """
+        while True:
+            # get next line
+            line = self.readline()
+    
+            # complain at eof
+            if line == None:
+                self.error("Unexpected end of file during '#header{' block")
+    
+            # break it up
+            firstbit = re.split("\\s+", line.strip().lower(), 1)[0]
+            if firstbit == '#}header':
+                # done
+                break
+            elif firstbit == '#header{':
+                self.error("Illegally nested #header{")
+            elif firstbit in ['#embed{', '#}embed']:
+                self.error("Illegal markup within header block")
+            else:
+                # legal - add to header lines
+                self.cppHeaderLines.append(line)
+    #@-node:processHeader
+    #@+node:processEmbed
+    def processEmbed(self, decl):
+        """
+        Reads and processes embed code from input
+        """
+        startline = self.lineNum
+    
+        embLines = []
+        while True:
+            # get next line
+            line = self.readline()
+            
+            # complain if EOF
+            if line == None:
+                self.error(
+                    "Unexpected end of file during '#embed{' block (%s)" % startline)
+    
+            # break it up
+            firstbit = re.split("\\s+", line.strip().lower(), 1)[0]
+            if firstbit == '#}embed':
+                # done
+                break
+            elif firstbit == '#embed{':
+                self.error("Illegally nested #embed{")
+            elif firstbit in ['#header{', '#}header']:
+                self.error("Illegal markup within embed block")
+            else:
+                # legal - add to embed lines
+                embLines.append(line)
+    
+        # ok, got full embedded func def
+        self.embedFuncs.append((decl.strip(), "\n".join(embLines) + "\n"))
+    #@-node:processEmbed
+    #@+node:generateFiles
+    def generateFiles(self):
+        """
+        Generate the required .pyx, .cpp and .h files from what we've
+        extracted from the input .pyxe file
+        """
+        #self.pyrexLines = []
+        #self.pyrexHeaderLines = []
+        #self.cppHeaderLines = []
+        #self.embedFuncs = []
+    
+        # open all the output files
+        filePyx = file(self.pathPyrex, "w")
+        fileCpp = file(self.pathCpp, "w")
+        fileH = file(self.pathH, "w")
+    
+        # save shim import funcs
+        pyrexShimDecs = []
+    
+        # write in an initial comment into each file
+        commentLines = [
+            "**************************************************************",
+            "Generated by pyrexembed from %s" % self.pathInFile,
+            "Please do not edit",
+            "**************************************************************",
+            ]
+        for line in commentLines:
+            filePyx.write("# %s\n" % line)
+            fileCpp.write("// %s\n" % line)
+            fileH.write("// %s\n" % line)
+        for f in (filePyx, fileCpp, fileH):
+            f.write("\n")
+    
+        # write out all the header stuff into the cpp file
+        fileCpp.write("// verbatim header lines from #header{ markups\n")
+        for line in self.cppHeaderLines:
+            fileCpp.write(line + "\n")
+        fileCpp.write("// end of verbatim header lines\n\n")
+    
+        # now process all the shim functions
+        for dec, body in self.embedFuncs:
+            # add the pyrex import
+            pyrexShimDecs.append("    cdef "+dec)
+            
+            # add the .h dec
+            fileH.write("extern " + dec + ";\n")
+            
+            # add the full dec and body to .c file
+            fileCpp.write("extern \"C\" " + dec + "\n{\n" + body + "}\n\n")
+    
+        # if there are shim funcs, stick in a pyrex dec block
+        if pyrexShimDecs:
+            filePyx.write('cdef extern from "%s":\n' % os.path.split(self.pathH)[1])
+            filePyx.write("\n".join(pyrexShimDecs) + "\n\n")
+    
+        # now write out the rest of the pyrex stuff
+        filePyx.write("\n".join(self.pyrexLines) + "\n")
+    
+        # should be all done now
+        filePyx.close()
+        fileCpp.close()
+        fileH.close()
+    
+    #@-node:generateFiles
+    #@+node:readline
+    def readline(self):
+        """
+        Reads a line of input file, updating the line number
+        """
+        if not self.fileIn:
+            raise Exception("Internal error - reading from closed input file")
+    
+        line = self.fileIn.readline()
+        if line == '':
+            # need None as a sentinel, since we're removing
+            # trailing newlines
+            self.fileIn.close()
+            self.fileIn = None
+            return None
+        line = line[:-1]    # chomp off trailing newline
+        self.lineNum += 1
+        return line
+    #@-node:readline
+    #@+node:error
+    def error(self, msg):
+        raise Exception("%s:\n  %s: %s:\s  %s" % (
+            progname,
+            self.pathInFile,
+            self.lineNum,
+            msg)
+            )
+    
+    
+    #@-node:error
+    #@-others
+
+#@-node:class PyrexEmbedder
+#@+node:process
+def process(pathname, filetype=".cpp"):
+    """
+    Arguments:
+        - pathname - path of .pyxe input file
+        - filetype - type of generated shim file, default '.cpp'
+    """
+
+    PyrexEmbedder().process(pathname, filetype)
+
+#@-node:process
+#@+node:linkwithgplusplus
+def linkwithgplusplus():
+    """
+    changes the linker from gcc to g++
+    """
+    from distutils import sysconfig
+
+    # grab original init func
+    save_init_posix = sysconfig._init_posix
+
+    # create a new one that uses old one, but changes from gcc to c++
+    def my_init_posix():
+        print 'my_init_posix: changing gcc to g++'
+        save_init_posix()
+        g = sysconfig._config_vars
+        g['LINKCC'] = 'g++ -pthread'
+        g['LDSHARED'] = 'g++ -shared'
+
+    # and plug in the new function
+    sysconfig._init_posix = my_init_posix
+
+#@-node:linkwithgplusplus
+#@+node:main
+def main():
+    
+    if argc not in [2, 3]:
+        print "usage: %s filename.pyxi [filetype]"
+        print "filetype defaults to .cpp"
+        sys.exit(1)
+    
+    path = argv[1]
+    if argc == 2:
+        process(path)
+    else:
+        process(path, argv[2])
+
+
+
+#@-node:main
+#@+node:mainline
+if __name__ == '__main__':
+    main()
+
+#@-node:mainline
+#@-others
+
+#@-node:@file pyrexembed.py
+#@-leo


Property changes on: cs/pyrexembed/trunk/pyrexembed.py
___________________________________________________________________
Name: svn:executable
   + 

Added: cs/pyrexembed/trunk/scripts/pyrexembed
===================================================================
--- cs/pyrexembed/trunk/scripts/pyrexembed	2007-03-28 23:21:42 UTC (rev 6453)
+++ cs/pyrexembed/trunk/scripts/pyrexembed	2007-03-29 00:39:37 UTC (rev 6454)
@@ -0,0 +1,11 @@
+#! /usr/bin/env python
+#@+leo-ver=4
+#@+node:@file scripts/pyrexembed
+#@@first
+
+import pyrexembed
+
+pyrexembed.main()
+
+#@-node:@file scripts/pyrexembed
+#@-leo


Property changes on: cs/pyrexembed/trunk/scripts/pyrexembed
___________________________________________________________________
Name: svn:executable
   + 

Added: cs/pyrexembed/trunk/setup.py
===================================================================
--- cs/pyrexembed/trunk/setup.py	2007-03-28 23:21:42 UTC (rev 6453)
+++ cs/pyrexembed/trunk/setup.py	2007-03-29 00:39:37 UTC (rev 6454)
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+#@+leo-ver=4
+#@+node:@file setup.py
+#@@first
+
+"""
+installer file for pyrex embed
+"""
+
+from distutils.core import setup
+
+scripts = ["scripts/pyrexembed"]
+
+setup(name="pyrexembed",
+      version="1.0",
+      description="Pyrex embedder extension",
+      author="David McNab",
+      author_email="david at freenet.org.nz",
+      url="http://www.freenet.org.nz/python/pyrexembed/",
+      py_modules=['pyrexembed'],
+      scripts=scripts,
+     )
+
+#@-node:@file setup.py
+#@-leo



More information about the cig-commits mailing list