Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download

build open-axiom

54510 views
1
;; O Emacs, this is a -*- Lisp -*- file, despite appearance
2
;;
3
;; Copyright (c) 1991-2002, The Numerical Algorithms Group Ltd.
4
;; All rights reserved.
5
;;
6
;; Copyright (C) 2007-2015, Gabriel Dos Reis.
7
;; All rights reserved.
8
;;
9
;; Redistribution and use in source and binary forms, with or without
10
;; modification, are permitted provided that the following conditions are
11
;; met:
12
;;
13
;; - Redistributions of source code must retain the above copyright
14
;; notice, this list of conditions and the following disclaimer.
15
;;
16
;; - Redistributions in binary form must reproduce the above copyright
17
;; notice, this list of conditions and the following disclaimer in
18
;; the documentation and/or other materials provided with the
19
;; distribution.
20
;;
21
;; - Neither the name of The Numerical Algorithms Group Ltd. nor the
22
;; names of its contributors may be used to endorse or promote products
23
;; derived from this software without specific prior written permission.
24
;;
25
;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
26
;; IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27
;; TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
28
;; PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
29
;; OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30
;; EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31
;; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32
;; PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33
;; LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34
;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35
;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36
37
38
;;
39
;; -*- Abstract -*-
40
;;
41
;; This file defines the core of the system utilities for building
42
;; Boot and OpenAxiom executable. It essentially etablishes a namespace
43
;; (package AxiomCore) and defines some macros and functions
44
;; that need to be present during compilation and executable
45
;; image construction.
46
;;
47
48
(defpackage "AxiomCore"
49
#+:common-lisp (:use "COMMON-LISP")
50
#-:common-lisp (:use "LISP" "USER")
51
#+(and :SBCL :SB-THREAD) (:use "SB-THREAD")
52
#+(and :ECL :THREADS) (:use "MP")
53
#+(and :CLISP :MT) (:use "THREADS")
54
;; For GCL we need to explicitly use the DEFPACKAGE, otherwise the
55
;; image obtained from compiler link will not work. The root cause
56
;; is a non-ANSI compliant organization of GCL's implementation.
57
#+:gcl (:use "DEFPACKAGE")
58
;; Clozure CL sequesters most of its useful extensions, in particular
59
;; threads, in the CCL package.
60
;; #+:clozure (:use "CCL")
61
#+:clozure (:import-from "CCL"
62
external-call %get-cstring
63
with-pointer-to-ivector with-cstrs)
64
#+:clozure (:export "CCL"
65
external-call %get-cstring
66
with-pointer-to-ivector with-cstrs)
67
68
(:export "%Thing"
69
"%Void"
70
"%Boolean"
71
"%String"
72
"%Symbol"
73
"%Short"
74
"%Bit"
75
"%Byte"
76
"%Char"
77
"%Bignum"
78
"%Integer"
79
"%Number"
80
"%IntegerSection"
81
"%DoubleFloat"
82
"%Atom"
83
"%Maybe"
84
"%Pair"
85
"%Node"
86
"%List"
87
"%Vector"
88
"%BitVector"
89
"%SimpleArray"
90
"%Table"
91
92
;; Some common data structures
93
"makeTable" ; construct a hash table with a given comp function
94
"tableValue" ; value associated with a key in a table
95
"tableLength" ; number of entries in the table.
96
"tableRemove!" ; remove an entry from a table
97
"ref"
98
"deref"
99
100
;; IO
101
"$stdin"
102
"$stdout"
103
"$stdio"
104
"$InputStream"
105
"$OutputStream"
106
"$ErrorStream"
107
108
"directoryEntries"
109
"inputBinaryFile"
110
"outputBinaryFile"
111
"inputTextFile"
112
"outputTextFile"
113
"closeFile"
114
"closeStream"
115
"eof?"
116
"getFileCursor"
117
"setFileCursor"
118
"forkStreamByName"
119
"prettyPrint"
120
"readLine"
121
"readExpr"
122
"readIntegerIfCan"
123
"formatToString"
124
"formatToStream"
125
"formatToStdout"
126
127
;; compiler data structures
128
"%Mode"
129
"%Sig"
130
"%Code"
131
"%Env"
132
"%Form"
133
"%Triple"
134
"%Shell"
135
;; functor data structures
136
"%FunctorData"
137
"%FunctorCoreData"
138
"%FunctorBytecode"
139
"%FunctorTemplate"
140
"%FunctorPredicateIndexTable"
141
"%FunctorOperatorDirectory"
142
"%FunctorCategoryTable"
143
"%FunctorAttributeTable"
144
"%FunctorDefaultTable"
145
"%FunctorLookupFunction"
146
147
"primitiveLoad"
148
"coreQuit"
149
"fatalError"
150
"internalError"
151
"coreError"
152
"errorCount"
153
"countError"
154
"resetErrorCount"
155
"warn"
156
"startCompileDuration"
157
"endCompileDuration"
158
159
"%ByteArray"
160
"makeByteArray"
161
"makeBitVector"
162
"makeString"
163
"mkVector"
164
"mkIntArray"
165
"listToString"
166
"maxIndex"
167
168
"%hasFeature"
169
"%systemOptions"
170
"%systemArguments"
171
"%sysInit"
172
"%basicSystemIsComplete"
173
"%algebraSystemIsComplete"
174
"%nothing"
175
"%nullStream"
176
"%nonNullStream"
177
"%escapeSequenceAverseHost?"
178
"%defaultReadAndLoadSettings"
179
180
"$hostPlatform"
181
"$buildPlatform"
182
"$targetPlatform"
183
184
"$faslType"
185
"$LispFileType"
186
"$delayedFFI"
187
"$useLLVM"
188
"$effectiveFaslType"
189
"$NativeModuleExt"
190
"$systemInstallationDirectory"
191
"$NativeTypeTable"
192
"$LispOptimizeOptions"
193
"$StandardLinking"
194
"$ECLVersionNumber"
195
"$FilesToRetain"
196
"$dynamicForeignFunctions"
197
198
"getOptionValue"
199
"getCommandLineArguments"
200
"$originalLispTopLevel"
201
"link"
202
"installDriver"
203
"associateRequestWithFileType"
204
"ensureTrailingSlash"
205
"getOutputPathname"
206
"loadPathname"
207
"loadFileIfPresent"
208
"compileLispFile"
209
"compileLispHandler"
210
"Option"
211
"systemRootDirectory"
212
"systemLibraryDirectory"
213
"userHomeDirectory"
214
215
"pathBasename"
216
217
"IMPORT-MODULE"
218
"bootImport"
219
"CONCAT"
220
"$EditorProgram"
221
222
"ident?"
223
;; numeric support
224
"fixnum?"
225
"double"
226
"%fNaN?"
227
"integerAndFractionalParts"
228
))
229
230
(in-package "AxiomCore")
231
232
;;
233
;; -*- Basic data types -*-
234
;;
235
236
;; Type of nothing. Bottom of the abstract machine type lattice.
237
;; Since Lisp functions always returns something, we cannot
238
;; use the `nil' type specifier (the ideal answer). Second
239
;; best possibility is to have Void-returning functions
240
;; systematically return `nil'. However, until the Lisp
241
;; backend is fixed, we will use the interpretation that a
242
;; Void-returning function may return anything, but nobody cares.
243
;; Hence, the choice below which contradicts the very first line
244
;; of this description.
245
(deftype |%Void| () 't)
246
247
(deftype |%Thing| () 't)
248
249
(deftype |%Boolean| () 'boolean)
250
251
(deftype |%String| () 'string)
252
253
(deftype |%Symbol| () 'symbol)
254
255
(deftype |%Short| () 'fixnum)
256
257
(deftype |%Bit| () 'bit)
258
259
(deftype |%Byte| () '(unsigned-byte 8))
260
261
(deftype |%Char| () 'character)
262
263
(deftype |%Bignum| () 'bignum)
264
265
(deftype |%Integer| () 'integer)
266
267
(deftype |%IntegerSection| (n) `(integer ,n))
268
269
(deftype |%DoubleFloat| () 'double-float)
270
271
(deftype |%Number| () 'number)
272
273
(deftype |%Atom| () 'atom)
274
275
(deftype |%Maybe| (s) `(or null ,s))
276
277
(deftype |%Pair| (u v)
278
`(cons ,u ,v))
279
280
(deftype |%Node| (s)
281
`(cons ,s null))
282
283
(deftype |%List| (s)
284
`(or null (cons ,s)))
285
286
(deftype |%SimpleArray| (s) `(simple-array ,s))
287
288
(deftype |%Vector| (s) `(vector ,s))
289
290
(deftype |%BitVector| () '(simple-array bit))
291
292
(deftype |%Table| nil 'hash-table)
293
294
(deftype |%Shell| () 'simple-vector)
295
296
(deftype |%Mode| () '(or symbol string cons))
297
298
(deftype |%Sig| () '(or symbol cons))
299
300
(deftype |%Code| () '(or |%Form| |%Char|))
301
302
(deftype |%Env| () '(or null cons))
303
304
(deftype |%Form| () '(or number symbol string cons))
305
306
(deftype |%Triple| ()
307
'(cons |%Code| (cons |%Mode| (cons |%Env| null))))
308
309
;; Functor templates
310
(deftype |%FunctorTemplate| ()
311
'simple-vector)
312
313
;; operator directory for functors.
314
(deftype |%FunctorOperatorDirectory| ()
315
'(simple-array (or symbol fixnum)))
316
317
;; List of (attribute . predicate-index) pairs for functors.
318
(deftype |%FunctorAttributeTable| ()
319
'list)
320
321
;; Lookup-function for functors. For most functors, they are
322
;; either lookupIncomplete or lookupComplete.
323
;; Historical functors have lookupInTable.
324
(deftype |%FunctorLookupFunction| ()
325
'|%Symbol|)
326
327
;; Functor predicate index table
328
(deftype |%FunctorPredicateIndexTable| ()
329
'(simple-array fixnum))
330
331
;; vector of categories a functor instantiation may belong to.
332
(deftype |%FunctorCategoryTable| ()
333
'(simple-array |%Form|))
334
335
;; vector of default category packages that a functor may implicitly use.
336
(deftype |%FunctorDefaultTable| ()
337
'(simple-array (|%Maybe| |%Constructor|)))
338
339
;; sequence of `byte codes' for a functor
340
(deftype |%FunctorBytecode| ()
341
'(simple-array fixnum))
342
343
;; PredicateIndex + DefaultTable + CategoryTable + Bytecode
344
(deftype |%FunctorCoreData| ()
345
'(cons |%FunctorPredicateIndexTable|
346
(cons |%FunctorDefaultTable|
347
(cons |%FunctorCategoryTable| |%FunctorBytecode|))))
348
349
350
;; The essential of what is needed to instantiate a functor.
351
;; This is the type of `infovec' properties of functors.
352
(deftype |%FunctorData| ()
353
'(cons |%FunctorTemplate|
354
(cons |%FunctorOperatorDirectory|
355
(cons |%FunctorAttributeTable|
356
(cons |%Thing|
357
(cons |%FunctorLookupFunction| null))))))
358
359
;;
360
;; -*- Configuration Constants -*-
361
;;
362
363
;; The canonical triplets for host, build, and target. For the moment,
364
;; they are all identical, for we don't support cross compilation yet.
365
(defconstant |$hostPlatform| "x86_64-unknown-linux-gnu")
366
(defconstant |$buildPlatform| "x86_64-unknown-linux-gnu")
367
(defconstant |$targetPlatform| "x86_64-unknown-linux-gnu")
368
369
;; How to invoke the host C++ compiler and linker flags
370
(defconstant oa-cxx "g++")
371
(defconstant oa-ldflags "-m64")
372
373
;; The directory that contains the final installation directory, as
374
;; specified at configuration time (or in exoteric cases, as overriden
375
;; on the Make command line).
376
(defconstant |$systemInstallationDirectory|
377
"/projects/77750c71-ec7b-4962-bf55-a49ff5065fb6/lib/open-axiom/x86_64-unknown-linux-gnu/1.5.0-2016-01-24/")
378
379
;; File kinds to retain.
380
(defconstant |$FilesToRetain|
381
'())
382
383
;; List of foreign function symbols to unload before saving the
384
;; Lisp image. This is meaningful only for those systems not
385
;; using standard linking and that delay FFI modules to runtime.
386
(defparameter |$dynamicForeignFunctions| nil)
387
388
;; Lisp compiler optimization settings.
389
(defconstant |$LispOptimizeOptions|
390
'(speed))
391
392
(proclaim '(optimize speed))
393
394
;; Enablig profiling of generated Lisp codes.
395
(eval-when (:compile-toplevel :load-toplevel :execute)
396
(defconstant |$EnableLispProfiling| nil))
397
398
(eval-when (:compile-toplevel :load-toplevel :execute)
399
(progn #+(and :sbcl (not :win32)) (require :sb-sprof)))
400
401
;; Return true if the full OpenAxiom algebra system is completed
402
;; built.
403
(defun |%algebraSystemIsComplete| nil
404
(member :open-axiom-algebra-system *features*))
405
406
;; Return true if the basic OpenAxiom system is complete. This means
407
;; that we have a compiler and an interpreter, but not necessarily
408
;; the algebras.
409
(defun |%basicSystemIsComplete| nil
410
(or (|%algebraSystemIsComplete|)
411
(member :open-axiom-basic-system *features*)))
412
413
;; Return true if the Boot system is completely bootstrapped.
414
(defun boot-completed-p nil
415
(or (|%basicSystemIsComplete|)
416
(member :open-axiom-boot *features*)))
417
418
;;
419
;; -*- Hosting Lisp System -*-
420
;;
421
422
(eval-when (:compile-toplevel :load-toplevel :execute)
423
(progn
424
(setq *read-default-float-format* 'double-float)
425
(setq *load-verbose* nil)))
426
427
;; True means that the base Lisp system uses conventional C-style
428
;; program linking model, whereby programs are constructed by linking
429
;; separately compiled units. By constrast, many Lisp systems build
430
;; executable programs by loading FASLs into core and dumping the resulting
431
;; image on disk.
432
(defconstant |$StandardLinking|
433
(eq 'no 'yes))
434
435
;; Almost every supported Lisp use dynamic link for FFI.
436
;; ECL's support is partial. GCL-2.6.x hasn't discovered it yet.
437
(defconstant |$useDynamicLink|
438
#+:ecl (member :dffi *features*)
439
#+:gcl nil
440
#-(or :ecl :gcl) t)
441
442
;; True if FFI modules were delayed till runtime.
443
(defconstant |$delayedFFI|
444
(eq 'yes 'yes))
445
446
;; True if the host has usable framework
447
(defconstant |$useLLVM|
448
(eq 'yes 'yes))
449
450
;; The top level read-eval-print loop function of the base
451
;; Lisp system we are using. This is a very brittle way
452
;; of achieving something conceptually simple.
453
(defconstant |$originalLispTopLevel|
454
#+:ecl #'si::top-level
455
#+:gcl #'si::top-level
456
#+:sbcl #'sb-impl::toplevel-init
457
#+clisp #'system::main-loop
458
#+:clozure nil ; don't know, kept private
459
)
460
461
;; Lisp source file extension.
462
(defconstant |$LispFileType| "lisp")
463
464
;; Extenstion of FASL files.
465
(defconstant |$faslType|
466
(pathname-type (compile-file-pathname "foo.lisp")))
467
468
(defconstant |$effectiveFaslType|
469
#+:ecl (pathname-type (compile-file-pathname "foo.lisp" :system-p t))
470
#-:ecl |$faslType|)
471
472
;; Extension of file containers for native shared libraries.
473
(defconstant |$NativeModuleExt|
474
(cond (|$useDynamicLink| ".so")
475
(t ".a")))
476
477
;; Return true if the host is escape sequence averse. This is notably
478
;; true on windows-based builds (win32 or win64)
479
(defun |%escapeSequenceAverseHost?| ()
480
(or (member :win32 *features*)
481
(member :windows *features*)))
482
483
;; Some default settings
484
(defmacro |%defaultReadAndLoadSettings| ()
485
`(eval-when (:compile-toplevel :load-toplevel :execute)
486
(progn
487
(setq *read-default-float-format* 'double-float)
488
(setq *load-verbose* nil))))
489
490
(defconstant |$EditorProgram| "/usr/bin/vi")
491
492
;; Token expression to indicate absence of value or bottom value.
493
;; This is also the bottom value of the Maybe domain.
494
(defconstant |%nothing| :|OpenAxiomNoValue|)
495
496
;; Token expression to indicate the end of a stream of values.
497
(defconstant |%nullStream| :|OpenAxiomNullStream|)
498
499
;; Token expression to indicate there are move to come in a stream of values.
500
(defconstant |%nonNullStream| :|OpenAxiomNonNullStream|)
501
502
;; Base name of the native core runtime library
503
(defconstant |$CoreLibName|
504
"open-axiom-core")
505
506
;; C runtime needed by the target system; e.g. -lm or -lwinsock
507
(defconstant |$ExtraRuntimeLibraries|
508
'("-lutil" "-lm"))
509
510
(defun extra-runtime-libs nil
511
(if (boot-completed-p)
512
(append
513
(list (concatenate 'string "-L" (|systemLibraryDirectory|))
514
(concatenate 'string "-l" |$CoreLibName|))
515
|$ExtraRuntimeLibraries|)
516
|$ExtraRuntimeLibraries|))
517
518
519
#+:clisp
520
(eval-when (:compile-toplevel :load-toplevel :execute)
521
(progn
522
(setf custom:*ansi* t)
523
(setf custom:*floating-point-contagion-ansi* t)
524
(setf custom:*warn-on-floating-point-contagion* t)
525
(setf custom:*trace-indent* t)
526
(setf custom:*foreign-encoding*
527
(ext:make-encoding :charset charset:iso-8859-1))))
528
529
530
;; ECL is a moving target, especially, in its FII support. Track
531
;; versions as poor man safeguard to portability chaos.
532
(defconstant |$ECLVersionNumber|
533
#-:ecl -1
534
#+:ecl (let ((ver (find-symbol "+ECL-VERSION-NUMBER+" "EXT")))
535
(cond (ver (symbol-value ver))
536
(t -1))))
537
538
;; -*- Hash table -*-
539
(defmacro |makeTable| (cmp)
540
`(make-hash-table :test ,cmp))
541
542
(defmacro |tableValue| (ht k)
543
`(gethash ,k ,ht))
544
545
(defmacro |tableRemove!| (ht k)
546
`(remhash ,k ,ht))
547
548
(defmacro |tableLength| (ht)
549
`(hash-table-count ,ht))
550
551
;; -*- Reference -*-
552
(defmacro |ref| (v)
553
`(cons ,v nil))
554
555
(defmacro |deref| (r)
556
`(car ,r))
557
558
;; -*- File IO -*-
559
560
(defparameter |$stdout| *standard-output*)
561
(defparameter |$stdin| *standard-input*)
562
(defparameter |$stdio| *terminal-io*)
563
564
(defparameter |$InputStream| (make-synonym-stream '*standard-input*))
565
(defparameter |$OutputStream| (make-synonym-stream '*standard-output*))
566
(defparameter |$ErrorStream| (make-synonym-stream '*standard-output*))
567
568
;; Return all entries (except dot and dot-dot) in a directory
569
(defun |directoryEntries| (dir &optional (pattern nil))
570
(let ((dirname (namestring dir)))
571
(cond (pattern (directory (concatenate 'string dirname "/" pattern)))
572
(t ;; list everything.
573
;; There are two groups: those who do the right and obvious thing;
574
;; and those that are anal-retentive about it.
575
#+(or :clisp :clozure :gcl)
576
(directory (concatenate 'string dirname "/*"))
577
#-(or :clisp :clozure :gcl)
578
(nunion
579
(directory (concatenate 'string dirname "/*"))
580
(directory (concatenate 'string dirname "/*.*")))))))
581
582
583
584
(defun |inputBinaryFile| (f)
585
(open f
586
:direction :input
587
:element-type 'unsigned-byte
588
:if-does-not-exist nil))
589
590
(defun |outputBinaryFile| (f)
591
(open f
592
:direction :output
593
:element-type 'unsigned-byte
594
:if-exists :supersede))
595
596
(defun |inputTextFile| (f)
597
(open f
598
:direction :input
599
:if-does-not-exist nil))
600
601
(defun |outputTextFile| (f)
602
(open f
603
:direction :output
604
:if-exists :supersede))
605
606
(defun |closeFile| (f)
607
(close f))
608
609
(defmacro |closeStream| (s)
610
`(close ,s))
611
612
(defmacro |eof?| (s)
613
`(null (peek-char nil ,s nil nil nil)))
614
615
(defmacro |getFileCursor| (s)
616
`(file-position ,s))
617
618
(defmacro |setFileCursor| (s n)
619
`(file-position ,s ,n))
620
621
;; Make a new stream object, duplicate of the denotation of argument.
622
(defmacro |forkStreamByName| (s)
623
`(make-synonym-stream ,s))
624
625
;; Read a line from the input text file. Quietly return
626
;; %nothing at end of file.
627
(defmacro |readLine| (f)
628
`(read-line ,f nil |%nothing|))
629
630
(defmacro |readByte| (f)
631
`(read-byte ,f nil |%nothing|))
632
633
(defmacro |readExpr| (f)
634
`(read ,f nil |%nothing|))
635
636
(defun |readIntegerIfCan| (s)
637
(let ((r (multiple-value-call #'cons (parse-integer s :junk-allowed t))))
638
(cond ((eql (cdr r) (length s)) (car r))
639
(t nil))))
640
641
;; Pretty-print a lisp form on a given output stream.
642
(defun |prettyPrint| (x &optional (s |$OutputStream|))
643
(let ((*print-pretty* t)
644
(*print-array* t)
645
(*print-circle* t)
646
(*print-length* nil)
647
(*print-level* nil))
648
(prin1 x s)))
649
650
(defmacro |formatToString| (&rest args)
651
`(format nil ,@args))
652
653
(defmacro |formatToStream| (&rest x)
654
`(format ,@x))
655
656
(defmacro |formatToStdout| (&rest args)
657
`(format |$stdout| ,@args))
658
659
;;
660
;; -*- OpenAxiom filesystem -*-
661
;;
662
663
(defconstant |$BootFileType| "boot")
664
(defconstant |$LibraryFileType| "spad")
665
(defconstant |$ScriptFileType| "input")
666
667
;; Canonalize source file extensions
668
(defun |getFileType|(file)
669
(let ((file-type (pathname-type file)))
670
(cond ((or (equal "clisp" file-type)
671
(equal "lsp" file-type))
672
|$LispFileType|)
673
(t file-type))))
674
675
;; Returns the root directory of the running system.
676
;; A directory specified on command line takes precedence
677
;; over directory specified at configuration time.
678
(defun |systemRootDirectory| nil
679
(let ((dir (assoc (|Option| "system") (|%systemOptions|))))
680
(if (not (null dir))
681
(|ensureTrailingSlash| (cdr dir))
682
|$systemInstallationDirectory|)))
683
684
;; Returns the directory containing the core runtime support
685
;; libraries, either as specified on command line, or as inferred
686
;; from the system root directory.
687
(defun |systemLibraryDirectory| nil
688
(let ((dir (assoc (|Option| "syslib") (|%systemOptions|))))
689
(if (not (null dir))
690
(|ensureTrailingSlash| (cdr dir))
691
(concatenate 'string (|systemRootDirectory|) "lib/"))))
692
693
694
(defmacro |userHomeDirectory| nil
695
(user-homedir-pathname))
696
697
;; Return the list of linkable fasls in in the directory `dir'.
698
(defun linkset-from (dir)
699
(mapcar #'(lambda(f) (concatenate 'string dir f))
700
(with-open-file (stream (concatenate 'string dir "linkset"))
701
(read stream t))))
702
703
;; Return a path to the the subdirectory `subdir' within the
704
;; OpenAxiom filesystem.
705
(defun system-subdirectory (subdir)
706
(concatenate 'string (|systemRootDirectory|) subdir))
707
708
;; Like linkset-from when `feature' in on the features list.
709
(defun linkset-from-if (dir feature)
710
(if (member feature *features*)
711
(linkset-from (system-subdirectory dir))
712
nil))
713
714
;; Return a complete list of fasls as appropriate for building
715
;; an executable program user thought consists only of `fasls'.
716
(defun complete-fasl-list-for-link (fasls)
717
(append (linkset-from-if "lisp/" :open-axiom-base-lisp)
718
(linkset-from-if "boot/" :open-axiom-boot)
719
(map 'list #'|compileFilePathname| fasls)))
720
721
;;
722
;; -*- OpenAxiom Driver Table -*-
723
;;
724
725
;; Global map from requests to drivers.
726
;; Ideally we want to handle
727
;; --help: just print a help menu and exit
728
;; --version: Print version information and exit
729
;; --system=<dir>: specify <dir> as the root directory
730
;; --sysalg=<dir>: specify <dir> as directory containing algebras
731
;; --compile: boot or lisp files
732
;; --translate: boot files
733
;; --prologue=<lisp-code>: Run <lisp-code> just before the main entry point.
734
;; --make: boot, lisp, or fasl files
735
(defparameter |$driverTable|
736
(make-hash-table :test #'equal :size 10))
737
738
739
;; Look up the driver that can handle REQUEST. Returns nil when
740
;; no driver exists.
741
(defun |getDriver| (request)
742
(gethash request |$driverTable|))
743
744
;; Associate DRIVER with REQUEST.
745
;; There can exist at most one driver per request.
746
(defun |installDriver| (request driver)
747
(when (|getDriver| request)
748
(|internalError| "attempt to override driver"))
749
(setf (gethash request |$driverTable|) driver))
750
751
(defun |useFileType?| (request)
752
(get request 'use-file-type))
753
754
;; Register DRIVER for a REQUEST for a file with FILE-TYPE extension.
755
(defun |associateRequestWithFileType| (request file-type driver)
756
;; If a driver is already installed, it must be non-null.
757
;; We don't allow overriding at the moment.
758
(let ((key (cons request file-type)))
759
(unless (|useFileType?| request)
760
(setf (get request 'use-file-type) file-type))
761
(|installDriver| key driver)))
762
763
764
;;
765
;; -*- OpenAxiom Command Line Parsing -*-
766
;;
767
768
;; Return a symbol object represensing option named OPT, without leading
769
;; double dash (--).
770
(defun |Option| (opt)
771
(intern (string opt) (find-package "AxiomCore")))
772
773
774
;; Translate option value:
775
;; "no" -> nil
776
;; "yes" -> t
777
;; [0-9]+ -> integer value
778
;; otherwise -> input string unmolested
779
(defun translate-option-value (val)
780
(cond ((string= val "no") nil)
781
((string= val "yes") t)
782
(t (multiple-value-bind (ival idx)
783
(parse-integer val :junk-allowed t)
784
(cond ((null ival) val)
785
((eql idx (length val)) ival)
786
(t val))))))
787
788
;; Returns a pair (name . value) if OPTION if of the form "--name=value",
789
;; where name is a symbol and value is a string. Otherwise, if
790
;; OPTION is of the form "--name", returns the symbol name.
791
(defun |parseOption| (option)
792
(setq option (subseq option 2))
793
(let ((p (position #\= option)))
794
(if p
795
(cons (|Option| (subseq option 0 p))
796
(translate-option-value (subseq option (1+ p))))
797
(|Option| option))))
798
799
;; Returns the value specified for OPTION. Otherwise, return nil
800
(defun |getOptionValue| (opt &optional (options (|%systemOptions|)))
801
(let ((val (assoc (|Option| opt) options)))
802
(cond (val (cdr val))
803
(t nil))))
804
805
;; Walk through the command line arguments ARGV, separating options
806
;; of the form --opt or --opt=val into an a-list, and the rest
807
;; of the command line into a list. The processing stop as soon as
808
;; a non-option form is encountered. OPTIONS-SO-FAR accumulates the
809
;; the list of processed options.
810
(defun |processCommandLine| (argv options-so-far args-so-far)
811
(cond ((null argv)
812
;; no more command-line argument to process
813
(values options-so-far (nreverse args-so-far)))
814
((equal "--" (car argv))
815
;; end of command-line options
816
(values options-so-far (concatenate 'list
817
(nreverse args-so-far)
818
(cdr argv))))
819
((or (< (length (car argv)) 2)
820
(not (equal "--" (subseq (car argv) 0 2))))
821
;; not a command-line option
822
(|processCommandLine| (cdr argv)
823
options-so-far
824
(cons (car argv) args-so-far)))
825
(t (let ((option (|parseOption| (car argv))))
826
(cond ((symbolp option)
827
(|processCommandLine| (cdr argv)
828
(cons (cons option t)
829
options-so-far)
830
args-so-far))
831
((consp option)
832
(|processCommandLine| (cdr argv)
833
(cons option options-so-far)
834
args-so-far))
835
(t (|internalError|
836
(format nil "processCommandLine: unknown option ~S"
837
option))))))))
838
839
;;
840
;; -*- Building New Lisp Images -*-
841
;;
842
;; At many points, the build machinery makes new Lisp images that
843
;; are the results of augmenting a given Lisp image with new
844
;; Lisp files (either compiled or in source form). For most Lisp
845
;; implementations, this is done by loading the Lisp files in the
846
;; current image and dumping the result on disk as an executable.
847
848
849
(defun |getOutputPathname| (options)
850
(let ((output-option (assoc (|Option| "output") options)))
851
(when output-option
852
;; If an output file name was specified on the command line, it
853
;; is so relative to the current working directory. In
854
;; particular we want to prevent overly zelous SBCL to mess
855
;; around with the output file when we call compile-file-pathname.
856
;; The SBCL-specific hack below does not work all the time, but in
857
;; most cases, it is OK.
858
#+:sbcl (merge-pathnames (cdr output-option)
859
*default-pathname-defaults*)
860
#-:sbcl (cdr output-option))))
861
862
863
(defun |getMainEntryPoint| (options)
864
(|getOptionValue| (|Option| "main") options))
865
866
(defun |getPrologue| (options)
867
(let ((prologue (|getOptionValue| (|Option| "prologue") options)))
868
(if prologue (read-from-string prologue) nil)))
869
870
;; This is meaningful only for systems that delay FFI.
871
;; Unbind foreign function symbols in case delaying FFI modules
872
;; is needed. Indeed, these systems should not have references to
873
;; foreign symbols that cannot be guaranteed to work properly
874
;; when the saved image is restarted.
875
(defun unbind-foreign-function-symbols ()
876
(when |$delayedFFI|
877
(mapc #'(lambda (s)
878
(when (fboundp s)
879
(fmakunbound s)))
880
|$dynamicForeignFunctions|)))
881
882
;; Save current image on disk as executable and quit.
883
(defun |saveCore| (core-image &optional (entry-point nil))
884
;; When building the OpenAxiom system, and in many other cases I suspect,
885
;; the main entry point is some function in a package not known to
886
;; the Lisp system at compile time, so we have delayed the
887
;; evaluation of the entry point in a form of a suspension. At this
888
;; point we must have all data needed to complete the evaluation.
889
(when (consp entry-point)
890
(setq entry-point (apply (car entry-point)
891
(cdr entry-point))))
892
(unbind-foreign-function-symbols)
893
#+:sbcl (if (null entry-point)
894
(sb-ext::save-lisp-and-die core-image :executable t)
895
(sb-ext::save-lisp-and-die core-image
896
:toplevel entry-point
897
:executable t))
898
#+:gcl (progn
899
(when entry-point
900
(setq si::*top-level-hook* entry-point))
901
(system::save-system core-image))
902
#+:clisp (progn
903
(if entry-point
904
(ext::saveinitmem core-image
905
:init-function entry-point
906
:executable t
907
:norc t
908
:quiet t
909
)
910
(ext::saveinitmem core-image
911
:executable t
912
:norc t
913
))
914
(ext::quit))
915
#+:clozure (progn
916
(ccl:save-application core-image
917
:toplevel-function entry-point
918
:error-handler :quit
919
:prepend-kernel t)
920
(return-from |saveCore|))
921
(error "don't know how to save Lisp image"))
922
923
924
;; Load a module designated by `f'.
925
(defmacro |primitiveLoad| (f)
926
`(load ,f))
927
928
;;
929
;; -*- Program Termination -*-
930
;;
931
;; When working in batch mode, we need to return so-called `exit status'
932
;; to the calling shell. Common Lisp has no provision for that ---
933
;; not even exiting from the toplevel read-eval-print loop. Most
934
;; Lisp implementations provide an `exit' function as extensions, though
935
;; they don't agree on the exact spelling, therefore on the API.
936
937
;; The function |coreQuit| is our abstractions over those variabilties.
938
;; It takes an optional small integer value, the exit status code to
939
;; return to the calling shell. When no exit status code is specified,
940
;; it would return $0$, meaning that everything is OK.
941
(defun |coreQuit| (&optional (status 0))
942
#+:sbcl (sb-ext:exit :code status)
943
#+:clisp (ext:quit status)
944
#+:gcl (si::bye status)
945
#+:ecl (ext:quit status)
946
#+:clozure (ccl:quit status)
947
#-(or :sbcl :clisp :gcl :ecl :clozure)
948
(error "`coreQuit' not implemented for this Lisp"))
949
950
951
;;
952
;; -*- Basic Diagnostic Routines -*-
953
;;
954
;; For the most basic batch stuff, we want:
955
;; (1) fatal error: output message and exit with nonzero status
956
;; (2) internal error: same. This is for use on reporting internal
957
;; consistency error.
958
(defun |diagnosticMessage|(prefix msg)
959
(let ((text (concatenate 'string prefix ": " msg)))
960
(write-line text *error-output*)))
961
962
;; Keep count of number of hard errors.
963
(defparameter |$errorCount| 0)
964
965
(defun |errorCount| nil
966
|$errorCount|)
967
968
(defun |countError| nil
969
(setq |$errorCount| (1+ |$errorCount|)))
970
971
(defun |resetErrorCount| nil
972
(setq |$errorCount| 0))
973
974
;; utils
975
976
;; GCL has a hard limit on the number of arguments for concatenate.
977
;; However, it has a specialized versions for catenating string
978
;; that seems immune to that hard limit. Specialized accordingly.
979
(defun |catenateStrings| (&rest l)
980
#+ :gcl (apply #'si::string-concatenate l)
981
#- :gcl (apply #'concatenate 'string l))
982
983
(defun concat (a b &rest l)
984
(cond ((bit-vector-p a)
985
(apply #'concatenate 'bit-vector a b l))
986
(t
987
(apply #'|catenateStrings|
988
(string a)
989
(string b)
990
(mapcar #'string l)))))
991
992
(defun |fatalError| (msg)
993
(|countError|)
994
(|diagnosticMessage| "fatal error" msg)
995
(|coreQuit| 1))
996
997
(defun |internalError| (msg)
998
(|countError|)
999
(|diagnosticMessage| "internal error" msg)
1000
(|coreQuit| 1))
1001
1002
(defun |coreError| (msg)
1003
(|countError|)
1004
(|diagnosticMessage| "error"
1005
(cond ((consp msg)
1006
(reduce #'(lambda (x y)
1007
(concatenate 'string x y))
1008
msg :initial-value ""))
1009
(t msg)))
1010
nil)
1011
1012
(defun |warn| (msg)
1013
(|diagnosticMessage| "warning"
1014
(cond ((consp msg)
1015
(reduce #'(lambda (x y)
1016
(concatenate 'string x y))
1017
msg :initial-value ""))
1018
(t msg))))
1019
1020
;;
1021
;; -*- Command Line Arguments -*-
1022
1023
(defparameter |$sysOpts| nil)
1024
(defparameter |$sysArgs| nil)
1025
1026
(defun |%systemOptions| ()
1027
|$sysOpts|)
1028
1029
(defun |%systemArguments| ()
1030
|$sysArgs|)
1031
1032
;;
1033
;; Ideally, we would just like to have a traditional command line
1034
;; passing mechanism from the shell to the application. That
1035
;; mechanism works fine with GCL. Some Lisp implementations such as
1036
;; SBCL or CLISP will insist on processing the command lines. Some
1037
;; such as CLISP will baffle when they hit an option they don't
1038
;; understand. Which is silly. It seems like the only common ground,
1039
;; as ever, is to go with the most annoying behaviour and penalize
1040
;; the good "citizen", sensible, Lisp implementations interfaces.
1041
;; Consequently, we have standardized on the the following practice:
1042
;; always issue a double bash (--) after the command line, and afterwards
1043
;; supply options and other arguments. The double dash has the effect
1044
;; of dissuading the underlying lisp implementation of trying to
1045
;; process whatever comes after as options.
1046
1047
;; Command line arguments: equivalent of traditional `argv[]' from
1048
;; systems programming world.
1049
(defun |getCommandLineArguments| nil
1050
#-(or :gcl :sbcl :clisp :ecl :clozure)
1051
(|fatalError| "don't know how to get command line args")
1052
(let* ((all-args
1053
#+:clozure ccl:*command-line-argument-list*
1054
#+:ecl (ext:command-args)
1055
#+:gcl si::*command-args*
1056
#+:sbcl sb-ext::*posix-argv*
1057
#+:clisp (coerce (ext::argv) 'list))
1058
(args (member "--" all-args :test #'equal)))
1059
(cons (car all-args) (if args (cdr args) args))))
1060
1061
;;
1062
;; -*- Building Standalone Executable -*-
1063
;;
1064
;; Build a standalone excutable from LISP-FILES -- a list of
1065
;; pathnames designating compiled source files (either FASLs, for
1066
;; most Lisp systems, or object files for systems like ECL.)
1067
;; ENTRY-POINT is the entry point of the program. If not supplied, or
1068
;; if null, then the entry entry is supposed to be the top level
1069
;; read-eval-print loop of original Lisp system.
1070
;; Note, despite the name LISP-FILEs, we do not expect bare Lisp source
1071
;; files here. We do insist on FASLs. There is no check for that at
1072
;; this point. You have been warned.
1073
(defun |link| (core-image lisp-files
1074
&optional (entry-point nil) (prologue nil))
1075
(if (and entry-point (stringp entry-point))
1076
(setq entry-point `(read-from-string ,entry-point)))
1077
#-:ecl
1078
(progn
1079
(mapcar #'(lambda (p) (|loadOrElse| p)) lisp-files)
1080
(eval prologue)
1081
(|saveCore| core-image entry-point))
1082
#+:ecl
1083
(let* ((compiler::*ld* oa-cxx)
1084
(compiler::*ld-flags* (concatenate 'string
1085
compiler::*ld-flags*
1086
" " oa-ldflags)))
1087
(progn
1088
(unless entry-point
1089
(setq entry-point #'si::top-level))
1090
(c:build-program core-image
1091
:lisp-files
1092
(complete-fasl-list-for-link lisp-files)
1093
:ld-flags (extra-runtime-libs)
1094
:epilogue-code
1095
`(progn
1096
(pushnew :open-axiom-base-lisp *features*)
1097
,prologue
1098
(funcall ,entry-point)))
1099
(|coreQuit|))))
1100
1101
;;
1102
;; -*- Handling Command Line Arguments -*-
1103
;;
1104
1105
(defun |handleRequest| (prog-name request options args)
1106
(let ((driver (|getDriver| request)))
1107
(when (null driver)
1108
(|fatalError| (format nil "invalid option `--~a'" (string request))))
1109
(funcall driver prog-name options args)))
1110
1111
(defun |hasHandler?| (request)
1112
(or (|getDriver| request)
1113
(|useFileType?| request)))
1114
1115
(defun run-driver (prog-name action options args)
1116
(cond ((|useFileType?| (car action))
1117
;; If the action is file-type dependent, make sure
1118
;; we have at least one file.
1119
(unless (not (null args))
1120
(|coreError| "missing input files"))
1121
(dolist (f args t)
1122
(let* ((name (car action))
1123
(file-type (or (|getFileType| f)
1124
(|useFileType?| name)))
1125
(request (cons name file-type)))
1126
(unless (|handleRequest| prog-name request options f)
1127
(return nil)))))
1128
(t (|handleRequest| prog-name (car action) options args))))
1129
1130
1131
(defun |handleCommandLine| (prog-name options args)
1132
(when (or options args)
1133
(let (action)
1134
(dolist (opt options)
1135
(cond ((stringp (cdr opt))
1136
;; In general, nothing is to be done for option value
1137
;; specifications, except when they require special handlers.
1138
(when (|hasHandler?| (car opt))
1139
(unless (|handleRequest| prog-name (car opt) options args)
1140
(return nil))))
1141
1142
;; Don't allow for more than one driver request.
1143
((|hasHandler?| (car opt))
1144
(if (not (null action))
1145
(|coreError| "multiple driver request")
1146
(setq action opt)))))
1147
;; By now, we hope to have figured out what action to perform.
1148
(cond ((consp action)
1149
(run-driver prog-name action options args))
1150
(t nil)))))
1151
1152
;;
1153
;; -*- --help Handler -*-
1154
;;
1155
1156
;; Print help screen
1157
(defun |printUsage| (prog-name)
1158
(write-line "usage:")
1159
(write-line
1160
(concatenate 'string prog-name " -- [options] [files]"))
1161
(write-line "option:")
1162
(write-line " --help print this message")
1163
(write-line " --system=<dir> set <dir> to the root directory of running system")
1164
(write-line " --sysalg=<dir> set <dir> to the algebra directory of running system")
1165
(write-line " --compile compile file")
1166
(write-line " --output=<out> set output file to <out>")
1167
(write-line " --load-directory=<dir> use <dir> as search path for modules")
1168
(write-line " --make create an executable"))
1169
1170
(defun |helpHandler|(prog-name options args)
1171
(declare (ignore options args))
1172
(|printUsage| prog-name)
1173
(|coreQuit|))
1174
1175
(|installDriver| (|Option| "help") #'|helpHandler|)
1176
1177
1178
;;
1179
;; -*- --make Handler -*-
1180
;;
1181
1182
(defun |makeHandler| (prog-name options args)
1183
(declare (ignore prog-name))
1184
(unless (> (length args) 0)
1185
(|fatalError| "--make requires at least one file"))
1186
1187
(|link| (or (|getOutputPathname| options) "a.out")
1188
args
1189
(|getMainEntryPoint| options)
1190
(|getPrologue| options))
1191
(|coreQuit|))
1192
1193
(|installDriver| (|Option| "make") #'|makeHandler|)
1194
1195
1196
;;
1197
;; -*- --load-directory Handler -*-
1198
;;
1199
1200
;; Remember value specified for the --load-dircetory option. Notice
1201
;; that this is the direct handler for that option. Consequently, it
1202
;; passed all three arguments: PROG-NAME OPTIONS ARGS. Only the second
1203
;; argument is of interest.
1204
(defun |recordLoadDirectory| (prog-name options args)
1205
(declare (ignore prog-name args)
1206
(special |$LoadDirectories|))
1207
(let ((load-option (assoc (|Option| "load-directory") options)))
1208
(unless load-option
1209
(|internalError| "`recordLoadDirectory' called without option"))
1210
(unless (cdr load-option)
1211
(|fatalError| "--load-directory option without value"))
1212
(pushnew (cdr load-option) |$LoadDirectories| :test #'equal)
1213
))
1214
1215
(|installDriver| (|Option| "load-directory") #'|recordLoadDirectory|)
1216
1217
;;
1218
;; -*- --compile Handler for Lisp Source Files -*-
1219
;;
1220
(declaim (inline |compileFilePathname|))
1221
(defun |compileFilePathname| (file)
1222
#-:ecl (compile-file-pathname file)
1223
#+:ecl (compile-file-pathname file :type :object))
1224
1225
(defun |currentDirectoryName| nil
1226
(let* ((dir (namestring (truename "")))
1227
(n (1- (length dir))))
1228
(if (char= (char dir n) #\/)
1229
(subseq dir 0 n)
1230
dir)))
1231
1232
;; Compile Lisp source files to target object code. Most of the time
1233
;; this function is called externally to accomplish just that: compile
1234
;; a Lisp file. So, by default, we exit the read-eval-print loop after
1235
;; the task is done.
1236
;;
1237
;; NOTE: The Lisp system ECL has an interesting compilation and program
1238
;; build model. It distinguishes between FASL files (results of
1239
;; compilation usable as operand to LOAD) and object files (result of
1240
;; compilation usable to build standalone programs). We are primarily
1241
;; interested in producing compiled files that can be used to produce
1242
;; standalone programs. Consequently we must convince ECL to produce
1243
;; object files. Notice that when program components require that
1244
;; previously compiled files be loaded in the startup environment,
1245
;; the system will load the FASL file. So, we end up with a 2-step
1246
;; compilation process for ECL:
1247
;; (1) compile as object code;
1248
;; (2) build a FASL from the result of (1).
1249
1250
(defun |compileLispFile| (file out-file)
1251
;; When OUT-FILE does not have a specified parent directory, it is
1252
;; implied that the compiled file is placed in the current directory.
1253
;; This is a very common convention on traditional systems and
1254
;; environments. However GCL would insist to pick the parent
1255
;; directory from FILE, which clearly is bogus.
1256
;; Consequently, we must convince GCL to do what we expected.
1257
#+gcl (when (and (pathname-directory file)
1258
(not (pathname-directory out-file)))
1259
(setq out-file
1260
(make-pathname :name (pathname-name out-file)
1261
:type (pathname-type out-file)
1262
:directory (list (|currentDirectoryName|)))))
1263
(unwind-protect
1264
(progn
1265
(|startCompileDuration|)
1266
(multiple-value-bind (result warning-p failure-p)
1267
#-:ecl (compile-file file :output-file out-file)
1268
#+:ecl (if |$EnableLispProfiling|
1269
(compile-file file :output-file out-file :system-p t
1270
:c-file t :h-file t)
1271
(compile-file file :output-file out-file :system-p t))
1272
#+:ecl
1273
(let ((compiler::*ld* oa-cxx))
1274
(if (and result (not failure-p)
1275
(null (c::build-fasl (compile-file-pathname out-file)
1276
:lisp-files `(,out-file)
1277
:ld-flags (extra-runtime-libs))))
1278
(setq result nil)))
1279
(cond ((null result)
1280
(|coreError| "compilation of Lisp code failed"))
1281
(failure-p
1282
;; Since we believe the source code must
1283
;; be fixed, we don't want to leave
1284
;; the generated FASL behing us, as that
1285
;; would confuse both users and tools.
1286
(delete-file result)
1287
(|coreError| "Lisp code contained errors"))
1288
(warning-p
1289
(|warn| "Lisp code contained warnings")))
1290
result))
1291
(|endCompileDuration|)))
1292
1293
(defun |compileLispHandler| (prog-name options in-file)
1294
(declare (ignore prog-name))
1295
(let ((out-file (|compileFilePathname| (or (|getOutputPathname| options)
1296
in-file))))
1297
(|compileLispFile| in-file out-file)))
1298
1299
(|associateRequestWithFileType| (|Option| "compile") |$LispFileType|
1300
#'|compileLispHandler|)
1301
1302
;;
1303
;; -*- Predefined System Entry Point -*-
1304
;;
1305
1306
;; The top level entry point to most saved Lisp image.
1307
(defun |topLevel|()
1308
(let ((*package* (find-package "AxiomCore"))
1309
(command-args (|getCommandLineArguments|)))
1310
(when (null command-args)
1311
(|internalError| "empty command line args"))
1312
;; Existing system programming practive, and POSIX, have it
1313
;; that the first argument on the command line is the name
1314
;; of the current instantiation of the program.
1315
;; We require at least two arguments:
1316
;; (0) the program name
1317
;; (1) either one of --help or --version, or
1318
;; a filename.
1319
(multiple-value-bind
1320
(options args) (|processCommandLine| (cdr command-args) nil nil)
1321
1322
(setq |$sysOpts| options)
1323
(setq |$sysArgs| args)
1324
1325
;; Run the system-specific initialization.
1326
(when (fboundp '|%sysInit|)
1327
(funcall (symbol-function '|%sysInit|)))
1328
1329
(when (|handleCommandLine| (car command-args) options args)
1330
(|coreQuit| (if (> (|errorCount|) 0) 1 0))))))
1331
1332
1333
;;
1334
;; -*- Filesystem Utilities -*-
1335
;;
1336
1337
;; Make sure that directory name DIR ends with a slash.
1338
(defun |ensureTrailingSlash| (dir)
1339
(let ((l (length dir)))
1340
(unless (> l 0)
1341
(|fatalError| "null directory name"))
1342
(if (char= (char dir (- l 1)) #\/)
1343
dir
1344
(concatenate 'string dir "/"))))
1345
1346
1347
;; Return the basename (without extension) of a file.
1348
(defun |pathBasename| (file)
1349
(pathname-name file))
1350
1351
;;
1352
;; -*- Modules in OpenAxiom -*-
1353
;;
1354
1355
;; List of directories to search for FASLs.
1356
(defparameter |$LoadDirectories| nil)
1357
;; List of FASLs imported
1358
1359
(defparameter |$ImportedModules| nil)
1360
;; Return true if MODULE is known to have been imported or loaded.
1361
1362
(defun |getModuleInternalSymbol| (module)
1363
(intern module (find-package "AxiomCore")))
1364
1365
(defun |alreadyLoaded?| (module)
1366
(get (|getModuleInternalSymbol| (namestring module))
1367
'|AxiomCore.loaded|))
1368
1369
;; Remember that MODULE was imported or loaded.
1370
(defun |noteUnitLoaded| (module)
1371
(setf (get (|getModuleInternalSymbol| (namestring module))
1372
'|AxiomCore.loaded|) t))
1373
1374
;; We are searching for MODULE (currently a FASL) in DIRECTORY. So, this
1375
;; function returns a (tentative) pathname designating that module.
1376
(defun |loadPathname| (module dir)
1377
(setq dir (|ensureTrailingSlash| dir))
1378
(make-pathname :directory (pathname-directory dir)
1379
:name module
1380
#-:ecl :type #-:ecl |$faslType|))
1381
1382
(defun |btxPthaname| (module dir)
1383
(setq dir (|ensureTrailingSlash| dir))
1384
(make-pathname :directory (pathname-directory dir)
1385
:name module
1386
:type "btx"))
1387
1388
(defun |loadFileIfPresent| (file)
1389
(load file :if-does-not-exist nil))
1390
1391
(defun |loadIfPresent| (module)
1392
(if (|alreadyLoaded?| module)
1393
module
1394
(when (|loadFileIfPresent| module)
1395
(|noteUnitLoaded| module)
1396
module)))
1397
1398
(defun |loadOrElse| (module)
1399
(if (|alreadyLoaded?| module)
1400
module
1401
(when (load module :if-does-not-exist :error)
1402
(|noteUnitLoaded| module)
1403
module)))
1404
1405
(defun import-module-if-present (module dir)
1406
(or (|loadIfPresent| (|btxPthaname| module dir))
1407
(|loadIfPresent| (|loadPathname| module dir))))
1408
1409
(defun do-import-module (module directories)
1410
(cond ((null directories)
1411
(|fatalError|
1412
(format nil
1413
"module ~S not found in search path ~S"
1414
module
1415
|$LoadDirectories|)))
1416
(t
1417
(unless (import-module-if-present module (car directories))
1418
(do-import-module module (cdr directories))))))
1419
1420
(defun |importModule| (module)
1421
(do-import-module module |$LoadDirectories|))
1422
1423
(defmacro import-module (module)
1424
`(progn (eval-when
1425
#+:common-lisp (:compile-toplevel :load-toplevel :execute)
1426
#-:common-lisp (compile load eval)
1427
(if (compile-time-p)
1428
(|importModule| ,module)))))
1429
1430
(defmacro |bootImport| (module)
1431
`(|importModule| ,module))
1432
1433
;;
1434
;; -*- Feature Tests in Boot -*-
1435
;;
1436
1437
(defun |%hasFeature| (f)
1438
(member f *features* :test #'eq))
1439
1440
(defun |startCompileDuration| nil
1441
(push :open-axiom-compile-time *features*))
1442
1443
(defun |endCompileDuration| nil
1444
(delete :open-axiom-compile-time *features*))
1445
1446
(defun compile-time-p nil
1447
(member :open-axiom-compile-time *features*))
1448
1449
;; -*- Lisp Implementatiom-dependent Supports -*-
1450
1451
#+(and :sbcl (not :win32))
1452
(require "sb-posix")
1453
1454
#+ :sbcl
1455
(defun shoe-provide-module(name)
1456
(load name)
1457
(provide name))
1458
1459
#+ :sbcl
1460
(eval-when (:load-toplevel :execute)
1461
(pushnew #'shoe-provide-module sb-ext:*module-provider-functions*))
1462
1463
;; Return true if `x' designates an identifier.
1464
(defun |ident?| (x)
1465
(and (symbolp x)
1466
(not (null x))))
1467
1468
;;
1469
;; -*-* Numerics support -*-
1470
;;
1471
(defmacro |fixnum?| (x)
1472
`(typep ,x 'fixnum))
1473
1474
(defmacro |%fNaN?| (x)
1475
#+:sbcl `(sb-ext:float-nan-p ,x)
1476
#+:ecl `(ext:float-nan-p ,x)
1477
#-(or :sbcl :ecl) `(/= ,x ,x))
1478
1479
;; convert an integer to double-float
1480
(defmacro |double| (x)
1481
`(float ,x 1.0d0))
1482
1483
(defmacro |integerAndFractionalParts| (x)
1484
`(multiple-value-list (floor ,x)))
1485
1486
;;
1487
;; -*- Native Datatype correspondance -*-
1488
;;
1489
1490
;; This should be an implementation-independent macro definition,
1491
;; but GCL has problems with it, for some obscure reasons.
1492
#-:gcl
1493
(defmacro |maxIndex| (x)
1494
`(1- (length ,x)))
1495
#+:gcl
1496
(defun |maxIndex| (x)
1497
(1- (length x)))
1498
1499
1500
;; Datatype for buffers mostly used for transmitting data between
1501
;; the Lisp world and Native World.
1502
(deftype |%ByteArray| ()
1503
'(simple-array (unsigned-byte 8)))
1504
1505
(declaim (ftype (function (fixnum) |%ByteArray|) |makeByteArray|))
1506
(defun |makeByteArray| (n)
1507
(make-array n
1508
:element-type '(unsigned-byte 8)
1509
:initial-element 0))
1510
1511
(defmacro |makeBitVector| (n)
1512
`(make-array ,n :element-type 'bit :initial-element 0))
1513
1514
(defun |makeString| (n &optional (c (code-char 0)))
1515
(make-string n :initial-element c))
1516
1517
(defun |listToString| (l)
1518
(let ((s (|makeString| (list-length l))))
1519
(do ((i 0 (1+ i)))
1520
((null l))
1521
(setf (schar s i) (car l))
1522
(setq l (cdr l)))
1523
s))
1524
1525
(defmacro |mkVector| (n)
1526
`(make-array ,n :initial-element nil))
1527
1528
(defmacro |mkIntArray| (n)
1529
`(make-array ,n :initial-element 0))
1530
1531
;; native data type translation table
1532
(defconstant |$NativeTypeTable|
1533
'((|void| . void)
1534
(|char| . char)
1535
(|int| . int)
1536
(|float| . float)
1537
(|double| . double)
1538
(|string| . c-string)
1539
(|address| . @pointer_type@)))
1540
1541
1542