Tcl Extension Architecture (TEA) Sample Extension

Check-in [1b651d6b40]
Login
Bounty program for improvements to Tcl and certain Tcl packages.
Tcl 2019 Conference, Houston/TX, US, Nov 4-8
Send your abstracts to [email protected]
or submit via the online form by Sep 9.

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:[Bug 2782806] sample package's test cases fail
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 1b651d6b40298baca1f3ebcb43754d0a38a4218d
User & Date: nijtmans 2010-04-23 11:51:53
References
2014-10-03
02:56 Closed ticket [2788536fff]: sample extension does not load plus 10 other changes artifact: 624537fbd2 user: stwo
Context
2010-04-23
12:10
Always define BUILD_sample, even on UNIX. check-in: d44e9373b5 user: nijtmans tags: trunk
11:51
[Bug 2782806] sample package's test cases fail check-in: 1b651d6b40 user: nijtmans tags: trunk
11:23
configure: Regenerated to use latest TEA tcl.m4. check-in: 532413ad00 user: nijtmans tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to .cvsignore.

1
2
3
4

5
autom4te.cache
Makefile
pkgIndex.tcl
*.dll

config.status



>

1
2
3
4
5
6
autom4te.cache
Makefile
pkgIndex.tcl
*.dll
*.so
config.status

Changes to ChangeLog.

1
2
3

4
5
6
7
8
9
10
2010-04-23  Jan Nijtmans <[email protected]>

	* configure: Regenerated to use latest TEA tcl.m4.


2010-02-19  Stuart Cassoff  <[email protected]>

	* tcl.m4: Correct compiler/linker flags
	for threaded builds on OpenBSD.
	* configure: Regenerated to use latest TEA tcl.m4.



>







1
2
3
4
5
6
7
8
9
10
11
2010-04-23  Jan Nijtmans <[email protected]>

	* configure: Regenerated to use latest TEA tcl.m4.
	* [Bug 2782806] sample package's test cases fail

2010-02-19  Stuart Cassoff  <[email protected]>

	* tcl.m4: Correct compiler/linker flags
	for threaded builds on OpenBSD.
	* configure: Regenerated to use latest TEA tcl.m4.

Changes to generic/tclsample.c.

332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
...
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
 *	function name must match the PACKAGE declaration at the top of
 *	configure.in.
 *
 * Results:
 *	A standard Tcl result
 *
 * Side effects:
 *	The Tclsha1 package is created.
 *	One new command "sha1" is added to the Tcl interpreter.
 *
 *----------------------------------------------------------------------
 */

int
Sample_Init(Tcl_Interp *interp)
................................................................................
     */
    if (Tcl_InitStubs(interp, "8.1", 0) == NULL) {
	return TCL_ERROR;
    }
    if (Tcl_PkgRequire(interp, "Tcl", "8.1", 0) == NULL) {
	return TCL_ERROR;
    }
    if (Tcl_PkgProvide(interp, "Tclsha1", PACKAGE_VERSION) != TCL_OK) {
	return TCL_ERROR;
    }
    Tcl_CreateObjCommand(interp, "sha1", (Tcl_ObjCmdProc *) Sha1_Cmd,
	    (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);

    numcontexts = 1;
    sha1Contexts = (SHA1_CTX *) malloc(sizeof(SHA1_CTX));
    ctxtotalRead = (int *) malloc(sizeof(int));
    ctxtotalRead[0] = 0;

    return TCL_OK;
}






|







 







|












332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
...
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
 *	function name must match the PACKAGE declaration at the top of
 *	configure.in.
 *
 * Results:
 *	A standard Tcl result
 *
 * Side effects:
 *	The Sample package is created.
 *	One new command "sha1" is added to the Tcl interpreter.
 *
 *----------------------------------------------------------------------
 */

int
Sample_Init(Tcl_Interp *interp)
................................................................................
     */
    if (Tcl_InitStubs(interp, "8.1", 0) == NULL) {
	return TCL_ERROR;
    }
    if (Tcl_PkgRequire(interp, "Tcl", "8.1", 0) == NULL) {
	return TCL_ERROR;
    }
    if (Tcl_PkgProvide(interp, PACKAGE_NAME, PACKAGE_VERSION) != TCL_OK) {
	return TCL_ERROR;
    }
    Tcl_CreateObjCommand(interp, "sha1", (Tcl_ObjCmdProc *) Sha1_Cmd,
	    (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);

    numcontexts = 1;
    sha1Contexts = (SHA1_CTX *) malloc(sizeof(SHA1_CTX));
    ctxtotalRead = (int *) malloc(sizeof(int));
    ctxtotalRead[0] = 0;

    return TCL_OK;
}

Changes to tea/packages.txt.

65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
..
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
...
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
...
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
...
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
   #
   # Copyright (c) 1998-2000 by Ajuba Solutions.
   # Copyright (c) 1998 by Mark Harrison.
   #
   # See the file "license.terms" for information on usage and redistribution
   # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
   #
   # RCS: @(#) $Id: packages.txt,v 1.1 2004/05/24 12:27:28 arjenmarkus Exp $

   package require Tcl 8.2
   # When the version number changes, be sure to update the pkgIndex.tcl file,
   # and the installation directory in the Makefiles.
   package provide msgcat 1.3

   namespace eval msgcat {
................................................................................
   package ifneeded msgcat 1.3 [list source [file join $dir msgcat.tcl]]
}]

Note the variable "$dir" in the second statement: this variable is set
by the package mechanism when it is looking for the required package.

[para]
From the example extension (SHA1):
[example {
/*
 *----------------------------------------------------------------------
 *
 * Examplea_Init --
 *
 *      Initialize the new package.  The string "Examplea" in the
 *      function name must match the PACKAGE declaration at the top of
 *      configure.in.
 *
 * Results:
 *      A standard Tcl result
 *
 * Side effects:
 *      The Tclsha1 package is created.
 *      One new command "sha1" is added to the Tcl interpreter.
 *
 *----------------------------------------------------------------------
 */

int
Examplea_Init(Tcl_Interp *interp)
{
    if (Tcl_InitStubs(interp, "8.0", 0) == NULL) {
        return TCL_ERROR;
    }
    if (Tcl_PkgRequire(interp, "Tcl", TCL_VERSION, 0) == NULL) {
        if (TCL_VERSION[0] == '7') {
            if (Tcl_PkgRequire(interp, "Tcl", "8.0", 0) == NULL) {
                return TCL_ERROR;
            }
        }
    }
    if (Tcl_PkgProvide(interp, "Tclsha1", VERSION) != TCL_OK) {
        return TCL_ERROR;
    }
    Tcl_CreateCommand(interp, "sha1", Sha1,
            (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);

    ...
}
}]
As this extension is built via the TEA facilities, a pkgIndex.tcl
file is provided for automatically. Instead of simply sourcing a
Tcl script, it will load the shared object or DLL that was built from
the C sources, roughly like:
[example {
   package ifneeded Tclsha1 1.0 [list load [file join $dir libTclsha1.so]]
}]
or:
[example {
   package ifneeded Tclsha1 1.0 [list load [file join $dir Tclsha1.dll]]
}]
The TEA will create the pkgIndex.tcl file automatically via the
pkg_mkIndex command.


[section {Details on version numbers}]

................................................................................
   # __CHANGE__
   # Set your package name and version numbers here.  The NODOT_VERSION is
   # required for constructing the library name on systems that don't like
   # dots in library names (Windows).  The VERSION variable is used on the
   # other systems.
   #--------------------------------------------------------------------

   PACKAGE=exampleA

   MAJOR_VERSION=0
   MINOR_VERSION=2
   PATCHLEVEL=

   VERSION=${MAJOR_VERSION}.${MINOR_VERSION}${PATCHLEVEL}
   NODOT_VERSION=${MAJOR_VERSION}${MINOR_VERSION}
}]

So, the above would result in a macro VERSION with the value 0.2
[para]
The version number is also used to construct a distinguishing name for
the library, like: libexampleA.0.2.so or exampleA02.dll.
This way there is much less chance of a conflict between versions.


[section {Subtleties with package names}]

There are a few things you must be aware of when choosing a name for
the extension:
................................................................................
initialisation routine. The precise rules are explained in the manual
page for the load command, but here are a few examples:
[example {
   Filename        Package name    Initial procedure
   foo.dll         foo             Foo_Init
   FOO.DLL         fOO             Foo_Init
   libFOO.so       fOO             Foo_Init
   libfoo.1.2.so   fOo             Foo_Init
}]
So, in the index file you might see:
[example {
   package ifneeded fOo 1.2 [list load [file join $dir libfoo.1.2.so]]
}]
A second issue is that for the extension to useful in a [emph safe]
interpreter, you need to define an initialisation routine with a name
like "Foo_SafeInit" (and possibly define the commands in another, safer,
way).

[para]
................................................................................
The third issue that we would like to bring under your attention is the
fact that under Windows you must explicitly indicate that a function in
a DLL is to made visible (exported) to the outside world. Without this
instruction the initialisation routine can not be loaded and therefore
loading the extension fails.

[para]
The sample extension contains this fragment of code (exampleA.h) to take
care of this (in general, the initialisation routine is the only one
that needs to be exported - all others should be defined as [emph static] to
reduce the chance of naming conflicts):
[example {
   /*
    * Windows needs to know which symbols to export.  Unix does not.
    * BUILD_exampleA should be undefined for Unix.
    */

   #ifdef BUILD_exampleA
   #undef TCL_STORAGE_CLASS
   #define TCL_STORAGE_CLASS DLLEXPORT
   #endif /* BUILD_exampleA */

   ...

   /*
    * Only the _Init function is exported.
    */

   EXTERN int      Examplea_Init _ANSI_ARGS_((Tcl_Interp * interp));
}]






|







 







|




|

|







|






|











|













|



|







 







|


|






|


|







 







|



|







 







|









|


|







|

65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
..
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
...
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
...
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
...
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
   #
   # Copyright (c) 1998-2000 by Ajuba Solutions.
   # Copyright (c) 1998 by Mark Harrison.
   #
   # See the file "license.terms" for information on usage and redistribution
   # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
   #
   # RCS: @(#) $Id: packages.txt,v 1.2 2010/04/23 11:51:53 nijtmans Exp $

   package require Tcl 8.2
   # When the version number changes, be sure to update the pkgIndex.tcl file,
   # and the installation directory in the Makefiles.
   package provide msgcat 1.3

   namespace eval msgcat {
................................................................................
   package ifneeded msgcat 1.3 [list source [file join $dir msgcat.tcl]]
}]

Note the variable "$dir" in the second statement: this variable is set
by the package mechanism when it is looking for the required package.

[para]
From the example extension (Sample):
[example {
/*
 *----------------------------------------------------------------------
 *
 * Sample_Init --
 *
 *      Initialize the new package.  The string "Sample" in the
 *      function name must match the PACKAGE declaration at the top of
 *      configure.in.
 *
 * Results:
 *      A standard Tcl result
 *
 * Side effects:
 *      The Sample package is created.
 *      One new command "sha1" is added to the Tcl interpreter.
 *
 *----------------------------------------------------------------------
 */

int
Sample_Init(Tcl_Interp *interp)
{
    if (Tcl_InitStubs(interp, "8.0", 0) == NULL) {
        return TCL_ERROR;
    }
    if (Tcl_PkgRequire(interp, "Tcl", TCL_VERSION, 0) == NULL) {
        if (TCL_VERSION[0] == '7') {
            if (Tcl_PkgRequire(interp, "Tcl", "8.0", 0) == NULL) {
                return TCL_ERROR;
            }
        }
    }
    if (Tcl_PkgProvide(interp, "sample", VERSION) != TCL_OK) {
        return TCL_ERROR;
    }
    Tcl_CreateCommand(interp, "sha1", Sha1,
            (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);

    ...
}
}]
As this extension is built via the TEA facilities, a pkgIndex.tcl
file is provided for automatically. Instead of simply sourcing a
Tcl script, it will load the shared object or DLL that was built from
the C sources, roughly like:
[example {
   package ifneeded sample 1.0 [list load [file join $dir libsample.so]]
}]
or:
[example {
   package ifneeded sample 1.0 [list load [file join $dir sample.dll]]
}]
The TEA will create the pkgIndex.tcl file automatically via the
pkg_mkIndex command.


[section {Details on version numbers}]

................................................................................
   # __CHANGE__
   # Set your package name and version numbers here.  The NODOT_VERSION is
   # required for constructing the library name on systems that don't like
   # dots in library names (Windows).  The VERSION variable is used on the
   # other systems.
   #--------------------------------------------------------------------

   PACKAGE=sample

   MAJOR_VERSION=0
   MINOR_VERSION=5
   PATCHLEVEL=

   VERSION=${MAJOR_VERSION}.${MINOR_VERSION}${PATCHLEVEL}
   NODOT_VERSION=${MAJOR_VERSION}${MINOR_VERSION}
}]

So, the above would result in a macro VERSION with the value 0.5
[para]
The version number is also used to construct a distinguishing name for
the library, like: libsample0.5.so or sample05.dll.
This way there is much less chance of a conflict between versions.


[section {Subtleties with package names}]

There are a few things you must be aware of when choosing a name for
the extension:
................................................................................
initialisation routine. The precise rules are explained in the manual
page for the load command, but here are a few examples:
[example {
   Filename        Package name    Initial procedure
   foo.dll         foo             Foo_Init
   FOO.DLL         fOO             Foo_Init
   libFOO.so       fOO             Foo_Init
   libfoo1.2.so    fOo             Foo_Init
}]
So, in the index file you might see:
[example {
   package ifneeded fOo 1.2 [list load [file join $dir libfoo1.2.so]]
}]
A second issue is that for the extension to useful in a [emph safe]
interpreter, you need to define an initialisation routine with a name
like "Foo_SafeInit" (and possibly define the commands in another, safer,
way).

[para]
................................................................................
The third issue that we would like to bring under your attention is the
fact that under Windows you must explicitly indicate that a function in
a DLL is to made visible (exported) to the outside world. Without this
instruction the initialisation routine can not be loaded and therefore
loading the extension fails.

[para]
The sample extension contains this fragment of code (sample.h) to take
care of this (in general, the initialisation routine is the only one
that needs to be exported - all others should be defined as [emph static] to
reduce the chance of naming conflicts):
[example {
   /*
    * Windows needs to know which symbols to export.  Unix does not.
    * BUILD_exampleA should be undefined for Unix.
    */

   #ifdef BUILD_sample
   #undef TCL_STORAGE_CLASS
   #define TCL_STORAGE_CLASS DLLEXPORT
   #endif /* BUILD_sample */

   ...

   /*
    * Only the _Init function is exported.
    */

   EXTERN int      Sample_Init _ANSI_ARGS_((Tcl_Interp * interp));
}]

Changes to tests/sample.test.

5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# generates output for errors.  No output means no errors were found.
#
# Copyright (c) 2000 by Scriptics Corporation.
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: sample.test,v 1.1 2002/03/06 05:35:31 hobbs Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import ::tcltest::*
}

package require Tclsha1

test sha-1.1 {Use of -string operand} {
    set result [sha1 -string foo]
} {0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33}

test sha-1.2 {Use of -init operand} {
    set result [catch {sha1 -init}]
} {0}


# cleanup
::tcltest::cleanupTests
return






|






|













5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# generates output for errors.  No output means no errors were found.
#
# Copyright (c) 2000 by Scriptics Corporation.
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: sample.test,v 1.2 2010/04/23 11:51:53 nijtmans Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import ::tcltest::*
}

package require sample

test sha-1.1 {Use of -string operand} {
    set result [sha1 -string foo]
} {0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33}

test sha-1.2 {Use of -init operand} {
    set result [catch {sha1 -init}]
} {0}


# cleanup
::tcltest::cleanupTests
return

Changes to tests/tclsample.test.

5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# generates output for errors.  No output means no errors were found.
#
# Copyright (c) 2000 by Scriptics Corporation.
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: tclsample.test,v 1.2 2004/12/02 00:35:38 dkf Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import ::tcltest::*
}

package require Tclsha1

test sha-1.1 {incorrect command usage} {
    list [catch {sha1} errMsg] $errMsg
} {1 {wrong # args: should be either:
  sha1 ?-log2base log2base? -string string
 or
  sha1 ?-log2base log2base? ?-copychan chanID? -chan chanID






|






|







5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# generates output for errors.  No output means no errors were found.
#
# Copyright (c) 2000 by Scriptics Corporation.
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: tclsample.test,v 1.3 2010/04/23 11:51:53 nijtmans Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import ::tcltest::*
}

package require sample

test sha-1.1 {incorrect command usage} {
    list [catch {sha1} errMsg] $errMsg
} {1 {wrong # args: should be either:
  sha1 ?-log2base log2base? -string string
 or
  sha1 ?-log2base log2base? ?-copychan chanID? -chan chanID

Changes to win/makefile.vc.

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
...
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
...
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
# Copyright (c) 1995-1996 Sun Microsystems, Inc.
# Copyright (c) 1998-2000 Ajuba Solutions.
# Copyright (c) 2001 ActiveState Corporation.
# Copyright (c) 2001-2002 David Gravereaux.
# Copyright (c) 2003-2006 Pat Thoyts
#
#-------------------------------------------------------------------------
# RCS: @(#)$Id: makefile.vc,v 1.11 2009/05/04 23:47:55 patthoyts Exp $
#-------------------------------------------------------------------------

# Check to see we are configured to build with MSVC (MSDEVDIR or MSVCDIR)
# or with the MS Platform SDK (MSSDK). Visual Studio .NET 2003 and 2005 define
# VCINSTALLDIR instead. The MSVC Toolkit release defines yet another.
!if !defined(MSDEVDIR) && !defined(MSVCDIR) && !defined(MSSDK) && !defined(VCINSTALLDIR) && !defined(VCToolkitInstallDir)
MSG = ^
................................................................................
#-------------------------------------------------------------------------
# Project specific information (EDIT)
#
# You should edit this with the name and version of your project. This
# information is used to generate the name of the package library and
# it's install location.
#
# For example, the sample extension is  going to build sample04.dll and
# would install it into $(INSTALLDIR)\lib\sample04
#
# You need to specify the object files that need to be linked into your
# binary here.
#
#-------------------------------------------------------------------------

PROJECT = sample
................................................................................

$(OUT_DIR)\pkgIndex.tcl: $(ROOT)\pkgIndex.tcl.in
	@nmakehlp -s << $** > [email protected]
@[email protected]    $(DOTVERSION)
@[email protected]       $(PROJECT)
@[email protected]       $(PRJLIBNAME)
<<
	@echo package ifneeded Tclsha1 $(DOTVERSION) \
	    [list load [file join $$dir $(PRJLIBNAME)] Sample] >> [email protected]

#---------------------------------------------------------------------
# Installation. (EDIT)
#
# You may need to modify this section to reflect the final distribution
# of your files and possibly to generate documentation.






|







 







|
|







 







|







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
...
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
...
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
# Copyright (c) 1995-1996 Sun Microsystems, Inc.
# Copyright (c) 1998-2000 Ajuba Solutions.
# Copyright (c) 2001 ActiveState Corporation.
# Copyright (c) 2001-2002 David Gravereaux.
# Copyright (c) 2003-2006 Pat Thoyts
#
#-------------------------------------------------------------------------
# RCS: @(#)$Id: makefile.vc,v 1.12 2010/04/23 11:51:53 nijtmans Exp $
#-------------------------------------------------------------------------

# Check to see we are configured to build with MSVC (MSDEVDIR or MSVCDIR)
# or with the MS Platform SDK (MSSDK). Visual Studio .NET 2003 and 2005 define
# VCINSTALLDIR instead. The MSVC Toolkit release defines yet another.
!if !defined(MSDEVDIR) && !defined(MSVCDIR) && !defined(MSSDK) && !defined(VCINSTALLDIR) && !defined(VCToolkitInstallDir)
MSG = ^
................................................................................
#-------------------------------------------------------------------------
# Project specific information (EDIT)
#
# You should edit this with the name and version of your project. This
# information is used to generate the name of the package library and
# it's install location.
#
# For example, the sample extension is  going to build sample05.dll and
# would install it into $(INSTALLDIR)\lib\sample05
#
# You need to specify the object files that need to be linked into your
# binary here.
#
#-------------------------------------------------------------------------

PROJECT = sample
................................................................................

$(OUT_DIR)\pkgIndex.tcl: $(ROOT)\pkgIndex.tcl.in
	@nmakehlp -s << $** > [email protected]
@[email protected]    $(DOTVERSION)
@[email protected]       $(PROJECT)
@[email protected]       $(PRJLIBNAME)
<<
	@echo package ifneeded sample $(DOTVERSION) \
	    [list load [file join $$dir $(PRJLIBNAME)] Sample] >> [email protected]

#---------------------------------------------------------------------
# Installation. (EDIT)
#
# You may need to modify this section to reflect the final distribution
# of your files and possibly to generate documentation.