[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