diff options
Diffstat (limited to 'Examples/tcl/class')
| -rw-r--r-- | Examples/tcl/class/Makefile | 19 | ||||
| -rw-r--r-- | Examples/tcl/class/example.cxx | 28 | ||||
| -rw-r--r-- | Examples/tcl/class/example.dsp | 152 | ||||
| -rw-r--r-- | Examples/tcl/class/example.h | 39 | ||||
| -rw-r--r-- | Examples/tcl/class/example.i | 11 | ||||
| -rw-r--r-- | Examples/tcl/class/index.html | 274 | ||||
| -rw-r--r-- | Examples/tcl/class/runme.tcl | 50 | ||||
| -rw-r--r-- | Examples/tcl/class/runme2.tcl | 70 |
8 files changed, 643 insertions, 0 deletions
diff --git a/Examples/tcl/class/Makefile b/Examples/tcl/class/Makefile new file mode 100644 index 0000000..c01283c --- /dev/null +++ b/Examples/tcl/class/Makefile @@ -0,0 +1,19 @@ +TOP = ../.. +SWIG = $(TOP)/../preinst-swig +CXXSRCS = example.cxx +TARGET = example +INTERFACE = example.i +LIBS = -lm + +all:: + $(MAKE) -f $(TOP)/Makefile CXXSRCS='$(CXXSRCS)' SWIG='$(SWIG)' \ + TARGET='$(TARGET)' INTERFACE='$(INTERFACE)' tcl_cpp + +static:: + $(MAKE) -f $(TOP)/Makefile CXXSRCS='$(CXXSRCS)' SWIG='$(SWIG)' \ + TARGET='mytclsh' INTERFACE='$(INTERFACE)' tclsh_cpp_static + +clean:: + $(MAKE) -f $(TOP)/Makefile tcl_clean + +check: all diff --git a/Examples/tcl/class/example.cxx b/Examples/tcl/class/example.cxx new file mode 100644 index 0000000..1e8e203 --- /dev/null +++ b/Examples/tcl/class/example.cxx @@ -0,0 +1,28 @@ +/* File : example.c */ + +#include "example.h" +#define M_PI 3.14159265358979323846 + +/* Move the shape to a new location */ +void Shape::move(double dx, double dy) { + x += dx; + y += dy; +} + +int Shape::nshapes = 0; + +double Circle::area(void) { + return M_PI*radius*radius; +} + +double Circle::perimeter(void) { + return 2*M_PI*radius; +} + +double Square::area(void) { + return width*width; +} + +double Square::perimeter(void) { + return 4*width; +} diff --git a/Examples/tcl/class/example.dsp b/Examples/tcl/class/example.dsp new file mode 100644 index 0000000..0ff5482 --- /dev/null +++ b/Examples/tcl/class/example.dsp @@ -0,0 +1,152 @@ +# Microsoft Developer Studio Project File - Name="example" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=example - Win32 Release
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "example.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "example.mak" CFG="example - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "example - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "example - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "example - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "EXAMPLE_EXPORTS" /YX /FD /GZ /c
+# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "$(TCL_INCLUDE)" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "EXAMPLE_EXPORTS" /YX /FD /GZ /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib "$(TCL_LIB)" /nologo /dll /debug /machine:I386 /out:"example.dll" /pdbtype:sept
+
+!ELSEIF "$(CFG)" == "example - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "EXAMPLE_EXPORTS" /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /I "$(TCL_INCLUDE)" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "EXAMPLE_EXPORTS" /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x809 /d "NDEBUG"
+# ADD RSC /l 0x809 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /dll /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib "$(TCL_LIB)" /nologo /dll /machine:I386 /out:"example.dll"
+
+!ENDIF
+
+# Begin Target
+
+# Name "example - Win32 Debug"
+# Name "example - Win32 Release"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\example.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\example_wrap.cxx
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\example.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# Begin Source File
+
+SOURCE=.\example.i
+
+!IF "$(CFG)" == "example - Win32 Debug"
+
+# Begin Custom Build
+InputPath=.\example.i
+InputName=example
+
+"$(InputName)_wrap.cxx" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ echo In order to function correctly, please ensure the following environment variables are correctly set:
+ echo TCL_INCLUDE: %TCL_INCLUDE%
+ echo TCL_LIB: %TCL_LIB%
+ echo on
+ ..\..\..\swig.exe -c++ -tcl8 $(InputPath)
+
+# End Custom Build
+
+!ELSEIF "$(CFG)" == "example - Win32 Release"
+
+# Begin Custom Build
+InputPath=.\example.i
+InputName=example
+
+"$(InputName)_wrap.cxx" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ echo In order to function correctly, please ensure the following environment variables are correctly set:
+ echo TCL_INCLUDE: %TCL_INCLUDE%
+ echo TCL_LIB: %TCL_LIB%
+ echo on
+ ..\..\..\swig.exe -c++ -tcl8 $(InputPath)
+
+# End Custom Build
+
+!ENDIF
+
+# End Source File
+# End Target
+# End Project
diff --git a/Examples/tcl/class/example.h b/Examples/tcl/class/example.h new file mode 100644 index 0000000..46d9013 --- /dev/null +++ b/Examples/tcl/class/example.h @@ -0,0 +1,39 @@ +/* File : example.h */ + +class Shape { +public: + Shape() { + nshapes++; + } + virtual ~Shape() { + nshapes--; + }; + double x, y; + void move(double dx, double dy); + virtual double area(void) = 0; + virtual double perimeter(void) = 0; + static int nshapes; +}; + +class Circle : public Shape { +private: + double radius; +public: + Circle(double r) : radius(r) { }; + virtual double area(void); + virtual double perimeter(void); +}; + +class Square : public Shape { +private: + double width; +public: + Square(double w) : width(w) { }; + virtual double area(void); + virtual double perimeter(void); +}; + + + + + diff --git a/Examples/tcl/class/example.i b/Examples/tcl/class/example.i new file mode 100644 index 0000000..23ee8a8 --- /dev/null +++ b/Examples/tcl/class/example.i @@ -0,0 +1,11 @@ +/* File : example.i */ +%module example + +%{ +#include "example.h" +%} + +/* Let's just grab the original header file here */ + +%include "example.h" + diff --git a/Examples/tcl/class/index.html b/Examples/tcl/class/index.html new file mode 100644 index 0000000..fd8cfe5 --- /dev/null +++ b/Examples/tcl/class/index.html @@ -0,0 +1,274 @@ +<html> +<head> +<title>SWIG:Examples:tcl:class</title> +</head> + +<body bgcolor="#ffffff"> + + +<tt>SWIG/Examples/tcl/class/</tt> +<hr> + +<H2>Wrapping a simple C++ class</H2> + +<p> +This example illustrates the most primitive form of C++ class wrapping performed +by SWIG. In this case, C++ classes are simply transformed into a collection of +C-style functions that provide access to class members. + +<h2>The C++ Code</h2> + +Suppose you have some C++ classes described by the following (and admittedly lame) +header file: + +<blockquote> +<pre> +/* File : example.h */ + +class Shape { +public: + Shape() { + nshapes++; + } + virtual ~Shape() { + nshapes--; + }; + double x, y; + void move(double dx, double dy); + virtual double area() = 0; + virtual double perimeter() = 0; + static int nshapes; +}; + +class Circle : public Shape { +private: + double radius; +public: + Circle(double r) : radius(r) { }; + virtual double area(); + virtual double perimeter(); +}; + +class Square : public Shape { +private: + double width; +public: + Square(double w) : width(w) { }; + virtual double area(); + virtual double perimeter(); +}; +</pre> +</blockquote> + +<h2>The SWIG interface</h2> + +A simple SWIG interface for this can be built by simply grabbing the header file +like this: + +<blockquote> +<pre> +/* File : example.i */ +%module example + +%{ +#include "example.h" +%} + +/* Let's just grab the original header file here */ +%include "example.h" +</pre> +</blockquote> + +Note: when creating a C++ extension, you must run SWIG with the <tt>-c++</tt> option like this: +<blockquote> +<pre> +% swig -c++ -tcl example.i +</pre> +</blockquote> + +<h2>Some sample Tcl scripts</h2> + +SWIG performs two forms of C++ wrapping-- a low level interface and a high level widget-like interface. +<ul> +<li> +Click <a href="example1.tcl">here</a> to see a script that calls the C++ functions using the +low-level interface. +<li> +Click <a href="example2.tcl">here</a> to see a the same script written with the high-level +interface. +</ul> + +<h2>Key points</h2> + +<ul> +<li>The low-level C++ interface works like this: +<p> +<ul> +<li>To create a new object, you call a constructor like this: + +<blockquote> +<pre> +set c [new_Circle 10.0] +</pre> +</blockquote> + +<p> +<li>To access member data, a pair of accessor functions are used. +For example: + +<blockquote> +<pre> +Shape_x_set $c 15 ;# Set member data +set x [Shape_x_get $c] ;# Get member data +</pre> +</blockquote> + +Note: when accessing member data, the name of the base class must +be used such as <tt>Shape_x_get</tt> + +<p> +<li>To invoke a member function, you simply do this + +<blockquote> +<pre> +puts "The area is [Shape_area $c]" +</pre> +</blockquote> + +<p> +<li>Type checking knows about the inheritance structure of C++. For example: + +<blockquote> +<pre> +Shape_area $c # Works (c is a Shape) +Circle_area $c # Works (c is a Circle) +Square_area $c # Fails (c is definitely not a Square) +</pre> +</blockquote> + +<p> +<li>To invoke a destructor, simply do this + +<blockquote> +<pre> +delete_Shape $c # Deletes a shape +</pre> +</blockquote> + +<p> +<li>Static member variables are wrapped as C global variables. For example: + +<blockquote> +<pre> +set n $Shape_nshapes # Get a static data member +set Shapes_nshapes 13 # Set a static data member +</pre> +</blockquote> + +</ul> + +<p> +<li>The high-level interface works like a Tk widget + +<p> +<ul> +<li>To create a new object, you call a constructor like this: + +<blockquote> +<pre> +Circle c 10 # c becomes a name for the Circle object +</pre> +</blockquote> + +<p> +<li>To access member data, use cget and configure methods. +For example: + +<blockquote> +<pre> +c configure -x 15 ;# Set member data +set x [c cget -x] ;# Get member data +</pre> +</blockquote> + +<p> +<li>To invoke a member function, you simply do this + +<blockquote> +<pre> +puts "The area is [c area]" +</pre> +</blockquote> + +<p> +<li>To invoke a destructor, simply destroy the object name like this: + +<blockquote> +<pre> +rename c "" # c goes away +</pre> +</blockquote> + +<p> +<li>Static member variables are wrapped as C global variables. For example: + +<blockquote> +<pre> +set n $Shape_nshapes # Get a static data member +set Shapes_nshapes 13 # Set a static data member +</pre> +</blockquote> + +</ul> +</ul> + +<h2>General Comments</h2> + +<ul> +<li>The low-level function interface is much faster than the high-level interface. +In fact, all the higher level interface does is call functions in the low-level interface. + +<p> +<li>SWIG *does* know how to properly perform upcasting of objects in an inheritance +hierarchy (including multiple inheritance). Therefore it is perfectly safe to pass +an object of a derived class to any function involving a base class. + +<p> +<li>A wide variety of C++ features are not currently supported by SWIG. Here is the +short and incomplete list: + +<p> +<ul> +<li>Overloaded methods and functions. SWIG wrappers don't know how to resolve name +conflicts so you must give an alternative name to any overloaded method name using the +%name directive like this: + +<blockquote> +<pre> +void foo(int a); +%name(foo2) void foo(double a, double b); +</pre> +</blockquote> + +<p> +<li>Overloaded operators. Not supported at all. The only workaround for this is +to write a helper function. For example: + +<blockquote> +<pre> +%inline %{ + Vector *vector_add(Vector *a, Vector *b) { + ... whatever ... + } +%} +</pre> +</blockquote> + +<p> +<li>Namespaces. Not supported at all. Won't be supported until SWIG2.0 (if at all). + +</ul> + +<hr> +</body> +</html> diff --git a/Examples/tcl/class/runme.tcl b/Examples/tcl/class/runme.tcl new file mode 100644 index 0000000..c7f4725 --- /dev/null +++ b/Examples/tcl/class/runme.tcl @@ -0,0 +1,50 @@ +# file: runme.tcl + +# This file illustrates the high level C++ interface. +# In this case C++ classes work kind of like Tk widgets + +catch { load ./example[info sharedlibextension] example} + +# ----- Object creation ----- + +puts "Creating some objects:" +Circle c 10 +puts " Created circle [c cget -this]" +Square s 10 +puts " Created square [s cget -this]" + +# ----- Access a static member ----- + +puts "\nA total of $Shape_nshapes shapes were created" + +# ----- Member data access ----- + +# Set the location of the object + +c configure -x 20 -y 30 +s configure -x -10 -y 5 + +puts "\nHere is their current position:" +puts " Circle = ([c cget -x], [c cget -y])" +puts " Square = ([s cget -x], [s cget -y])" + +# ----- Call some methods ----- + +puts "\nHere are some properties of the shapes:" +foreach o "c s" { + puts " [$o cget -this]" + puts " area = [$o area]" + puts " perimeter = [$o perimeter]" +} + +# ----- Delete everything ----- + +puts "\nGuess I'll clean up now" + +# Note: this invokes the virtual destructor +rename c "" +rename s "" + +puts "$Shape_nshapes shapes remain" +puts "Goodbye" + diff --git a/Examples/tcl/class/runme2.tcl b/Examples/tcl/class/runme2.tcl new file mode 100644 index 0000000..88ec2f6 --- /dev/null +++ b/Examples/tcl/class/runme2.tcl @@ -0,0 +1,70 @@ +# file: runme2.tcl + +# This file illustrates the low-level C++ interface +# created by SWIG. In this case, all of our C++ classes +# get converted into function calls. + +catch { load ./example[info sharedlibextension] example} + +# ----- Object creation ----- + +puts "Creating some objects:" +set c [new_Circle 10] +puts " Created circle $c" +set s [new_Square 10] +puts " Created square $s" + +# ----- Access a static member ----- + +puts "\nA total of $Shape_nshapes shapes were created" + +# ----- Member data access ----- + +# Set the location of the object +# Note: the base class must be used since that's where x and y +# were declared. + +Shape_x_set $c 20 +Shape_y_set $c 30 +Shape_x_set $s -10 +Shape_y_set $s 5 + +puts "\nHere is their current position:" +puts " Circle = ([Shape_x_get $c], [Shape_y_get $c])" +puts " Square = ([Shape_x_get $s], [Shape_y_get $s])" + +# ----- Call some methods ----- + +puts "\nHere are some properties of the shapes:" +foreach o "$c $s" { + puts " $o" + puts " area = [Shape_area $o]" + puts " perimeter = [Shape_perimeter $o]" +} +# Notice how the Shape_area() and Shape_perimeter() functions really +# invoke the appropriate virtual method on each object. + +# ----- Try to cause a type error ----- + +puts "\nI'm going to try and break the type system" + +if { [catch { + # Bad script! + Square_area $c # Try to invoke Square method on a Circle + puts " Bad bad SWIG!" + +}]} { + puts " Well, it didn't work. Good SWIG." +} + +# ----- Delete everything ----- + +puts "\nGuess I'll clean up now" + +# Note: this invokes the virtual destructor +delete_Shape $c +delete_Shape $s + +puts "$Shape_nshapes shapes remain" +puts "Goodbye" + |
