extern int __declspec(dllexport) Foo_Init(Tcl_Interp *); ... int __declspec(dllexport) Foo_Init(Tcl_Interp *interp) { ... }Most other compilers for Windows (including the MinGW and CYGWIN versions of gcc) have adopted this extension.Naturally, the __declspec(dllexport) bit should be hidden inside a preprocessor macro for cross-platform portability. Tcl.h defines such a macro: the symbol DLLEXPORT expands to the appropriate Windows voodoo if the compilation environment supports it, and to the empty string otherwise.
int DLLEXPORT Foo_Init(Tcl_Interp *interp) { ... }
That should be sufficient for Tcl extensions' _Init() and _SafeInit() routines. In the general case, though, more preprocessor trickery is needed.Windows also requires that functions appearing in an external shared library be declared with the "__declspec(dllimport)" storage class. Instead of creating two copies of each header file — one with __declspec(dllimport) for users of the library and one with __declspec(dllexport) for the library itself — the usual idiom is to say:
#ifdef BUILD_FOO # define FOOAPI __declspec(dllexport) #else # define FOOAPI __declspec(dllimport) #endif ... extern int FOOAPI foo_fiddle(); extern int FOOAPI foo_faddle(); extern int FOOAPI foo_twaddle();in the relevant header files, then compile the library with -DBUILD_FOO. Tcl does this, too; the macro TCL_STORAGE_CLASS expands to __declspec(dllexport) when building Tcl on Windows, __declspec(dllimport) when linking directly against the Tcl shared library, and to the empty string when linking with the Stubs library and on non-Windows platforms.Many Tcl extensions use preprocessor contortions like:
#undef TCL_STORAGE_CLASS #ifdef BUILD_sampleextension # define TCL_STORAGE_CLASS DLLEXPORT #endif ... EXTERN int Sample_Init(); …This is overly complex and error-prone; I recommend not doing this. Basically, this is hijacking Tcl's preprocessor voodoo for reuse by other packages. It's simpler, clearer, and safer for extensions to just define their own voodoo.