summaryrefslogtreecommitdiffstats
path: root/generic/tclPkg.c
diff options
context:
space:
mode:
Diffstat (limited to 'generic/tclPkg.c')
-rw-r--r--generic/tclPkg.c82
1 files changed, 63 insertions, 19 deletions
diff --git a/generic/tclPkg.c b/generic/tclPkg.c
index 919b1b9..43d859b 100644
--- a/generic/tclPkg.c
+++ b/generic/tclPkg.c
@@ -9,7 +9,7 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclPkg.c,v 1.8 2002/01/17 04:37:33 dgp Exp $
+ * RCS: @(#) $Id: tclPkg.c,v 1.9 2002/02/22 22:36:09 dgp Exp $
*/
#include "tclInt.h"
@@ -187,7 +187,7 @@ Tcl_PkgRequireEx(interp, name, version, exact, clientDataPtr)
Tcl_DString command;
/*
- * If an attempt is being made to load this into a standalong executable
+ * If an attempt is being made to load this into a standalone executable
* on a platform where backlinking is not supported then this must be
* a shared version of Tcl (Otherwise the load would have failed).
* Detect this situation by checking that this library has been correctly
@@ -195,7 +195,67 @@ Tcl_PkgRequireEx(interp, name, version, exact, clientDataPtr)
* work.
*/
- if (!tclEmptyStringRep) {
+ if (tclEmptyStringRep == NULL) {
+
+ /*
+ * OK, so what's going on here?
+ *
+ * First, what are we doing? We are performing a check on behalf of
+ * one particular caller, Tcl_InitStubs(). When a package is
+ * stub-enabled, it is statically linked to libtclstub.a, which
+ * contains a copy of Tcl_InitStubs(). When a stub-enabled package
+ * is loaded, its *_Init() function is supposed to call
+ * Tcl_InitStubs() before calling any other functions in the Tcl
+ * library. The first Tcl function called by Tcl_InitStubs() through
+ * the stub table is Tcl_PkgRequireEx(), so this code right here is
+ * the first code that is part of the original Tcl library in the
+ * executable that gets executed on behalf of a newly loaded
+ * stub-enabled package.
+ *
+ * One easy error for the developer/builder of a stub-enabled package
+ * to make is to forget to define USE_TCL_STUBS when compiling the
+ * package. When that happens, the package will contain symbols
+ * that are references to the Tcl library, rather than function
+ * pointers referencing the stub table. On platforms that lack
+ * backlinking, those unresolved references may cause the loading
+ * of the package to also load a second copy of the Tcl library,
+ * leading to all kinds of trouble. We would like to catch that
+ * error and report a useful message back to the user. That's
+ * what we're doing.
+ *
+ * Second, how does this work? If we reach this point, then the
+ * global variable tclEmptyStringRep has the value NULL. Compare
+ * that with the definition of tclEmptyStringRep near the top of
+ * the file generic/tclObj.c. It clearly should not have the value
+ * NULL; it should point to the char tclEmptyString. If we see it
+ * having the value NULL, then somehow we are seeing a Tcl library
+ * that isn't completely initialized, and that's an indicator for the
+ * error condition described above. (Further explanation is welcome.)
+ *
+ * Third, so what do we do about it? This situation indicates
+ * the package we just loaded wasn't properly compiled to be
+ * stub-enabled, yet it thinks it is stub-enabled (it called
+ * Tcl_InitStubs()). We want to report that the package just
+ * loaded is broken, so we want to place an error message in
+ * the interpreter result and return NULL to indicate failure
+ * to Tcl_InitStubs() so that it will also fail. (Further
+ * explanation why we don't want to Tcl_Panic() is welcome.
+ * After all, two Tcl libraries can't be a good thing!)
+ *
+ * Trouble is that's going to be tricky. We're now using a Tcl
+ * library that's not fully initialized. In particular, it
+ * doesn't have a proper value for tclEmptyStringRep. The
+ * Tcl_Obj system heavily depends on the value of tclEmptyStringRep
+ * and all of Tcl depends (increasingly) on the Tcl_Obj system, we
+ * need to correct that flaw before making the calls to set the
+ * interpreter result to the error message. That's the only flaw
+ * corrected; other problems with initialization of the Tcl library
+ * are not remedied, so be very careful about adding any other calls
+ * here without checking how they behave when initialization is
+ * incomplete.
+ */
+
+ tclEmptyStringRep = &tclEmptyString;
Tcl_AppendResult(interp, "Cannot load package \"", name,
"\" in standalone executable: This package is not ",
"compiled with stub support", NULL);
@@ -387,22 +447,6 @@ Tcl_PkgPresentEx(interp, name, version, exact, clientDataPtr)
Package *pkgPtr;
int satisfies, result;
- /*
- * If an attempt is being made to load this into a standalone executable
- * on a platform where backlinking is not supported then this must be
- * a shared version of Tcl (Otherwise the load would have failed).
- * Detect this situation by checking that this library has been correctly
- * initialised. If it has not been then return immediately as nothing will
- * work.
- */
-
- if (!tclEmptyStringRep) {
- Tcl_AppendResult(interp, "Cannot load package \"", name,
- "\" in standalone executable: This package is not ",
- "compiled with stub support", NULL);
- return NULL;
- }
-
hPtr = Tcl_FindHashEntry(&iPtr->packageTable, name);
if (hPtr) {
pkgPtr = (Package *) Tcl_GetHashValue(hPtr);