elmer
  
  

Examples


The following examples show how a C or Tcl developer can use the Python module below in their applications:
File: IntList.py
class IntList : def __init__( self, size ) : self._maxSize = size self._size = 0 self._list = [] def __repr__( self ) : retString = "" for i in range( self._size ) : retString += "index %s: %s\n" % (i, self._list[i]) return retString def getList( self ) : return self._list def addInt( self, val ) : self._list.append( val ) self._size += 1 def addIntList( self, ilObj ) : for i in ilObj.getList() : self.addInt( i ) def getInt( lst, index ) : return lst[index]

Using the IntList Python module (shown above) in C


Step 1: Create the Elmer interface file

File: IntList.elm


module IntList class IntList { IntList __init__( int ) -> create string __repr__() -> getStringRep list getList() void addInt( int ) void addIntList( IntList ) } int getInt( list, int )
Step 2: Run elmer to generate IntList.c and IntList.h

LINUX> elmer -int IntList.elm IntList.py LINUX> ls IntList.c IntList.elm IntList.h IntList.py
Step 3: Use the Python module in your C application

File: myApp.c


#include <IntList.h> int main( int argc, char** argv ) { int il_id; int il_id2; int list_id = 99; il_id = IntList_create( 3, elNEWID ); il_id2 = IntList_create( 3, elNEWID ); IntList_addInt( il_id, 12 ); IntList_addInt( il_id, 14 ); IntList_addInt( il_id, 4 ); IntList_addIntList( il_id2, il_id ); printf( "IntList #1:\n%s\n", IntList_getStringRep( il_id ) ); printf( "IntList #2:\n%s\n", IntList_getStringRep( il_id2 ) ); IntList_getList( il_id, list_id ); printf( "SECOND VALUE IN INTLIST #1: %d\n", getInt( list_id, 1 ) ); return 0; }
Step 4: Build and run the application

Note: the libraries required (-ldl, -lm, etc.) may vary depending on what is required for the Python install on the build machine.

LINUX> cc -I. -I/usr/local/include/elmer -I/usr/include/python2.1 -o myApp \ IntList.c myApp.c -L/usr/local/lib/elmer -lelmer -L/usr/lib/python2.1/config \ -lpython2.1 -ldl -lm -lutil -lpthread
Note: Since elmer was not run using -frozen (see manual), the PYTHONPATH environment variable should be set to include the directory which IntList.py resides in.
LINUX> ./myApp IntList #1: index 0: 12 index 1: 14 index 2: 4 IntList #2: index 0: 12 index 1: 14 index 2: 4 SECOND VALUE IN INTLIST #1: 14 LINUX>

Using the IntList Python module (shown above) in Tcl


Step 1: Create the Elmer interface file (this is the same interface file used in the C example above)

File: IntList.elm


module IntList class IntList { IntList __init__( int ) -> create string __repr__() -> getStringRep list getList() void addInt( int ) void addIntList( IntList ) } int getInt( list, int )
Step 2: Run elmer to generate IntList.c and IntList.h, specifying a Tcl interface by using the -tcl flag

LINUX> elmer -tcl -int IntList.elm IntList.py LINUX> ls IntList.c IntList.elm IntList.h IntList.py
Step 3: Create a Tcl interpreter with the IntList extension

Note: The generated IntList elmer interface could be compiled into a dynamically-loaded package, in which case this custom Tcl interpreter would not be needed.
File: myTcl.c


#include <tcl.h> #include <IntList.h> int Tcl_AppInit( Tcl_Interp* interp ) { return IntListTcl_Init( interp ); } int main( int argc, char** argv ) { Tcl_Main( argc, argv, Tcl_AppInit ); return 0; }
Step 4: Use the Python module in your Tcl application

File: myApp.tcl


set il_id [IntList 3] set il_id2 [IntList 3] $il_id addInt 12 $il_id addInt 14 $il_id addInt 4 $il_id2 addIntList $il_id puts "IntList #1:\n[$il_id getStringRep]" puts "IntList #2:\n[$il_id2 getStringRep]" set list_id [$il_id getList] puts "SECOND VALUE IN INTLIST #1: [lindex $list_id 1]"
Step 5: Build and run the application

Note: the libraries required (-ldl, -lm, etc.) may vary depending on what is required for the Python and Tcl installs on the build machine.

LINUX> cc -I. -I/usr/local/include/elmer -I/usr/include/python2.1 -o myTcl \ IntList.c myTcl.c -L/usr/local/lib/elmer -lelmer -L/usr/lib/python2.1/config \ -lpython2.1 -ltcl8.3 -ldl -lm -lutil -lpthread
Note: Since elmer was not run using -frozen (see manual), the PYTHONPATH environment variable should be set to include the directory which IntList.py resides in.
LINUX> ./myTcl myApp.tcl IntList #1: index 0: 12 index 1: 14 index 2: 4 IntList #2: index 0: 12 index 1: 14 index 2: 4 SECOND VALUE IN INTLIST #1: 14 LINUX>

Building a Windows DLL

A common approach on Windows is to use Elmer to generate the C interface to your Python code, and build it into a DLL which can be loaded by another program.

The entire example can be downloaded here.

The following Python module (container.py) will be used in a C program via a DLL (container.dll). Elmer will generate the C code (container.c and container.h) that will be built into container.dll and included in another C program, respectively.:


The Elmer interface for container.py (container.elm) is shown below:



The C program (main.c) that will include the Elmer-generated container.h and call the Elmer-generated functions provided by container.dll is below:



A Makefile will be used here to call the MS C compiler (cl.exe) to build the DLL and the test program:



Before calling the Makefile, the environment must be set up for running cl.exe and Elmer:



Now the Makefile can be run:



Because Elmer was not used in "frozen" mode, the embedded Python interpreter will need to use PYTHONPATH to find the .py files. And since a DLL was built, container.dll will have to either be copied to the default system location (C:\windows) or the directory it resides in added to PATH.



Now the test program can be run:



Since the .py files were not "frozen" into the DLL, they can be changed without rebuilding the DLL or test application. This can be very handy for quick prototyping work. Lets add a print statment and re-run:




How to build Elmer

The following example shows how to build Elmer on a Linux machine...other platforms use the same options: # # unpack the tarfile and change to the new directory # [rlratzel@triumph build]$ tar zxf elmer1.1.6a.tar.gz [rlratzel@triumph build]$ ls elmer1.1.6a elmer1.1.6a.tar.gz [rlratzel@triumph build]$ cd elmer1.1.6a # # scons is used for build and install. If you want, try giving it the -h option # to print out lots of useful information on using it. # [rlratzel@triumph elmer1.1.6a]$ python scons/scons.py -h scons: Reading SConscript files ... scons: done reading SConscript files. How to build: From the elmerx.y.z directory, type: python scons/scons.py How to install: From the elmerx.y.z directory, type: python scons/scons.py install [PREFIX=<install dir>] Note: All targets (even non-related ones) will run a configure step which reads the command-line options (below) and elmerConfig.py (if present). The command-line options override the settings in elmerConfig.py. The configure step will verify that the pacakges specified are present and working and will use that information to modify various source files. Targets: build - (default) builds elmer runtime library and .pyc & .pyo files in the build dir (named after platform). install - runs build if not already done and installs elmer in the directories specified by PREFIX and/or BINDIR, LIBDIR, & INCDIR. elmer can be run from the build dir and does not need to be installed in order to use/try it. Options (OPTION=VALUE): PYTHON_INCDIR - directory containing Python.h PYTHON_LIBDIR - directory containing Python library PYTHON_LIBNAME - the name of the Python library...for example, if lib is python23.lib, PYTHON_LIBNAME=python23, and if lib is libpython2.3.a, PYTHON_LIBNAME=python2.3 NO_TCL - set to anything for no Tcl configuration TCL_INCDIR - directory containing tcl.h TCL_LIBDIR - directory containing Tcl library TCL_LIBNAME - the name of the Tcl library...for example, if lib is tcl84.lib, TCL_LIBNAME=tcl84, and if lib is libtcl.so, TCL_LIBNAME=tcl NO_FREEZE - set to anything for no freeze configuration FREEZE_DIR - directory containing freeze.py and all supporting file PREFIX - specifies where elmer is installed (default is /usr/local on Unix and c:\elmer on Windows) BINDIR - specifies where executables are installed (default is /usr/local/bin on Unix and c:\elmein on Windows) LIBDIR - specifies where library files are installed (default is /usr/local/lib/elmerx.y.z on Unix and c:\elmer\lib\elmerx.y.z on Windows) INCDIR - specifies where include files are installed (default is /usr/local/lib/elmerx.y.z on Unix and c:\elmer\lib\elmerx.y.z on Windows) CC - the C compiler to use CCFLAGS - extra flags to pass to the C compiler CXX - the C++ compiler to use CXXFLAGS - extra flags to pass to the C++ compiler LIBS - extra libraries to be passed to the linker LIBPATH - extra directories to search for LIBS LINKFLAGS - extra flags to pass to the linker Flags (not nearly all of them...use scons.py -H for complete list): -c - "cleans" the build dir -h - prints this help message Use scons -H for help about command-line options. # # Run scons to build. The example below is broken into multiple lines for # clarity. Here, the location of the Tcl install is specified since it is in a # non-standard location, as well as the directory containing the freeze sources. # If you do not have Tcl or freeze (or do not want them to be used), then you # can still build and install Elmer without them. Finally, the install PREFIX # is given so that everything is installed under /usr/local in this case. # [rlratzel@triumph elmer1.1.6a]$ python scons/scons.py \ > TCL_INCDIR=/data/local/include \ > TCL_LIBDIR=/data/local/lib \ > TCL_LIBNAME=tcl8.4 \ > FREEZE_DIR=/data/local/lib/python2.3/site-packages/Tools/freeze \ > PREFIX=/usr/local scons: Reading SConscript files ... Applying the following overrides to the loaded options: FREEZE_DIR = /data/local/lib/python2.3/site-packages/Tools/freeze PREFIX = /usr/local TCL_LIBNAME = tcl8.4 TCL_LIBDIR = /data/local/lib TCL_INCDIR = /data/local/include build/install options will be loaded from: /home/rlratzel/build/elmer1.1.6a/linux2/elmerConfig.py Using the following configuration: PYTHON_INCDIR = <will try defaults> PYTHON_LIBDIR = <will try defaults> PYTHON_LIBNAME = <will try defaults> TCL_INCDIR = /data/local/include TCL_LIBDIR = /data/local/lib TCL_LIBNAME = tcl8.4 FREEZE_DIR = /data/local/lib/python2.3/site-packages/Tools/freeze BINDIR = /usr/local/bin LIBDIR = /usr/local/lib/elmer1.1.6a INCDIR = /usr/local/include/elmer1.1.6a CC = gcc CCFLAGS = CXX = g++ CXXFLAGS = $CCFLAGS CPPPATH = ['/home/rlratzel/build/elmer1.1.6a/linux2'] LIBS = <will try defaults> LIBPATH = <will try defaults> LINKFLAGS = $__RPATH Checking Python: include="/usr/include/python2.4", libdir="/usr/lib/python2.4/config", lib="python2.4"...ok Checking Tcl: include="/data/local/include", libdir="/data/local/lib", lib="tcl8.4"...ok Checking Freeze in: "/data/local/lib/python2.3/site-packages/Tools/freeze"...ok Removing dir: .conf_dir scons: done reading SConscript files. scons: Building targets ... fixupSrcFiles(["linux2/elmer.py", "linux2/elmer"], ["linux2/elmer.py.in", "linux2/elmer.sh.in", "linux2/elmerConfig.py"]) Chmod("linux2/elmer", 0755) gcc -Ilinux2 -I/usr/include/python2.4 -I/data/local/include -c -o linux2/elString.o linux2/elString.c g++ -Ilinux2 -I/usr/include/python2.4 -I/data/local/include -c -o linux2/elCpp.o linux2/elCpp.cpp In file included from /usr/include/python2.4/Python.h:8, from linux2/elCpp.cpp:29: /usr/include/python2.4/pyconfig.h:838:1: warning: "_POSIX_C_SOURCE" redefined In file included from /usr/lib/gcc/i386-redhat-linux/4.0.2/../../../../include/c++/4.0.2/i386-redhat-linux/bits/os_defines.h:39, from /usr/lib/gcc/i386-redhat-linux/4.0.2/../../../../include/c++/4.0.2/i386-redhat-linux/bits/c++config.h:35, from /usr/lib/gcc/i386-redhat-linux/4.0.2/../../../../include/c++/4.0.2/iostream:43, from linux2/elCpp.h:29, from linux2/elCpp.cpp:26: /usr/include/features.h:150:1: warning: this is the location of the previous definition gcc -Ilinux2 -I/usr/include/python2.4 -I/data/local/include -c -o linux2/elTypeSupport.o linux2/elTypeSupport.c ar r linux2/libelmer.a linux2/elString.o linux2/elCpp.o linux2/elTypeSupport.o linux2/elmer.h linux2/elString.h linux2/elCpp.h linux2/elTcl.h ranlib linux2/libelmer.a ar: creating linux2/libelmer.a buildPycFiles(["linux2/elClass.pyc", "linux2/elException.pyc", "linux2/elFunction.pyc", "linux2/elInterfaceFile.pyc", "linux2/elTokenizer.pyc", "linux2/elPythonToC.pyc", "linux2/elType.pyc", "linux2/elCallback.pyc", "linux2/elUtil.pyc", "linux2/elmer.pyc", "linux2/elmerConfig.pyc", "linux2/elPythonToCpp.pyc", "linux2/elPythonToProcTcl.pyc", "linux2/elPythonToObjTcl.pyc"], ["linux2/elClass.py", "linux2/elException.py", "linux2/elFunction.py", "linux2/elInterfaceFile.py", "linux2/elTokenizer.py", "linux2/elPythonToC.py", "linux2/elType.py", "linux2/elCallback.py", "linux2/elUtil.py", "linux2/elmer.py", "linux2/elmerConfig.py", "linux2/elPythonToCpp.py", "linux2/elPythonToProcTcl.py", "linux2/elPythonToObjTcl.py"]) buildPyoFiles(["linux2/elClass.pyo", "linux2/elException.pyo", "linux2/elFunction.pyo", "linux2/elInterfaceFile.pyo", "linux2/elTokenizer.pyo", "linux2/elPythonToC.pyo", "linux2/elType.pyo", "linux2/elCallback.pyo", "linux2/elUtil.pyo", "linux2/elmer.pyo", "linux2/elmerConfig.pyo", "linux2/elPythonToCpp.pyo", "linux2/elPythonToProcTcl.pyo", "linux2/elPythonToObjTcl.pyo"], ["linux2/elClass.py", "linux2/elException.py", "linux2/elFunction.py", "linux2/elInterfaceFile.py", "linux2/elTokenizer.py", "linux2/elPythonToC.py", "linux2/elType.py", "linux2/elCallback.py", "linux2/elUtil.py", "linux2/elmer.py", "linux2/elmerConfig.py", "linux2/elPythonToCpp.py", "linux2/elPythonToProcTcl.py", "linux2/elPythonToObjTcl.py"]) scons: done building targets. # # Now, install it to the install directory. Make sure you have write permission! # [root@triumph elmer1.1.6a]# python scons/scons.py install scons: Reading SConscript files ... build/install options will be loaded from: /home/rlratzel/build/elmer1.1.6a/linux2/elmerConfig.py Using the following configuration: PYTHON_INCDIR = /usr/include/python2.4 PYTHON_LIBDIR = /usr/lib/python2.4/config PYTHON_LIBNAME = python2.4 TCL_INCDIR = /data/local/include TCL_LIBDIR = /data/local/lib TCL_LIBNAME = tcl8.4 FREEZE_DIR = /data/local/lib/python2.3/site-packages/Tools/freeze BINDIR = /usr/local/bin LIBDIR = /usr/local/lib/elmer1.1.6a INCDIR = /usr/local/include/elmer1.1.6a CC = gcc CCFLAGS = [] CXX = g++ CXXFLAGS = ['$CCFLAGS'] CPPPATH = ['/home/rlratzel/build/elmer1.1.6a/linux2', '/usr/include/python2.4', '/data/local/include'] LIBS = ['python2.4', 'tcl8.4'] LIBPATH = ['/usr/lib/python2.4/config', '/data/local/lib'] LINKFLAGS = ['$__RPATH'] scons: done reading SConscript files. scons: Building targets ... Install file: "linux2/elmer" as "/usr/local/bin/elmer116a" fixupBinScript(["/usr/local/bin/elmer116a"], ["linux2/elmer"]) Chmod("/usr/local/bin/elmer116a", 0755) Install file: "linux2/elmer" as "/usr/local/bin/elmer" fixupBinScript(["/usr/local/bin/elmer"], ["linux2/elmer"]) Chmod("/usr/local/bin/elmer", 0755) Install file: "linux2/libelmer.a" as "/usr/local/lib/elmer1.1.6a/libelmer.a" Install file: "linux2/elClass.pyc" as "/usr/local/lib/elmer1.1.6a/elClass.pyc" Install file: "linux2/elException.pyc" as "/usr/local/lib/elmer1.1.6a/elException.pyc" Install file: "linux2/elFunction.pyc" as "/usr/local/lib/elmer1.1.6a/elFunction.pyc" Install file: "linux2/elInterfaceFile.pyc" as "/usr/local/lib/elmer1.1.6a/elInterfaceFile.pyc" Install file: "linux2/elTokenizer.pyc" as "/usr/local/lib/elmer1.1.6a/elTokenizer.pyc" Install file: "linux2/elPythonToC.pyc" as "/usr/local/lib/elmer1.1.6a/elPythonToC.pyc" Install file: "linux2/elType.pyc" as "/usr/local/lib/elmer1.1.6a/elType.pyc" Install file: "linux2/elCallback.pyc" as "/usr/local/lib/elmer1.1.6a/elCallback.pyc" Install file: "linux2/elUtil.pyc" as "/usr/local/lib/elmer1.1.6a/elUtil.pyc" Install file: "linux2/elmer.pyc" as "/usr/local/lib/elmer1.1.6a/elmer.pyc" Install file: "linux2/elmerConfig.pyc" as "/usr/local/lib/elmer1.1.6a/elmerConfig.pyc" Install file: "linux2/elPythonToCpp.pyc" as "/usr/local/lib/elmer1.1.6a/elPythonToCpp.pyc" Install file: "linux2/elPythonToProcTcl.pyc" as "/usr/local/lib/elmer1.1.6a/elPythonToProcTcl.pyc" Install file: "linux2/elPythonToObjTcl.pyc" as "/usr/local/lib/elmer1.1.6a/elPythonToObjTcl.pyc" Install file: "linux2/elClass.pyo" as "/usr/local/lib/elmer1.1.6a/elClass.pyo" Install file: "linux2/elException.pyo" as "/usr/local/lib/elmer1.1.6a/elException.pyo" Install file: "linux2/elFunction.pyo" as "/usr/local/lib/elmer1.1.6a/elFunction.pyo" Install file: "linux2/elInterfaceFile.pyo" as "/usr/local/lib/elmer1.1.6a/elInterfaceFile.pyo" Install file: "linux2/elTokenizer.pyo" as "/usr/local/lib/elmer1.1.6a/elTokenizer.pyo" Install file: "linux2/elPythonToC.pyo" as "/usr/local/lib/elmer1.1.6a/elPythonToC.pyo" Install file: "linux2/elType.pyo" as "/usr/local/lib/elmer1.1.6a/elType.pyo" Install file: "linux2/elCallback.pyo" as "/usr/local/lib/elmer1.1.6a/elCallback.pyo" Install file: "linux2/elUtil.pyo" as "/usr/local/lib/elmer1.1.6a/elUtil.pyo" Install file: "linux2/elmer.pyo" as "/usr/local/lib/elmer1.1.6a/elmer.pyo" Install file: "linux2/elmerConfig.pyo" as "/usr/local/lib/elmer1.1.6a/elmerConfig.pyo" Install file: "linux2/elPythonToCpp.pyo" as "/usr/local/lib/elmer1.1.6a/elPythonToCpp.pyo" Install file: "linux2/elPythonToProcTcl.pyo" as "/usr/local/lib/elmer1.1.6a/elPythonToProcTcl.pyo" Install file: "linux2/elPythonToObjTcl.pyo" as "/usr/local/lib/elmer1.1.6a/elPythonToObjTcl.pyo" Install file: "linux2/elmer.py" as "/usr/local/lib/elmer1.1.6a/elmer.py" Install file: "linux2/elmer.h" as "/usr/local/include/elmer1.1.6a/elmer.h" Install file: "linux2/elString.h" as "/usr/local/include/elmer1.1.6a/elString.h" Install file: "linux2/elCpp.h" as "/usr/local/include/elmer1.1.6a/elCpp.h" Install file: "linux2/elTcl.h" as "/usr/local/include/elmer1.1.6a/elTcl.h" scons: done building targets. # # Give it a try...if you did not build with the Tcl or freeze options, they will # not be shown in the elmer usage output. # [rlratzel@triumph ~]$ which elmer /usr/local/bin/elmer [rlratzel@triumph ~]$ elmer elmer version 1.1.6a elmer [OPTIONS] -int <interface file> [<python file>...] OPTIONS: -O - run embedded Python with optimization level 1 -OO - run embedded Python with optimization level 2 (same as level 1 but does not insert doc-strings into the byte-compiled Python modules) -debug - print every call at runtime made to the embedded Python interpreter -test - read the interface file and print info on it (for verifying interface file correctness) -o <output dir> - generate all output in <output dir> -sp <search path or dir> - look for interface files in current dir first, then in <search path or dir>. Multiple dirs can be given by repeatedly specifying -sp, or by using a search path delimited by the platform's pathsep -c - C mode...generate glue code to embed the Python module into a C application. Cannot be combined with any other mode. This is the default output mode. -cpp - C++ mode...generate glue code to embed the Python module into a C++ application. Cannot be combined with any other mode -tcl [-obj | -proc] - Tcl mode...generate glue code to embed the Python module into a Tcl application. -obj generates a pseudo object-oriented interface where objects are registered as Tcl commands, and methods are args to the commands (default). -proc generates a procedural interface where methods take an object id as the first arg -warm - run the embedded interpreter in a manner which requires the PYTHONPATH env var to be set and the .py[co] files present (default) -frozen [-E] - byte compile every Python module used by the embedded module and generate a .c file for each which is to be compiled into the application or library. The byte compiled code is effected by the -O and -OO options. -E will cause elmer to stop if it cannot find a required module to byte compile. This option is used to create applications which do not need the .py[co] files present at runtime. At least one python file (typically the module's .py file) must be specified on the command line in order for elmer to byte compile the module. -h - print this help message and exit defaults are: -o . -c -sp . -obj (if -tcl) -warm