Tcl Source Code

Changes On Branch frq-3579001
Login

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

Changes In Branch frq-3579001 Excluding Merge-Ins

This is equivalent to a diff from 73042d17c8 to 7e567b9e05

2012-11-15
00:20
IMPLEMENTATION OF TIP#416: New Options for 'load': -global and -lazy check-in: ee5b8dcfad user: jan.nijtmans tags: trunk
2012-11-14
13:01
* unix/tclUnixFCmd.c (TclUnixOpenTemporaryFile): [Bug 2933003]: Factor out all the code to do temp...
check-in: 2f3da59db1 user: dkf tags: trunk
09:58
merge trunk Closed-Leaf check-in: 7e567b9e05 user: jan.nijtmans tags: frq-3579001
09:12
Workaround for mingw versions which don't provide _fpcontrol in float.h check-in: 73042d17c8 user: jan.nijtmans tags: trunk
09:11
Workaround for mingw versions which don't provide _fpcontrol in float.h check-in: f93feee5b5 user: jan.nijtmans tags: core-8-5-branch
2012-11-13
21:23
360894 Threads inherit floating point config from their creator thread check-in: 3574448bf4 user: dgp tags: trunk
2012-11-12
08:01
merge trunk.

doc fix

check-in: 50ce5a659d user: jan.nijtmans tags: frq-3579001

Changes to doc/Load.3.

27
28
29
30
31
32
33
34


35
36
37
38
39
40
41
27
28
29
30
31
32
33

34
35
36
37
38
39
40
41
42







-
+
+







The name of the file to load. If it is a single name, the library search path
of the current environment will be used to resolve it.
.AP "const char *const" symbols[] in
Array of names of symbols to be resolved during the load of the library, or
NULL if no symbols are to be resolved. If an array is given, the last entry in
the array must be NULL.
.AP int flags in
Reserved for future expansion. Must be 0.
The value should normally be 0, but \fITCL_LOAD_GLOBALfR or \fITCL_LOAD_LAZYfR
or a combination of those two is allowed as well.
.AP void *procPtrs out
Points to an array that will hold the addresses of the functions described in
the \fIsymbols\fR argument. Should be NULL if no symbols are to be resolved.
.AP Tcl_LoadHandle *loadHandlePtr out
Points to a variable that will hold the handle to the abstract token
describing the library that has been loaded.
.AP Tcl_LoadHandle loadHandle in

Changes to doc/load.n.

1
2
3
4
5
6
7
8
9
10
11
12
13
14

15
16

17
18

19
20
21
22
23
24
25
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15

16
17

18
19
20
21
22
23
24
25













-
+

-
+

-
+







'\"
'\" Copyright (c) 1995-1996 Sun Microsystems, Inc.
'\"
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\" 
.so man.macros
.TH load n 7.5 Tcl "Tcl Built-In Commands"
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
load \- Load machine code and initialize new commands
.SH SYNOPSIS
\fBload \fIfileName\fR
\fBload\fR ?\fB\-global\fR? ?\fB\-lazy\fR? ?\fB\-\-\fR? \fIfileName\fR
.br
\fBload \fIfileName packageName\fR
\fBload\fR ?\fB\-global\fR? ?\fB\-lazy\fR? ?\fB\-\-\fR? \fIfileName packageName\fR
.br
\fBload \fIfileName packageName interp\fR
\fBload\fR ?\fB\-global\fR? ?\fB\-lazy\fR? ?\fB\-\-\fR? \fIfileName packageName interp\fR
.BE
.SH DESCRIPTION
.PP
This command loads binary code from a file into the
application's address space and calls an initialization procedure
in the package to incorporate it into an interpreter.  \fIfileName\fR
is the name of the file containing the code;  its exact form varies
100
101
102
103
104
105
106
















107
108
109
110
111
112
113
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







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







The \fBload\fR command first searches for a statically loaded package
(one that has been registered by calling the \fBTcl_StaticPackage\fR
procedure) by that name; if one is found, it is used.
Otherwise, the \fBload\fR command searches for a dynamically loaded
package by that name, and uses it if it is found.  If several
different files have been \fBload\fRed with different versions of
the package, Tcl picks the file that was loaded first.
.PP
If \fB\-global\fR is specified preceding the filename, all symbols
found in the shared library are exported for global use by other
libraries. The option \fB\-lazy\fR delays the actual loading of
symbols until their first actual use. The options may be abbreviated.
The option \fB\-\-\fR indicates the end of the options, and should
be used if you wish to use a filename which starts with \fB\-\fR
and you provide a packageName to the \fBload\fR command.
.PP
On platforms which do not support the \fB\-global\fR or \fB\-lazy\fR
options, the options still exist but have no effect. Note that use
of the \fB\-global\fR or \fB\-lazy\fR option may lead to crashes
in your application later (in case of symbol conflicts resp. missing
symbols), which cannot be detected during the \fBload\fR. So, only
use this when you know what you are doing, you will not get a nice
error message when something is wrong with the loaded library.
.SH "PORTABILITY ISSUES"
.TP
\fBWindows\fR\0\0\0\0\0
.
When a load fails with
.QW "library not found"
error, it is also possible

Changes to generic/tcl.h.

2356
2357
2358
2359
2360
2361
2362








2363
2364
2365
2366
2367
2368
2369
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377







+
+
+
+
+
+
+
+







 */

#define TCL_ZLIB_NO_FLUSH	0
#define TCL_ZLIB_FLUSH		2
#define TCL_ZLIB_FULLFLUSH	3
#define TCL_ZLIB_FINALIZE	4

/*
 *----------------------------------------------------------------------------
 * Definitions needed for the Tcl_LoadFile function. [TIP #416]
 */

#define TCL_LOAD_GLOBAL 1
#define TCL_LOAD_LAZY 2

/*
 *----------------------------------------------------------------------------
 * Single public declaration for NRE.
 */

typedef int (Tcl_NRPostProc) (ClientData data[], Tcl_Interp *interp,
				int result);

Changes to generic/tclLoad.c.

128
129
130
131
132
133
134








135

















136
137

138
139
140
141
142
143
144
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
154
155
156
157
158
159
160
161

162
163
164
165
166
167
168
169







+
+
+
+
+
+
+
+

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
+







    int code, namesMatch, filesMatch, offset;
    const char *symbols[2];
    Tcl_PackageInitProc *initProc;
    const char *p, *fullFileName, *packageName;
    Tcl_LoadHandle loadHandle;
    Tcl_UniChar ch;
    unsigned len;
    int index, flags = 0;
    Tcl_Obj *const *savedobjv = objv;
    static const char *const options[] = {
	"-global",		"-lazy",		"--",	NULL
    };
    enum options {
	LOAD_GLOBAL,	LOAD_LAZY,	LOAD_LAST
    };

    while (objc > 2) {
	if (TclGetString(objv[1])[0] != '-') {
	    break;
	}
	if (Tcl_GetIndexFromObj(interp, objv[1], options, "option", 0,
		&index) != TCL_OK) {
	    return TCL_ERROR;
	}
	++objv; --objc;
	if (LOAD_GLOBAL == (enum options) index) {
	    flags |= TCL_LOAD_GLOBAL;
	} else if (LOAD_LAZY == (enum options) index) {
	    flags |= TCL_LOAD_LAZY;
	} else {
		break;
	}
    }
    if ((objc < 2) || (objc > 4)) {
	Tcl_WrongNumArgs(interp, 1, objv, "fileName ?packageName? ?interp?");
	Tcl_WrongNumArgs(interp, 1, savedobjv, "?-global? ?-lazy? ?--? fileName ?packageName? ?interp?");
	return TCL_ERROR;
    }
    if (Tcl_FSConvertToPathType(interp, objv[1]) != TCL_OK) {
	return TCL_ERROR;
    }
    fullFileName = Tcl_GetString(objv[1]);

361
362
363
364
365
366
367
368

369
370
371
372
373
374
375
386
387
388
389
390
391
392

393
394
395
396
397
398
399
400







-
+







	 * initialization functions.
	 */

	symbols[0] = Tcl_DStringValue(&initName);
	symbols[1] = NULL;

	Tcl_MutexLock(&packageMutex);
	code = Tcl_LoadFile(interp, objv[1], symbols, 0, &initProc,
	code = Tcl_LoadFile(interp, objv[1], symbols, flags, &initProc,
		&loadHandle);
	Tcl_MutexUnlock(&packageMutex);
	if (code != TCL_OK) {
	    goto done;
	}

	/*
387
388
389
390
391
392
393
394

395
396
397
398
399
400
401
412
413
414
415
416
417
418

419
420
421
422
423
424
425
426







-
+







	pkgPtr->initProc	   = initProc;
	pkgPtr->safeInitProc	   = (Tcl_PackageInitProc *)
		Tcl_FindSymbol(interp, loadHandle,
			Tcl_DStringValue(&safeInitName));
	pkgPtr->unloadProc	   = (Tcl_PackageUnloadProc *)
		Tcl_FindSymbol(interp, loadHandle,
			Tcl_DStringValue(&unloadName));
	pkgPtr->safeUnloadProc	   = (Tcl_PackageUnloadProc *) 
	pkgPtr->safeUnloadProc	   = (Tcl_PackageUnloadProc *)
		Tcl_FindSymbol(interp, loadHandle,
			Tcl_DStringValue(&safeUnloadName));
	pkgPtr->interpRefCount	   = 0;
	pkgPtr->safeInterpRefCount = 0;

	Tcl_MutexLock(&packageMutex);
	pkgPtr->nextPtr		   = firstPackagePtr;

Changes to tests/load.test.

43
44
45
46
47
48
49
50

51
52
53

54
55
56
57
58

59
60
61

62
63
64
65






66
67
68
69

70
71
72
73
74
75

76
77
78
79
80
81
82
43
44
45
46
47
48
49

50
51
52

53
54
55
56
57

58
59
60

61
62
63
64
65
66
67
68
69
70
71
72
73
74

75
76
77
78
79
80

81
82
83
84
85
86
87
88







-
+


-
+




-
+


-
+




+
+
+
+
+
+



-
+





-
+







# Test load-10.1 requires the 'testsimplefilesystem' command from tcltest

testConstraint testsimplefilesystem \
	[llength [info commands testsimplefilesystem]]

test load-1.1 {basic errors} {} {
    list [catch {load} msg] $msg
} "1 {wrong \# args: should be \"load fileName ?packageName? ?interp?\"}"
} "1 {wrong \# args: should be \"load ?-global? ?-lazy? ?--? fileName ?packageName? ?interp?\"}"
test load-1.2 {basic errors} {} {
    list [catch {load a b c d} msg] $msg
} "1 {wrong \# args: should be \"load fileName ?packageName? ?interp?\"}"
} "1 {wrong \# args: should be \"load ?-global? ?-lazy? ?--? fileName ?packageName? ?interp?\"}"
test load-1.3 {basic errors} {} {
    list [catch {load a b foobar} msg] $msg
} {1 {could not find interpreter "foobar"}}
test load-1.4 {basic errors} {} {
    list [catch {load {}} msg] $msg
    list [catch {load -global {}} msg] $msg
} {1 {must specify either file name or package name}}
test load-1.5 {basic errors} {} {
    list [catch {load {} {}} msg] $msg
    list [catch {load -lazy {} {}} msg] $msg
} {1 {must specify either file name or package name}}
test load-1.6 {basic errors} {} {
    list [catch {load {} Unknown} msg] $msg
} {1 {package "Unknown" isn't loaded statically}}
test load-1.7 {basic errors} {} {
    list [catch {load -abc foo} msg] $msg
} "1 {bad option \"-abc\": must be -global, -lazy, or --}"
test load-1.8 {basic errors} {} {
    list [catch {load -global} msg] $msg
} "1 {couldn't figure out package name for -global}"

test load-2.1 {basic loading, with guess for package name} \
	[list $dll $loaded] {
    load [file join $testDir pkga$ext]
    load -global [file join $testDir pkga$ext]
    list [pkga_eq abc def] [lsort [info commands pkga_*]]
} {0 {pkga_eq pkga_quote}}
interp create -safe child
test load-2.2 {loading into a safe interpreter, with package name conversion} \
	[list $dll $loaded] {
    load [file join $testDir pkgb$ext] pKgB child
    load -lazy [file join $testDir pkgb$ext] pKgB child
    list [child eval pkgb_sub 44 13] [catch {child eval pkgb_unsafe} msg] $msg \
	    [catch {pkgb_sub 12 10} msg2] $msg2
} {31 1 {invalid command name "pkgb_unsafe"} 1 {invalid command name "pkgb_sub"}}
test load-2.3 {loading with no _Init procedure} -constraints [list $dll $loaded] \
-body {
    list [catch {load [file join $testDir pkgc$ext] foo} msg] $msg $errorCode
} -match glob \
122
123
124
125
126
127
128
129

130
131
132
133
134
135
136
128
129
130
131
132
133
134

135
136
137
138
139
140
141
142







-
+







    list [catch {load [file join $testDir pkga$ext] pkgb} msg] $msg
} [list 1 "file \"[file join $testDir pkga$ext]\" is already loaded for package \"Pkga\""]

test load-5.1 {file name not specified and no static package: pick default} \
	[list $dll $loaded] {
    catch {interp delete x}
    interp create x
    load [file join $testDir pkga$ext] pkga
    load -global [file join $testDir pkga$ext] pkga
    load {} pkga x
    set result [info loaded x]
    interp delete x
    set result
} [list [list [file join $testDir pkga$ext] Pkga]]

# On some platforms, like SunOS 4.1.3, these tests can't be run because

Changes to unix/tclLoadDl.c.

71
72
73
74
75
76
77

78
79
80
81
82
83
84
85
86
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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
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







+









-
+

+
+
+
+
+
+
+
+
+
+
-
+












-
+

-
+







				 * function which should be used for this
				 * file. */
    int flags)
{
    void *handle;
    Tcl_LoadHandle newHandle;
    const char *native;
    int dlopenflags = 0;

    /*
     * First try the full path the user gave us. This is particularly
     * important if the cwd is inside a vfs, and we are trying to load using a
     * relative path.
     */

    native = Tcl_FSGetNativePath(pathPtr);
    /*
     * Use (RTLD_NOW|RTLD_LOCAL) always, see [Bug #3216070]
     * Use (RTLD_NOW|RTLD_LOCAL) as default, see [Bug #3216070]
     */
    if (flags & TCL_LOAD_GLOBAL) {
    	dlopenflags |= RTLD_GLOBAL;
    } else {
    	dlopenflags |= RTLD_LOCAL;
    }
    if (flags & TCL_LOAD_LAZY) {
    	dlopenflags |= RTLD_LAZY;
    } else {
    	dlopenflags |= RTLD_NOW;
    }
    handle = dlopen(native, RTLD_NOW | RTLD_LOCAL);
    handle = dlopen(native, dlopenflags);
    if (handle == NULL) {
	/*
	 * Let the OS loader examine the binary search path for whatever
	 * string the user gave us which hopefully refers to a file on the
	 * binary path.
	 */

	Tcl_DString ds;
	const char *fileName = Tcl_GetString(pathPtr);

	native = Tcl_UtfToExternalDString(NULL, fileName, -1, &ds);
	/*
	 * Use (RTLD_NOW|RTLD_LOCAL) always, see [Bug #3216070]
	 * Use (RTLD_NOW|RTLD_LOCAL) as default, see [Bug #3216070]
	 */
	handle = dlopen(native, RTLD_NOW | RTLD_LOCAL);
	handle = dlopen(native, dlopenflags);
	Tcl_DStringFree(&ds);
    }

    if (handle == NULL) {
	/*
	 * Write the string to a variable first to work around a compiler bug
	 * in the Sun Forte 6 compiler. [Bug 1503729]
149
150
151
152
153
154
155
156

157
158
159
160
161
162
163
160
161
162
163
164
165
166

167
168
169
170
171
172
173
174







-
+







    Tcl_Interp *interp,		/* Place to put error messages. */
    Tcl_LoadHandle loadHandle,	/* Value from TcpDlopen(). */
    const char *symbol)		/* Symbol to look up. */
{
    const char *native;		/* Name of the library to be loaded, in
				 * system encoding */
    Tcl_DString newName, ds;	/* Buffers for converting the name to
				 * system encoding and prepending an 
				 * system encoding and prepending an
				 * underscore*/
    void *handle = (void *) loadHandle->clientData;
				/* Native handle to the loaded library */
    void *proc;			/* Address corresponding to the resolved
				 * symbol */

    /*

Changes to unix/tclLoadDyld.c.

166
167
168
169
170
171
172



173
174
175
176
177
178
179
180
181
182
183
184
185
186

187
188










189

190
191
192
193
194
195

196
197
198
199

200
201
202
203
204
205
206
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
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
213
214
215
216







+
+
+













-
+


+
+
+
+
+
+
+
+
+
+
-
+





-
+
-
-
-
-
+







    int errorNumber;
    const char *errorName, *objFileImageErrMsg = NULL;
#endif /* TCL_DYLD_USE_NSMODULE */
    const char *errMsg = NULL;
    int result;
    Tcl_DString ds;
    const char *nativePath, *nativeFileName = NULL;
#if TCL_DYLD_USE_DLFCN
    int dlopenflags = 0;
#endif /* TCL_DYLD_USE_DLFCN */

    /*
     * First try the full path the user gave us. This is particularly
     * important if the cwd is inside a vfs, and we are trying to load using a
     * relative path.
     */

    nativePath = Tcl_FSGetNativePath(pathPtr);
    nativeFileName = Tcl_UtfToExternalDString(NULL, Tcl_GetString(pathPtr),
	    -1, &ds);

#if TCL_DYLD_USE_DLFCN
    /*
     * Use (RTLD_NOW|RTLD_LOCAL) always, see [Bug #3216070]
     * Use (RTLD_NOW|RTLD_LOCAL) as default, see [Bug #3216070]
     */

    if (flags & TCL_LOAD_GLOBAL) {
    	dlopenflags |= RTLD_GLOBAL;
    } else {
    	dlopenflags |= RTLD_LOCAL;
    }
    if (flags & TCL_LOAD_LAZY) {
    	dlopenflags |= RTLD_LAZY;
    } else {
    	dlopenflags |= RTLD_NOW;
    }
    dlHandle = dlopen(nativePath, RTLD_NOW | RTLD_LOCAL);
    dlHandle = dlopen(nativePath, dlopenflags);
    if (!dlHandle) {
	/*
	 * Let the OS loader examine the binary search path for whatever string
	 * the user gave us which hopefully refers to a file on the binary
	 * path.
	 *

	 * Use (RTLD_NOW|RTLD_LOCAL) always, see [Bug #3216070]
	 */

	dlHandle = dlopen(nativeFileName, RTLD_NOW | RTLD_LOCAL);
	dlHandle = dlopen(nativeFileName, dlopenflags);
	if (!dlHandle) {
	    errMsg = dlerror();
	}
    }
#endif /* TCL_DYLD_USE_DLFCN */

    if (!dlHandle) {
234
235
236
237
238
239
240
241
242
243




244
245
246
247
248
249
250
244
245
246
247
248
249
250



251
252
253
254
255
256
257
258
259
260
261







-
-
-
+
+
+
+







		 * The requested file was found but was not of type MH_DYLIB,
		 * attempt to load it as a MH_BUNDLE.
		 */

		err = NSCreateObjectFileImageFromFile(nativePath,
			&dyldObjFileImage);
		if (err == NSObjectFileImageSuccess && dyldObjFileImage) {
		    module = NSLinkModule(dyldObjFileImage, nativePath,
			    NSLINKMODULE_OPTION_BINDNOW | NSLINKMODULE_OPTION_PRIVATE
			    | NSLINKMODULE_OPTION_RETURN_ON_ERROR);
		    int nsflags = NSLINKMODULE_OPTION_RETURN_ON_ERROR;
		    if (!(flags & 1)) nsflags |= NSLINKMODULE_OPTION_PRIVATE;
		    if (!(flags & 2)) nsflags |= NSLINKMODULE_OPTION_BINDNOW;
		    module = NSLinkModule(dyldObjFileImage, nativePath, nsflags);
		    NSDestroyObjectFileImage(dyldObjFileImage);
		    if (module) {
			modulePtr = ckalloc(sizeof(Tcl_DyldModuleHandle));
			modulePtr->module = module;
			modulePtr->nextPtr = NULL;
		    } else {
			NSLinkEditError(&editError, &errorNumber, &errorName,
561
562
563
564
565
566
567

568
569
570
571
572
573
574
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586







+







{
    Tcl_LoadHandle newHandle;
    Tcl_DyldLoadHandle *dyldLoadHandle;
    NSObjectFileImage dyldObjFileImage = NULL;
    Tcl_DyldModuleHandle *modulePtr;
    NSModule module;
    const char *objFileImageErrMsg = NULL;
    int nsflags = NSLINKMODULE_OPTION_RETURN_ON_ERROR;

    /*
     * Try to create an object file image that we can load from.
     */

    if (codeSize >= 0) {
	NSObjectFileImageReturnCode err = NSObjectFileImageSuccess;
655
656
657
658
659
660
661


662

663
664
665
666
667
668
669
670
671
667
668
669
670
671
672
673
674
675

676


677
678
679
680
681
682
683







+
+
-
+
-
-







	return TCL_ERROR;
    }

    /*
     * Extract the module we want from the image of the object file.
     */

    if (!(flags & 1)) nsflags |= NSLINKMODULE_OPTION_PRIVATE;
    if (!(flags & 2)) nsflags |= NSLINKMODULE_OPTION_BINDNOW;
    module = NSLinkModule(dyldObjFileImage, "[Memory Based Bundle]",
    module = NSLinkModule(dyldObjFileImage, "[Memory Based Bundle]", nsflags);
	    NSLINKMODULE_OPTION_BINDNOW | NSLINKMODULE_OPTION_PRIVATE
	    | NSLINKMODULE_OPTION_RETURN_ON_ERROR);
    NSDestroyObjectFileImage(dyldObjFileImage);
    if (!module) {
	NSLinkEditErrors editError;
	int errorNumber;
	const char *errorName, *errMsg;

	NSLinkEditError(&editError, &errorNumber, &errorName, &errMsg);