Tcl HomeTcl Home Hosted by
ActiveState

Google SiteSearch

Building Extensions on Windows

This page describes the compiler macros you need to use when compiling a Tcl extension for Windows. This assumes you are building a DLL that will be loaded into Tcl with its load command. With the Windows compilers you have to worry about how you export symbols from DLLs. tcl.h defines a few macros to help solve this problem:
EXTERN
all Tcl_ function prototypes use this macro, which implies they are exported. You'll see this used in tcl.h and tk.h. You should use this in your exported procedures. However, this is not the whole story.
TCL_STORAGE_CLASS
this is really an import/export flag, depending on if you are importing symbols from a DLL (i.e., a user of the DLL), or if you are exporting symbols from the DLL (i.e., you are building it.) The EXTERN macro includes TCL_STORAGE_CLASS. TCL_STORAGE_CLASS is defined to be either DLLIMPORT or DLLEXPORT as described below.
STATIC_BUILD
define this if you are *not* building a DLL (e.g., a main program)
DLL_BUILD
define this if you *are* building a DLL
DLLIMPORT
If STATIC_BUILD is defined, this becomes nothing. (On UNIX, DLLIMPORT is defined to be empty) Otherwise, this this expands to __declspec(dllimport)
DLLEXPORT
If STATIC_BUILD is defined, this becomes nothing. (On UNIX, DLLEXPORT is defined to be empty) Otherwise, this this expands to __declspec(dllexport)
EXPORT(type, func)
For the Borland compiler, you need to export functions differently. The DLLEXPORT macro is empty, and instead you need to use EXPORT because they had a different order. Your declaration will look like
EXTERN EXPORT(int, Foo_Init)(Tcl_Interp *interp);
We have not defined EXPORT anywhere. You can paste this into your C file:
#ifndef STATIC_BUILD
#if defined(_MSC_VER)
#   define EXPORT(a,b) __declspec(dllexport) a b
#   define DllEntryPoint DllMain
#else
#   if defined(__BORLANDC__)
#       define EXPORT(a,b) a _export b
#   else
#       define EXPORT(a,b) a b
#   endif
#endif
#endif
How to use these:

Assume your extension is named Foo. In its Makefile, define BUILD_Foo so that you know you are building Foo and not using it. Then, in your main header file, foo.h, conditionally define EXPORT to be either DLLIMPORT or DLLEXPORT based on the presense of BUILD_Foo, like this:

#ifndef _FOO
#define _FOO
#include "tcl.h"
/* Additional includes go here */
/*
 * if the BUILD_foo macro is defined, the assumption is that we are
 * building the dynamic library.
 */
#ifdef BUILD_Foo
#  undef TCL_STORAGE_CLASS
#  define TCL_STORAGE_CLASS DLLEXPORT
#endif
/*
 * Function prototypes for this module.
 */
EXTERN int Foo_Init _ANSI_ARGS_((Tcl_Interp *interp));
EXTERN int Foo_SafeInit _ANSI_ARGS_((Tcl_Interp *interp));
/* Additional prototypes go here */
/*
 * end of foo.h
 * reset TCL_STORAGE_CLASS to DLLIMPORT.
 */
# undef TCL_STORAGE_CLASS
# define TCL_STORAGE_CLASS DLLIMPORT
#endif /* _FOO */
In your C file, put EXTERN before then functions you need to export. If you use Borland, you'll need to use the old EXPORT macro, too. Add link to comments for /doc/howto/winext.tml