|
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
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
#include
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=]
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 =
PYTHON_LIBDIR =
PYTHON_LIBNAME =
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 =
LIBPATH =
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 [...]
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
|