SCM Repository
Annotation of /sml/trunk/src/system/README
Parent Directory
|
Revision Log
Revision 573 - (view) (download)
1 : | blume | 537 | Compiler Hacker's Guide to the new CM... |
2 : | ======================================== | ||
3 : | monnier | 416 | |
4 : | blume | 573 | Last change: 3/2000 |
5 : | blume | 537 | |
6 : | monnier | 416 | * Libraries |
7 : | ----------- | ||
8 : | |||
9 : | The new way of building the compiler is heavily library-oriented. | ||
10 : | Aside from a tiny portion of code that is responsible for defining the | ||
11 : | pervasive environment, _everything_ lives in libraries. Building the | ||
12 : | compiler means compiling and stabilizing these libraries first. Some | ||
13 : | of the libraries exist just for reasons of organizing the code, the | ||
14 : | other ones are potentially useful in their own right. Therefore, as a | ||
15 : | beneficial side-effect of compiling the compiler, you will end up with | ||
16 : | stable versions of these libraries. | ||
17 : | |||
18 : | At the moment, the following libraries are constructed when compiling | ||
19 : | the compiler ("*" means that I consider the library potentially useful | ||
20 : | in its own right): | ||
21 : | |||
22 : | blume | 573 | * basis.cm SML'97 Basis Library (pre-loaded) |
23 : | * smlnj-lib.cm SML/NJ Utility Library | ||
24 : | * html-lib.cm SML/NJ HTML Library | ||
25 : | * pp-lib.cm SML/NJ Pretty-print Library | ||
26 : | monnier | 416 | |
27 : | blume | 573 | * ml-yacc-lib.cm SML/NJ ML-Yacc runtime library |
28 : | |||
29 : | * smlnj/compiler/{alpha32,hppa,ppc,sparc,x86}.cm | ||
30 : | cross-compiler libraries, exporting | ||
31 : | structure <Arch>Compiler | ||
32 : | * smlnj/compiler/current.cm structure Compiler (current arch) | ||
33 : | * smlnj/compiler/all.cm all cross-compilers and all cross-CMBs | ||
34 : | |||
35 : | * smlnj/cm/minimal.cm minimal CM (pre-loaded) | ||
36 : | * smlnj/cm/full.cm full structure CM (see manual) | ||
37 : | * smlnj/cm/tools.cm CM tools library | ||
38 : | |||
39 : | * smlnj/cmb/{alpha32,hppa,ppc,sparc,x86}-unix.cm | ||
40 : | cross-bootstrap-compilers for Unix | ||
41 : | (structure <Arch>UnixCMB) | ||
42 : | * smlnj/cmb/ppc-macos.cm ...for Mac (structure PPCMacosCMB) | ||
43 : | * smlnj/cmb/x86-win32.cm ...for Windoze (structure X86Win32CMB) | ||
44 : | * smlnj/cmb/current.cm structure CMB (current arch/os) | ||
45 : | |||
46 : | * smlnj/compiler.cm abbrev. for smlnj/compiler/current.cm | ||
47 : | * smlnj/cm.cm abbrev. for smlnj/cm/full.cm | ||
48 : | * smlnj/cmb.cm abbrev. for smlnj/cmb/current.cm | ||
49 : | |||
50 : | * comp-lib.cm Utility library for compiler | ||
51 : | |||
52 : | - smlnj/viscomp/core.cm Compiler core functionality | ||
53 : | - smlnj/viscomp/{alpha32,hppa,ppc,sparc,x86}.cm | ||
54 : | Machine-specific parts of compiler | ||
55 : | |||
56 : | - smlnj/internal/{intsys,cm-lib,cm-hook,host-compiler-0}.cm | ||
57 : | Glue that holds the interactive system | ||
58 : | together | ||
59 : | |||
60 : | * MLRISC/{MLRISC,Control,Lib,ALPHA,HPPA,PPC,SPARC,IA32}.cm | ||
61 : | Various MLRISC bits | ||
62 : | |||
63 : | * {mlyacc,mllex,mlburg}-tool.cm CM plug-in libraries for common tools | ||
64 : | * {grm,lex,burg}-ext.cm CM plug-in libraries for common file | ||
65 : | extensions | ||
66 : | |||
67 : | monnier | 416 | * Before you can use the bootstrap compiler (CMB)... |
68 : | ---------------------------------------------------- | ||
69 : | |||
70 : | To be able to use CMB at all, you must first say | ||
71 : | |||
72 : | blume | 573 | CM.autoload "smlnj/cmb.cm"; |
73 : | monnier | 416 | |
74 : | blume | 569 | after you start sml. Alternatively -- and perhaps more conveniently -- |
75 : | you can provide "host-cmb.cm" as a command-line argument to sml: | ||
76 : | monnier | 416 | |
77 : | blume | 573 | $ sml smlnj/cmb.cm |
78 : | monnier | 416 | |
79 : | blume | 569 | * Compiling the compiler |
80 : | ------------------------ | ||
81 : | monnier | 416 | |
82 : | blume | 569 | We are now back to the old scheme where a call to CMB.make() suffices to |
83 : | build a bootable set of files (libraries in our case). CMB.make maintains | ||
84 : | two parallel hierarchies of derived files: | ||
85 : | monnier | 416 | |
86 : | blume | 569 | 1. the binfile hierarchy ("binfiles"), containing compiled objects for |
87 : | each individual ML source file; this hierarchy is rooted at | ||
88 : | <prefix>.bin.<arch>-<opsys> | ||
89 : | 2. the stable library hierarchy ("boot files"), containing library files | ||
90 : | for each library that participates in building SML/NJ; this hierarchy | ||
91 : | is rooted at | ||
92 : | <prefix>.boot.<arch>-<opsys> | ||
93 : | monnier | 416 | |
94 : | blume | 569 | The default for <prefix> is "sml". It can be changed by using |
95 : | CMB.make' with the new <prefix> as the optional string argument. | ||
96 : | monnier | 416 | |
97 : | blume | 569 | CMB.make uses bootfiles after it has verified that they are consistent |
98 : | with their corresponding binfiles. Bootfiles do not need to be | ||
99 : | deleted in order for CMB.make to work correctly. | ||
100 : | monnier | 416 | |
101 : | blume | 569 | To bootstrap a new system (using the runtime system boot loader), the |
102 : | bootfiles _must_ be present, the binfiles need not be present (but | ||
103 : | their presence does not hurt either). | ||
104 : | monnier | 416 | |
105 : | monnier | 498 | You can reduce the number of extra files compiled and stabilized |
106 : | blume | 569 | during CMB.make at the expense of not building any cross-compilers. |
107 : | monnier | 498 | For that, say |
108 : | #set (CMB.symval "LIGHT") (SOME 1); | ||
109 : | blume | 569 | before running CMB.make. |
110 : | monnier | 498 | |
111 : | monnier | 416 | * Making the heap image |
112 : | ----------------------- | ||
113 : | |||
114 : | The heap image is made by running the "makeml" script that you find | ||
115 : | here in this directory. By default it will try to refer to the | ||
116 : | monnier | 498 | sml.boot.<arch>-<os> directory. You can change this using the -boot |
117 : | monnier | 416 | argument (which takes the full name of the boot directory to be used). |
118 : | |||
119 : | The "feel" of using makeml should be mostly as it used to. However, | ||
120 : | internally, there are some changes that you should be aware of: | ||
121 : | |||
122 : | blume | 569 | 1. The script will make a heap image and build a separate library directory |
123 : | that contains links to the library files in the bootfile directory. | ||
124 : | monnier | 416 | |
125 : | 2. There is no "-full" option anymore. This functionality should | ||
126 : | eventually be provided by a library with a sufficiently rich export | ||
127 : | interface. | ||
128 : | |||
129 : | 3. No image will be generated if you use the -rebuild option. | ||
130 : | Instead, the script quits after making new bin and new boot | ||
131 : | directories. You must re-invoke makeml with a suitable "-boot" | ||
132 : | option to actually make the image. The argument to "-rebuild" | ||
133 : | is the <prefix> for the new bin and boot directories (see above). | ||
134 : | |||
135 : | blume | 569 | Makeml will not destroy the bootfile directory. |
136 : | monnier | 416 | |
137 : | * Testing a newly generated heap image | ||
138 : | -------------------------------------- | ||
139 : | |||
140 : | If you use a new heap image by saying "sml @SMLload=..." then things | ||
141 : | will not go as you may expect because along with the new heap image | ||
142 : | should go those new stable libraries, but unless you do something | ||
143 : | blume | 569 | about it, the newly booted system will look for its stable libraries |
144 : | in places where you stored your _old_ stable libraries. | ||
145 : | monnier | 416 | |
146 : | After you have made the new heap image, the new libraries are in a | ||
147 : | separate directory whose name is derived from the name of the heap | ||
148 : | blume | 569 | image. (Actually, only the directory hierachy is separate, the |
149 : | library files themselves are hard links.) The "testml" script that you | ||
150 : | also find here will run the heap image and instruct it to look for its | ||
151 : | libraries in that new library directory. | ||
152 : | monnier | 416 | |
153 : | monnier | 498 | "testml" takes the <prefix> of the heap image as its first |
154 : | argument. All other arguments are passed verbatim to the ML process. | ||
155 : | |||
156 : | The <prefix> is the same as the one used when you did "makeml". If | ||
157 : | you run "testml" without arguments, <prefix> defaults to "sml". | ||
158 : | Thus, if you just said "makeml" without argument you can also say | ||
159 : | "testml" without argument. (Note that you _must_ supply the <prefix> | ||
160 : | argument if you intend to pass any additional arguments.) | ||
161 : | |||
162 : | monnier | 416 | * Installing a heap image for more permanent use |
163 : | ------------------------------------------------ | ||
164 : | |||
165 : | monnier | 498 | You can "install" a newly generated heap image by replacing the old |
166 : | image with the new one _AND AT THE SAME TIME_ replacing the old stable | ||
167 : | libaries with the new ones. To do this, run the "installml" script. | ||
168 : | monnier | 416 | |
169 : | monnier | 498 | Like "testml", "installml" also expects the <prefix> as its first |
170 : | argument. <prefix> defaults to "sml" if no argument is specified. | ||
171 : | |||
172 : | "installml" patches the ../../lib/pathconfig file to reflect any | ||
173 : | changes or additions to the path name mapping. | ||
174 : | |||
175 : | blume | 569 | Thus, after a successful CMB.make, you should say |
176 : | monnier | 498 | |
177 : | ./makeml | ||
178 : | |||
179 : | to make the new heap image + libraries, then | ||
180 : | |||
181 : | ./testml | ||
182 : | |||
183 : | to make sure everything works, and finally | ||
184 : | |||
185 : | ./installml | ||
186 : | |||
187 : | to replace your existing compiler with the one you just built and tested. | ||
188 : | |||
189 : | monnier | 416 | * Cross-compiling |
190 : | ----------------- | ||
191 : | |||
192 : | blume | 573 | All cross-compilers live in the "smlnj/compiler/all.cm" library. You |
193 : | monnier | 416 | must first say |
194 : | |||
195 : | blume | 573 | CM.autoload "smlnj/compiler/all.cm"; |
196 : | monnier | 416 | |
197 : | before you can access them. (This step corresponds to the old | ||
198 : | CMB.retarget call.) After that, _all_ cross-compilers are available | ||
199 : | at the same time. However, the ones that you are not using don't take | ||
200 : | up any undue space because they only get loaded once you actually | ||
201 : | mention them at the top-level. The names of the structures currently | ||
202 : | exported by target-compilers.cm are: | ||
203 : | |||
204 : | structure Alpha32UnixCMB | ||
205 : | structure HppaUnixCMB | ||
206 : | structure PPCMacOSCMB | ||
207 : | structure PPCUnixCMB | ||
208 : | structure SparcUnixCMB | ||
209 : | structure X86UnixCMB | ||
210 : | structure X86Win32CMB | ||
211 : | |||
212 : | structure Alpha32Compiler | ||
213 : | structure HppaCompiler | ||
214 : | structure PPCCompiler | ||
215 : | structure SparcCompiler | ||
216 : | structure X86Compiler | ||
217 : | |||
218 : | (PPCMacOSCMB is not very useful at the moment because there is no | ||
219 : | implementation of the basis library for the MacOS.) | ||
220 : | |||
221 : | monnier | 498 | Alternatively, you can select just the one single structure that you |
222 : | blume | 573 | are interested in by auto-loading smlnj/compiler/<arch>.cm or |
223 : | smlnj/cmb/<arch>-<os>.cm. | ||
224 : | monnier | 498 | <arch> currently ranges over "alpha32", "hppa", "ppc", "sparc", and "x86. |
225 : | <os> can be either "unix" or "macos" or "win32". | ||
226 : | (Obviously, not all combinations are valid.) | ||
227 : | |||
228 : | blume | 573 | Again, as with smlnj/cmb.cm, you can specify the .cm file as an |
229 : | blume | 569 | argument to the sml command: |
230 : | |||
231 : | blume | 573 | $ sml smlnj/compiler/all.cm |
232 : | blume | 569 | |
233 : | or | ||
234 : | |||
235 : | blume | 573 | $ sml smlnj/cmb/alpha32-unix.cm |
236 : | blume | 569 | |
237 : | monnier | 416 | * Path configuration |
238 : | -------------------- | ||
239 : | |||
240 : | + Basics: | ||
241 : | |||
242 : | One of the new features of CM is its handling of path names. In the | ||
243 : | old CM, one particular point of trouble was the autoloader. It | ||
244 : | analyzes a group or library and remembers the locations of associated | ||
245 : | files. Later, when the necessity arises, those files will be read. | ||
246 : | Therefore, one was asking for trouble if the current working directory | ||
247 : | was changed between analysis- and load-time, or, worse, if files | ||
248 : | actually moved about (as is often the case if build- and | ||
249 : | installation-directories are different, or, to put it more generally, | ||
250 : | if CM's state is frozen into a heap image and used in a different | ||
251 : | environment). | ||
252 : | |||
253 : | Maybe it would have been possible to work around most of these | ||
254 : | problems by fixing the path-lookup mechanism in the old CM and using | ||
255 : | it extensively. But path-lookup (as in the Unix-shell's "PATH") is | ||
256 : | inherently dangerous because one can never be too sure what it will be | ||
257 : | that is found on the path. A new file in one of the directories early | ||
258 : | in the path can upset the program that hopes to find something under | ||
259 : | the same name later on the path. Even when ignoring security-issues | ||
260 : | like trojan horses and such, this definitely opens the door for | ||
261 : | monnier | 498 | various unpleasant surprises. (Who has never named a test version |
262 : | monnier | 416 | of a program "test" an found that it acts strangely only to discover |
263 : | later that /bin/test was run instead?) | ||
264 : | |||
265 : | Thus, the new scheme used by CM is a fixed mapping of what I call | ||
266 : | "configuration anchors" to corresponding directories. The mapping can | ||
267 : | be changed, but one must do so explicitly. In effect, it does not | ||
268 : | depend on the contents of the file system. Here is how it works: | ||
269 : | |||
270 : | If I specify a relative pathname in one of CM's description files | ||
271 : | where the first component (the first arc) of that pathname is known to | ||
272 : | CM as a configuration anchor, then the corresponding directory | ||
273 : | (according to CM's mapping) is prepended to the path. Suppose the | ||
274 : | path name is "a/foo.sml" and "a" is a known anchor that maps to | ||
275 : | "/usr/lib/smlnj", then the resulting complete pathname is | ||
276 : | "/usr/lib/smlnj/a/foo.sml". The pathname can be a single arc (but | ||
277 : | does not have to be). For example, the anchor "basis.cm" is typically | ||
278 : | mapped to the directory where the basis library is stored. | ||
279 : | |||
280 : | Now, the important point is that one can change the mapping of the | ||
281 : | anchor, and the path name will also change accordingly -- even very | ||
282 : | late in the game. CM avoids "elaborating" path names until it really | ||
283 : | needs them when it is time to open files. CM is also willing to | ||
284 : | re-elaborate the same names if there is reason to do so. Thus, the | ||
285 : | "basis.cm" library that was analyzed "here" but then moved "there" | ||
286 : | will also be found "there" if the anchor has been re-set accordingly. | ||
287 : | |||
288 : | + Different configurations at different times: | ||
289 : | |||
290 : | During compilation of the compiler, CMB uses a path configuration that | ||
291 : | is read from the file "pathconfig" located here in this directory. | ||
292 : | |||
293 : | At bootstrap time, the same anchors are mapped to the corresponding | ||
294 : | sub-directory of the "boot" directory: basis.cm is mapped to | ||
295 : | monnier | 498 | sml.boot.<arch>-<os>/basis.cm -- which means that CM will look for a |
296 : | library named sml.boot.<arch>-<os>/basis.cm/basis.cm -- and so forth. | ||
297 : | monnier | 416 | |
298 : | By the way, you will perhaps notice that there is no file | ||
299 : | monnier | 498 | sml.boot.<arch>-<os>/basis.cm/basis.cm |
300 : | monnier | 416 | but there _is_ the corresponding stable archive |
301 : | monnier | 498 | sml.boot.<arch>-<os>/basis.cm/CM/<arch>-<os>/basis.cm |
302 : | monnier | 416 | CM always looks for stable archives first. |
303 : | |||
304 : | This mapping (from anchors to names in the boot directory) is the one | ||
305 : | that will get frozen into the generated heap image at boot time. | ||
306 : | Thus, unless it is changed, CM will look for its libraries in the boot | ||
307 : | monnier | 429 | directory. The aforementioned "testml" script will make sure that |
308 : | monnier | 416 | the mapping is changed to the one specified in a new "pathconfig" file |
309 : | which was created by makeml and placed into the test library | ||
310 : | directory. It points all anchors to the corresponding entry in the | ||
311 : | monnier | 429 | test library directory. Thus, "testml" will let a new heap image run |
312 : | monnier | 416 | with its corresponding new libraries. |
313 : | |||
314 : | Normally, however, CM consults other pathconfig files at startup -- | ||
315 : | files that live in standard locations. These files are used to modify | ||
316 : | the path configuration to let anchors point to their "usual" places. | ||
317 : | The names of the files that are read (if present) are configurable via | ||
318 : | environment variables. At the moment they default to | ||
319 : | /usr/lib/smlnj-pathconfig | ||
320 : | and | ||
321 : | $HOME/.smlnj-pathconfig | ||
322 : | The first one is configurable via CM_PATHCONFIG (and the default is | ||
323 : | configurable at boot time via CM_PATHCONFIG_DEFAULT); the last is | ||
324 : | configurable via CM_LOCAL_PATHCONFIG and CM_LOCAL_PATHCONFIG_DEFAULT. | ||
325 : | In fact, the makeml script sets the CM_PATHCONFIG_DEFAULT variable | ||
326 : | before making the heap image. Therefore, heap images generated by | ||
327 : | makeml will look for their global pathconfig file in | ||
328 : | |||
329 : | monnier | 429 | `pwd`/../../lib/pathconfig |
330 : | monnier | 416 | |
331 : | monnier | 429 | For example, I always keep my "good" libraries in `pwd`/../../lib -- |
332 : | where both the main "install" script and the "installml" script (see | ||
333 : | monnier | 498 | above) also put them -- so I don't have to do anything special about |
334 : | monnier | 429 | my pathconfig file. |
335 : | monnier | 416 | |
336 : | Once I have new heap image and libraries working, I replace the old | ||
337 : | "good" image with the new one: | ||
338 : | |||
339 : | mv <image>.<arch>-<osvariant> ../../bin/.heap/sml.<arch>-<osvariant> | ||
340 : | |||
341 : | blume | 573 | After this you must also move all libraries from <image>.libs/* to their |
342 : | corresponding position in ../../lib. | ||
343 : | monnier | 416 | |
344 : | blume | 573 | Since this is cumbersome to do by hand, there is a script called |
345 : | "installml" that automates this task. Using the script has the added | ||
346 : | advantage that it will not clobber libraries that belong to other than | ||
347 : | the current architecture. (A rather heavy-handed "rm/mv" approach | ||
348 : | will delete all stable libraries for all architectures.) | ||
349 : | "installml" also patches the ../../lib/pathconfig file as necessary. | ||
350 : | monnier | 416 | |
351 : | Of course, you can organize things differently for yourself -- the | ||
352 : | path configuration mechanism should be sufficiently flexible. | ||
353 : | |||
354 : | * Libraries vs. Groups | ||
355 : | ---------------------- | ||
356 : | |||
357 : | With the old CM, "group" was the primary concept while "library" and | ||
358 : | "stabilization" could be considered afterthoughts. This has changed. | ||
359 : | Now "library" is the primary concept, "stabilization" is semantically | ||
360 : | significant, and "groups" are a secondary mechanism. | ||
361 : | |||
362 : | Libraries are used to "structure the world"; groups are used to give | ||
363 : | structure to libraries. Each group can be used either in precisely | ||
364 : | one library (in which case it cannot be used at the interactive | ||
365 : | toplevel) or at the toplevel (in which case it cannot be used in any | ||
366 : | library). In other words, if you count the toplevel as a library, | ||
367 : | then each group has a unique "owner" library. Of course, there still | ||
368 : | is no limit on how many times a group can be mentioned as a member of | ||
369 : | other groups -- as long as all these other groups belong to the same | ||
370 : | owner library. | ||
371 : | |||
372 : | If you want to take a collection of files whose purpose fits that of a | ||
373 : | library, then, please, make them into a library (i.e., not a group!). | ||
374 : | The purpose of groups is to deal with name-space issues _within_ | ||
375 : | libraries. | ||
376 : | |||
377 : | Aside from the fact that I find this design quite natural, there is | ||
378 : | actually a technical reason for it: when you stabilize a library | ||
379 : | (groups cannot be stabilized), then all its sub-groups (not | ||
380 : | sub-libraries!) get "sucked into" the stable archive of the library. | ||
381 : | In other words, even if you have n+1 CM description files (1 for the | ||
382 : | library, n for n sub-groups), there will be just one file representing | ||
383 : | the one stable archive (per architecture/os) for the whole thing. For | ||
384 : | example, I structured the standard basis into one library with two | ||
385 : | blume | 569 | sub-groups, but once you compile it (CMB.make) there is only one |
386 : | monnier | 416 | stable file that represents the whole basis library. If groups were |
387 : | allowed to appear in more than one library, then stabilization would | ||
388 : | duplicate the group (its code, its environment data structures, and | ||
389 : | even its dynamic state). | ||
390 : | |||
391 : | There is a small change to the syntax of group description files: they | ||
392 : | must explicitly state which library they belong to. CM will verify | ||
393 : | that. The owner library is specified in parentheses after the "group" | ||
394 : | keyword. If the specification is missing (that's the "old" syntax), | ||
395 : | then the the owner will be taken to be the interactive toplevel. | ||
396 : | |||
397 : | blume | 537 | * Pervasive environment, core environment, the init group "init.cmi" |
398 : | monnier | 416 | ------------------------------------------------------------------------- |
399 : | |||
400 : | blume | 569 | CMB.make starts out by building and compiling the |
401 : | blume | 537 | "init group". This group cannot be described in the "usual" way |
402 : | because it uses "magic" in three ways: | ||
403 : | - it is used to later tie in the runtime system | ||
404 : | blume | 569 | - it exports the "core" environment |
405 : | - it exports the "pervasive" environment | ||
406 : | monnier | 416 | |
407 : | blume | 537 | The pervasive environment no longer includes the entire basis library |
408 : | but only non-modular bindings (top-level bindings of variables and | ||
409 : | types). | ||
410 : | |||
411 : | blume | 569 | CM cannot automatically determine dependencies (or exports) for the |
412 : | init group source files, but it still does use its regular cutoff | ||
413 : | recompilation mechanism. Therefore, dependencies must be given | ||
414 : | explicitly. This is done by a special description file which | ||
415 : | blume | 573 | currently lives in ../system/smlnj/init/init.cmi. See the long comment |
416 : | at the beginning of that file for more details. | ||
417 : | monnier | 416 | |
418 : | blume | 573 | After it is built, smlnj/init/init.cmi can be used as an "ordinary" library |
419 : | by other libraries. (This is done, for example, by the implementation of | ||
420 : | the Basis library.) Access to "smlnj/init/init.cmi" is protected by the | ||
421 : | blume | 569 | privilege named "primitive". Also, note that the .cmi-file is not |
422 : | automatically recognized as as CM description file. Therefore, it | ||
423 : | must be given an explicit member class: | ||
424 : | blume | 537 | |
425 : | blume | 573 | smlnj/init/init.cmi : cm |
426 : | blume | 569 | |
427 : | monnier | 416 | * Autoloader |
428 : | ------------ | ||
429 : | |||
430 : | The new system heavily relies on the autoloader. As a result, almost | ||
431 : | blume | 569 | no static environments need to get unpickled at bootstrap time. The |
432 : | monnier | 416 | construction of such environments is deferred until they become |
433 : | blume | 569 | necessary. Thanks of this, it was possible to reduce the size of the |
434 : | heap image by more than one megabyte (depending on the architecture). | ||
435 : | The downside (although not really terribly bad) is that there is a | ||
436 : | short wait when you first touch an identifier that hasn't been touched | ||
437 : | monnier | 416 | before. (I acknowledge that the notion of "short" may depend on your |
438 : | sense of urgency. :-) | ||
439 : | |||
440 : | The reliance on the autoloader (and therefore CM's library mechanism) | ||
441 : | means that in order to be able to use the system, your paths must be | ||
442 : | properly configured. | ||
443 : | |||
444 : | Two libraries get pre-registered at bootstap time: the basis library | ||
445 : | monnier | 498 | ("basis.cm") and CM itself ("minimal-cm.cm"). The latter is crucial: |
446 : | monnier | 416 | without it one wouldn't be able to register any other libraries |
447 : | via CM.autoload. The registration of basis.cm is a mere convenience. | ||
448 : | |||
449 : | Here are some other useful libraries that are not pre-registered but | ||
450 : | which can easily be made accessible via CM.autoload (or, non-lazily, | ||
451 : | via CM.make): | ||
452 : | |||
453 : | blume | 573 | smlnj/cm.cm - provides the actual ("full") structure CM |
454 : | monnier | 498 | as described in the CM manual |
455 : | blume | 573 | smlnj/cm/full.cm - same as smlnj/cm.cm |
456 : | smlnj/compiler.cm - provides "structure Compiler" | ||
457 : | smlnj/compiler/current.cm - same as smlnj/compiler.cm | ||
458 : | smlnj/cmb.cm - provides "structure CMB" | ||
459 : | smlnj/cmb/current.cm - same as smlnj/cmb.cm | ||
460 : | smlnj/compiler/all.cm - provides "structure <Arch>Compiler" and | ||
461 : | monnier | 416 | "structure <Arch><OS>CMB" for various |
462 : | values of <Arch> and <OS> | ||
463 : | smlnj-lib.cm - the SML/NJ library | ||
464 : | |||
465 : | * Internal sharing | ||
466 : | ------------------ | ||
467 : | |||
468 : | Dynamic values of loaded modules are shared. This is true even for | ||
469 : | those modules that are used by the interactive compiler itself. If | ||
470 : | you load a module from a library that is also used by the interactive | ||
471 : | compiler, then "loading" means "loading the static environmnent" -- it | ||
472 : | does not mean "loading the code and linking it". Instead, you get to | ||
473 : | share the compiler's dynamic values (and therefore the executable | ||
474 : | code as well). | ||
475 : | |||
476 : | Of course, if you load a module that hasn't been loaded before and | ||
477 : | also isn't used by the interactive system, then CM will get the code | ||
478 : | and link (execute) it. | ||
479 : | |||
480 : | * Access control | ||
481 : | ---------------- | ||
482 : | |||
483 : | In some places, you will find that the "group" and "library" keywords | ||
484 : | in description files are preceeded by certain strings, sometimes in | ||
485 : | parentheses. These strings are the names of "privileges". Don't | ||
486 : | worry about them too much at the moment. For the time being, access | ||
487 : | control is not enforced, but the infrastructure is in place. | ||
488 : | |||
489 : | * Preprocessor | ||
490 : | -------------- | ||
491 : | |||
492 : | The syntax of expressions in #if and #elif clauses is now more ML-ish | ||
493 : | instead of C-ish. (Hey, this is ML after all!) In particular, you | ||
494 : | must use "andalso", "orelse", and "not" instead of "&&", "||" and "!". | ||
495 : | Unary minus is "~". | ||
496 : | |||
497 : | A more interesting change is that you can now query the exports of | ||
498 : | sources/subgroups/sublibraries: | ||
499 : | |||
500 : | - Within the "members" section of the description (i.e., after "is"): | ||
501 : | The expression | ||
502 : | defined(<namespace> <name>) | ||
503 : | is true if any of the included members preceeding this clause exports | ||
504 : | a symbol "<namespace> <name>". | ||
505 : | - Within the "exports" section of the description (i.e., before "is): | ||
506 : | The same expression is true if _any_ of the members exports the | ||
507 : | named symbol. | ||
508 : | (It would be more logical if the exports section would follow the | ||
509 : | members section, but for esthetic reasons I prefer the exports | ||
510 : | section to come first.) | ||
511 : | |||
512 : | Example: | ||
513 : | |||
514 : | +--------------------------+ | ||
515 : | |Library | | ||
516 : | | structure Foo | | ||
517 : | |#if defined(structure Bar)| | ||
518 : | | structure Bar | | ||
519 : | |#endif | | ||
520 : | |is | | ||
521 : | |#if SMLNJ_VERSION > 110 | | ||
522 : | | new-foo.sml | | ||
523 : | |#else | | ||
524 : | | old-foo.sml | | ||
525 : | |#endif | | ||
526 : | |#if defined(structure Bar)| | ||
527 : | | bar-client.sml | | ||
528 : | |#else | | ||
529 : | | no-bar-so-far.sml | | ||
530 : | |#endif | | ||
531 : | +--------------------------+ | ||
532 : | |||
533 : | Here, the file "bar-client.sml" gets included if SMLNJ_VERSION is | ||
534 : | greater than 110 and new-foo.sml exports a structure Bar _or_ if | ||
535 : | SMLNJ_VERSION <= 110 and old-foo.sml exports structure Bar. Otherwise | ||
536 : | "no-bar-so-far.sml" gets included instead. In addition, the export of | ||
537 : | structure Bar is guarded by its own existence. (Structure Bar could | ||
538 : | also be defined by "no-bar-so-far.sml" in which case it would get | ||
539 : | exported regardless of the outcome of the other "defined" test.) | ||
540 : | |||
541 : | Some things to note: | ||
542 : | |||
543 : | - For the purpose of the pre-processor, order among members is | ||
544 : | significant. (For the purpose of dependency analysis, order continues | ||
545 : | to be not significant). | ||
546 : | - As a consequence, in some cases pre-processor dependencies and | ||
547 : | compilation-dependencies may end up to be opposites of each other. | ||
548 : | (This is not a problem; it may very well be a feature.) | ||
549 : | |||
550 : | * The Basis Library is no longer built-in | ||
551 : | ----------------------------------------- | ||
552 : | |||
553 : | The SML'97 basis is no longer built-in. If you want to use it, you | ||
554 : | must specify "basis.cm" as a member of your group/library. | ||
555 : | |||
556 : | * No more aliases | ||
557 : | ----------------- | ||
558 : | |||
559 : | The "alias" feature is no longer with us. At first I thought I could | ||
560 : | keep it, but it turns out that it causes some fairly fundamental | ||
561 : | problems with the autoloader. However, I don't think that this is a | ||
562 : | big loss because path anchors make up for most of it. Moreover, | ||
563 : | stable libraries can now easily be moved to convenient locations | ||
564 : | without having to move large source trees at the same time. (See my | ||
565 : | new build/install.sh script for examples of that.) | ||
566 : | |||
567 : | blume | 573 | It is possible to simulate aliases (in a way that is safer than the |
568 : | original alias mechanism). For example, the root.cm file (which is the | ||
569 : | root of the whole system as far as CMB.make is concerned) acts as an | ||
570 : | alias for smlnj/internal/intsys.cm. In this case, root.cm is a group | ||
571 : | to avoid having a (trivial) stable library file built for it. | ||
572 : | |||
573 : | A library can act as an "alias" for another library if it has a | ||
574 : | verbatim copy of the export list and mentions the other library as its | ||
575 : | only member. Examples for this are smlnj/cm.cm (for smlnj/cm/full.cm), | ||
576 : | smlnj/compiler.cm (for smlnj/compiler/current.cm), etc. | ||
577 : | |||
578 : | monnier | 416 | * Don't use relative or absolute pathnames to refer to libraries |
579 : | ---------------------------------------------------------------- | ||
580 : | |||
581 : | Don't use relative or absolute pathnames to refer to libraries. If | ||
582 : | you do it anyway, you'll get an appropriate warning at the time when | ||
583 : | blume | 569 | you do CMB.make(). If you use relative or absolute pathnames to |
584 : | monnier | 416 | refer to library B from library A, you will be committed to keeping B |
585 : | in the same relative (to A) or absolute location. This, clearly, | ||
586 : | would be undesirable. |
root@smlnj-gforge.cs.uchicago.edu | ViewVC Help |
Powered by ViewVC 1.0.0 |