/[slime]/slime/swank-loader.lisp
ViewVC logotype

Diff of /slime/swank-loader.lisp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.35 by asimon, Sun Sep 26 17:09:13 2004 UTC revision 1.107 by alendvai, Fri Oct 15 22:53:45 2010 UTC
# Line 1  Line 1 
1  ;;;; -*- Mode: lisp; indent-tabs-mode: nil -*-  ;;;; -*- indent-tabs-mode: nil -*-
2  ;;;  ;;;
3  ;;; swank-loader.lisp --- Compile and load the Slime backend.  ;;; swank-loader.lisp --- Compile and load the Slime backend.
4  ;;;  ;;;
# Line 8  Line 8 
8  ;;; are disclaimed.  ;;; are disclaimed.
9  ;;;  ;;;
10    
11  (cl:defpackage :swank-loader  ;; If you want customize the source- or fasl-directory you can set
12    (:use :common-lisp))  ;; swank-loader:*source-directory* resp. swank-loader:*fasl-directory*
13    ;; before loading this files. (you also need to create the
14  (in-package :swank-loader)  ;; swank-loader package.)
15    ;; E.g.:
16    ;;
17    ;;   (make-package :swank-loader)
18    ;;   (defparameter swank-loader::*fasl-directory* "/tmp/fasl/")
19    ;;   (load ".../swank-loader.lisp")
20    
21  (defun make-swank-pathname (name &optional (type "lisp"))  (cl:defpackage :swank-loader
22    "Return a pathname with name component NAME in the Slime directory."    (:use :cl)
23    (merge-pathnames (make-pathname :name name :type type)    (:export :init
24                     (or *compile-file-pathname*             :dump-image
25                         *load-pathname*             :*source-directory*
26                         *default-pathname-defaults*)))             :*fasl-directory*))
27    
28  (defparameter *sysdep-pathnames*  (cl:in-package :swank-loader)
29    (mapcar #'make-swank-pathname  
30            (append  (defvar *source-directory*
31             '("nregex")    (make-pathname :name nil :type nil
32             #+cmu '("swank-source-path-parser" "swank-cmucl")                   :defaults (or *load-pathname* *default-pathname-defaults*))
33             #+sbcl '("swank-sbcl" "swank-source-path-parser" "swank-gray")    "The directory where to look for the source.")
34             #+openmcl '("metering" "swank-openmcl" "swank-gray")  
35             #+lispworks '("swank-lispworks" "swank-gray")  (defparameter *sysdep-files*
36             #+allegro '("swank-allegro" "swank-gray")    #+cmu '(swank-source-path-parser swank-source-file-cache swank-cmucl)
37             #+clisp '("xref" "metering" "swank-clisp" "swank-gray")    #+scl '(swank-source-path-parser swank-source-file-cache swank-scl)
38             #+armedbear '("swank-abcl")    #+sbcl '(swank-source-path-parser swank-source-file-cache
39             )))             swank-sbcl swank-gray)
40      #+clozure '(metering swank-ccl swank-gray)
41  (defparameter *lisp-name*    #+lispworks '(swank-lispworks swank-gray)
42    #+cmu       (format nil "cmu-~A"    #+allegro '(swank-allegro swank-gray)
43                        (substitute #\- #\/ (lisp-implementation-version)))    #+clisp '(xref metering swank-clisp swank-gray)
44    #+sbcl      (format nil "sbcl-~A" (lisp-implementation-version))    #+armedbear '(swank-abcl)
45    #+openmcl   "openmcl"    #+cormanlisp '(swank-corman swank-gray)
46    #+lispworks (format nil "lispworks-~A" (lisp-implementation-version))    #+ecl '(swank-source-path-parser swank-source-file-cache
47    #+allegro   (format nil "allegro-~A" excl::*common-lisp-version-number*)            swank-ecl swank-gray))
48    #+clisp     (format nil "clisp-~A" (let ((s (lisp-implementation-version)))  
49                                         (subseq s 0 (position #\space s))))  (defparameter *implementation-features*
50    #+armedbear "abcl"    '(:allegro :lispworks :sbcl :clozure :cmu :clisp :ccl :corman :cormanlisp
51    )      :armedbear :gcl :ecl :scl))
52    
53  (defparameter *swank-pathname* (make-swank-pathname "swank"))  (defparameter *os-features*
54      '(:macosx :linux :windows :mswindows :win32 :solaris :darwin :sunos :hpux
55        :unix))
56    
57    (defparameter *architecture-features*
58      '(:powerpc :ppc :x86 :x86-64 :x86_64 :amd64 :i686 :i586 :i486 :pc386 :iapx386
59        :sparc64 :sparc :hppa64 :hppa
60        :pentium3 :pentium4
61        :java-1.4 :java-1.5 :java-1.6 :java-1.7))
62    
63    (defun q (s) (read-from-string s))
64    
65    #+ecl
66    (defun ecl-version-string ()
67      (format nil "~A~@[-~A~]"
68              (lisp-implementation-version)
69              (when (find-symbol "LISP-IMPLEMENTATION-VCS-ID" :ext)
70                (let ((vcs-id (funcall (q "ext:lisp-implementation-vcs-id"))))
71                  (when (>= (length vcs-id) 8)
72                    (subseq vcs-id 0 8))))))
73    
74    (defun lisp-version-string ()
75      #+(or clozure cmu) (substitute-if #\_ (lambda (x) (find x " /"))
76                                        (lisp-implementation-version))
77      #+(or cormanlisp scl sbcl) (lisp-implementation-version)
78      #+lispworks (lisp-implementation-version)
79      #+allegro   (format nil "~A~A~A~A"
80                          excl::*common-lisp-version-number*
81                          (if (eq 'h 'H) "A" "M")     ; ANSI vs MoDeRn
82                          (if (member :64bit *features*) "-64bit" "")
83                          (excl:ics-target-case
84                           (:-ics "")
85                           (:+ics "-ics")))
86      #+clisp     (let ((s (lisp-implementation-version)))
87                    (subseq s 0 (position #\space s)))
88      #+armedbear (lisp-implementation-version)
89      #+ecl (ecl-version-string) )
90    
91    (defun unique-dir-name ()
92      "Return a name that can be used as a directory name that is
93    unique to a Lisp implementation, Lisp implementation version,
94    operating system, and hardware architecture."
95      (flet ((first-of (features)
96               (loop for f in features
97                     when (find f *features*) return it))
98             (maybe-warn (value fstring &rest args)
99               (cond (value)
100                     (t (apply #'warn fstring args)
101                        "unknown"))))
102        (let ((lisp (maybe-warn (first-of *implementation-features*)
103                                "No implementation feature found in ~a."
104                                *implementation-features*))
105              (os   (maybe-warn (first-of *os-features*)
106                                "No os feature found in ~a." *os-features*))
107              (arch (maybe-warn (first-of *architecture-features*)
108                                "No architecture feature found in ~a."
109                                *architecture-features*))
110              (version (maybe-warn (lisp-version-string)
111                                   "Don't know how to get Lisp ~
112                                    implementation version.")))
113          (format nil "~(~@{~a~^-~}~)" lisp version os arch))))
114    
115  (defun file-newer-p (new-file old-file)  (defun file-newer-p (new-file old-file)
116    "Returns true if NEW-FILE is newer than OLD-FILE."    "Returns true if NEW-FILE is newer than OLD-FILE."
117    (> (file-write-date new-file) (file-write-date old-file)))    (> (file-write-date new-file) (file-write-date old-file)))
118    
119  (defun binary-pathname (source-pathname)  (defun slime-version-string ()
120    "Return the pathname where SOURCE-PATHNAME's binary should be compiled."    "Return a string identifying the SLIME version.
121    (let ((cfp (compile-file-pathname source-pathname)))  Return nil if nothing appropriate is available."
122      (merge-pathnames (make-pathname    (with-open-file (s (merge-pathnames "ChangeLog" *source-directory*)
123                        :directory `(:relative ".slime" "fasl" ,*lisp-name*)                       :if-does-not-exist nil)
124                        :name (pathname-name cfp)      (and s (symbol-name (read s)))))
125                        :type (pathname-type cfp))  
126                       (user-homedir-pathname))))  (defun default-fasl-dir ()
127      (or
128  (defun compile-files-if-needed-serially (files)     ;; If ASDF is available then store Slime's fasl's where ASDF stores them.
129    "Compile each file in FILES if the source is newer than     (let ((translate-fn (find-symbol "COMPILE-FILE-PATHNAME*" :asdf)))
130  its corresponding binary, or the file preceding it was       (when translate-fn
131  recompiled."         (make-pathname
132    (with-compilation-unit ()          :name nil :type nil
133      (let ((needs-recompile nil))          :defaults (funcall translate-fn
134        (dolist (source-pathname files)                             (make-pathname :name "foo"
135          (let ((binary-pathname (binary-pathname source-pathname)))                                            :defaults *source-directory*)))))
136            (handler-case     (merge-pathnames
137                (progn      (make-pathname
138                  (when (or needs-recompile       :directory `(:relative ".slime" "fasl"
139                            (not (probe-file binary-pathname))                              ,@(if (slime-version-string) (list (slime-version-string)))
140                            (file-newer-p source-pathname binary-pathname))                              ,(unique-dir-name)))
141                    (format t "~&;; Compiling ~A...~%" source-pathname)      (user-homedir-pathname))))
142                    (ensure-directories-exist binary-pathname)  
143                    (compile-file source-pathname :output-file binary-pathname)  (defvar *fasl-directory* (default-fasl-dir)
144                    (setq needs-recompile t))    "The directory where fasl files should be placed.")
145                  (load binary-pathname))  
146              #+(or)  (defun binary-pathname (src-pathname binary-dir)
147              (error ()    "Return the pathname where SRC-PATHNAME's binary should be compiled."
148                ;; If an error occurs compiling, load the source instead    (let ((cfp (compile-file-pathname src-pathname)))
149                ;; so we can try to debug it.      (merge-pathnames (make-pathname :name (pathname-name cfp)
150                (load source-pathname))                                      :type (pathname-type cfp))
151              ))))))                       binary-dir)))
152    
153  (defun user-init-file ()  (defun handle-swank-load-error (condition context pathname)
154    "Return the name of the user init file or nil."    (fresh-line *error-output*)
155    (probe-file (merge-pathnames (user-homedir-pathname)    (pprint-logical-block (*error-output* () :per-line-prefix ";; ")
156                                 (make-pathname :name ".swank" :type "lisp"))))      (format *error-output*
157                "~%Error while ~A ~A:~%  ~A~%Aborting.~%"
158                context pathname condition))
159  (compile-files-if-needed-serially    (when (equal (directory-namestring pathname)
160    (append (list (make-swank-pathname "swank-backend"))                 (directory-namestring *fasl-directory*))
161            *sysdep-pathnames*      (ignore-errors (delete-file pathname)))
162            (list *swank-pathname*)))    (abort))
163    
164  (funcall (intern (string :warn-unimplemented-interfaces) :swank-backend))  (defun compile-files (files fasl-dir load)
165      "Compile each file in FILES if the source is newer than its
166  (when (user-init-file)  corresponding binary, or the file preceding it was recompiled.
167    (load (user-init-file)))  If LOAD is true, load the fasl file."
168      (let ((needs-recompile nil)
169            (state :unknown))
170        (dolist (src files)
171          (let ((dest (binary-pathname src fasl-dir)))
172            (handler-case
173                (progn
174                  (when (or needs-recompile
175                            (not (probe-file dest))
176                            (file-newer-p src dest))
177                    (ensure-directories-exist dest)
178                    ;; need to recompile SRC, so we'll need to recompile
179                    ;; everything after this too.
180                    (setq needs-recompile t)
181                    (setq state :compile)
182                    (or (compile-file src :output-file dest :print nil :verbose t)
183                        ;; An implementation may not necessarily signal a
184                        ;; condition itself when COMPILE-FILE fails (e.g. ECL)
185                        (error "COMPILE-FILE returned NIL.")))
186                  (when load
187                    (setq state :load)
188                    (load dest :verbose t)))
189              ;; Fail as early as possible
190              (serious-condition (c)
191                (ecase state
192                  (:compile (handle-swank-load-error c "compiling" src))
193                  (:load    (handle-swank-load-error c "loading" dest))
194                  (:unknown (handle-swank-load-error c "???ing" src)))))))))
195    
196    #+(or cormanlisp)
197    (defun compile-files (files fasl-dir load)
198      "Corman Lisp has trouble with compiled files."
199      (declare (ignore fasl-dir))
200      (when load
201        (dolist (file files)
202          (load file :verbose t)
203          (force-output))))
204    
205    (defun load-user-init-file ()
206      "Load the user init file, return NIL if it does not exist."
207      (load (merge-pathnames (user-homedir-pathname)
208                             (make-pathname :name ".swank" :type "lisp"))
209            :if-does-not-exist nil))
210    
211    (defun load-site-init-file (dir)
212      (load (make-pathname :name "site-init" :type "lisp"
213                           :defaults dir)
214            :if-does-not-exist nil))
215    
216    (defun src-files (names src-dir)
217      (mapcar (lambda (name)
218                (make-pathname :name (string-downcase name) :type "lisp"
219                               :defaults src-dir))
220              names))
221    
222    (defvar *swank-files*
223      `(swank-backend ,@*sysdep-files* swank-match swank-rpc swank))
224    
225    (defvar *contribs*
226      '(swank-c-p-c swank-arglists swank-fuzzy
227        swank-fancy-inspector
228        swank-presentations swank-presentation-streams
229        #+(or asdf sbcl ecl) swank-asdf
230        swank-package-fu
231        swank-hyperdoc
232        #+sbcl swank-sbcl-exts
233        )
234      "List of names for contrib modules.")
235    
236    (defun append-dir (absolute name)
237      (merge-pathnames
238       (make-pathname :directory `(:relative ,name) :defaults absolute)
239       absolute))
240    
241    (defun contrib-dir (base-dir)
242      (append-dir base-dir "contrib"))
243    
244    (defun load-swank (&key (src-dir *source-directory*)
245                            (fasl-dir *fasl-directory*))
246      (when (find-package :asdf)
247        ;; Make sure our swank.asd is visible to ASDF.
248        (eval
249         (let ((*package* (find-package :swank-loader)))
250           (read-from-string
251            "(let ((swank-system (asdf:find-system :swank nil)))
252              (unless (and swank-system
253                           (equal (asdf:component-pathname swank-system)
254                                  (merge-pathnames \"swank.asd\" *source-directory*)))
255                (push *source-directory* asdf:*central-registry*)))"))))
256      (compile-files (src-files *swank-files* src-dir) fasl-dir t)
257      (funcall (q "swank::before-init")
258               (slime-version-string)
259               (list (contrib-dir fasl-dir)
260                     (contrib-dir src-dir))))
261    
262    (defun compile-contribs (&key (src-dir (contrib-dir *source-directory*))
263                             (fasl-dir (contrib-dir *fasl-directory*))
264                             load)
265      (compile-files (src-files *contribs* src-dir) fasl-dir load))
266    
267    (defun loadup ()
268      (load-swank)
269      (compile-contribs :load t))
270    
271    (defun setup ()
272      (load-site-init-file *source-directory*)
273      (load-user-init-file)
274      (when (#-clisp probe-file
275             #+clisp ext:probe-directory
276             (contrib-dir *source-directory*))
277        (eval `(pushnew 'compile-contribs ,(q "swank::*after-init-hook*"))))
278      (funcall (q "swank::init")))
279    
280    (defun init (&key delete reload load-contribs (setup t))
281      "Load SWANK and initialize some global variables.
282    If DELETE is true, delete any existing SWANK packages.
283    If RELOAD is true, reload SWANK, even if the SWANK package already exists.
284    If LOAD-CONTRIBS is true, load all contribs
285    If SETUP is true, load user init files and initialize some
286    global variabes in SWANK."
287      (when (and delete (find-package :swank))
288        (mapc #'delete-package '(:swank :swank-io-package :swank-backend)))
289      (cond ((or (not (find-package :swank)) reload)
290             (load-swank))
291            (t
292             (warn "Not reloading SWANK.  Package already exists.")))
293      (when load-contribs
294        (compile-contribs :load t))
295      (when setup
296        (setup)))
297    
298    (defun dump-image (filename)
299      (init :setup nil)
300      (funcall (q "swank-backend:save-image") filename))

Legend:
Removed from v.1.35  
changed lines
  Added in v.1.107

  ViewVC Help
Powered by ViewVC 1.1.5