source: tags/0.00.7/j/build-abcl.lisp

Last change on this file was 9573, checked in by piso, 19 years ago

DELETE-FILES

File size: 22.0 KB
Line 
1;;; build-abcl.lisp
2
3#+abcl
4(require 'format)
5
6(defpackage build-abcl
7  (:use "COMMON-LISP")
8  (:export #:build-abcl #:make-dist)
9  #+abcl (:import-from #:extensions #:run-shell-command #:probe-directory)
10  #+allegro (:import-from #:excl #:probe-directory)
11  #+clisp (:import-from #:ext #:probe-directory)
12  )
13
14(in-package #:build-abcl)
15
16;; Platform detection.
17
18(defun platform ()
19  #-clisp
20  (let ((software-type (software-type)))
21    (cond ((search "Linux" software-type)
22           :linux)
23          ((or (search "Mac OS X" software-type) ; abcl
24               (search "Darwin" software-type))  ; sbcl
25           :darwin)
26          ((search "Windows" software-type)
27           :windows)
28          (t
29           :unknown)))
30  #+clisp
31  (cond ((member :win32 *features*)
32         :windows)
33        ((zerop (ext:run-shell-command "uname | grep -i darwin" :output nil))
34         :darwin)
35        ((zerop (ext:run-shell-command "uname | grep -i linux" :output nil))
36         :linux)
37        (t
38         :unknown)))
39
40(defparameter *platform* (platform))
41
42(defparameter *file-separator-char*
43  (if (eq *platform* :windows) #\\ #\/))
44
45(defparameter *path-separator-char*
46  (if (eq *platform* :windows) #\; #\:))
47
48(defmacro with-current-directory ((directory) &body body)
49  `(let ((*default-pathname-defaults* ,directory)
50         #+clisp
51         (old-directory (ext:cd)))
52     #+clisp
53     (ext:cd ,directory)
54     (unwind-protect
55         (progn ,@body)
56       #+clisp
57       (ext:cd old-directory)
58       )))
59
60#+sbcl
61(defun run-shell-command (command &key directory (output *standard-output*))
62  (when directory
63    (setf command (concatenate 'string
64                               "\\cd \""
65                               (namestring (pathname directory))
66                               "\" && "
67                               command)))
68  (sb-impl::process-exit-code
69   (sb-ext:run-program
70    "/bin/sh"
71    (list  "-c" command)
72    :input nil :output output)))
73
74#+cmu
75(defun run-shell-command (command &key directory (output *standard-output*))
76  (when directory
77    (setf command (concatenate 'string
78                               "\\cd \""
79                               (namestring (pathname directory))
80                               "\" && "
81                               command)))
82  (ext::process-exit-code
83   (ext:run-program
84    "/bin/sh"
85    (list  "-c" command)
86    :input nil :output output)))
87
88#+clisp
89(defun run-shell-command (command &key directory (output *standard-output*))
90  (declare (ignore output)) ;; FIXME
91  (let (status old-directory)
92    (when directory
93      (setf old-directory (ext:cd))
94      (ext:cd directory))
95    (unwind-protect
96        (setf status (ext:run-shell-command command))
97      (when old-directory
98        (ext:cd old-directory)))
99    (cond ((numberp status)
100           status)
101          ((eq status t)
102           0)
103          (t
104           -1))))
105
106#+lispworks
107(defun run-shell-command (command &key directory (output *standard-output*))
108  (when directory
109    (unless (eq *platform* :windows)
110      (setf command (concatenate 'string
111                                 "\\cd \""
112                                 (namestring (pathname directory))
113                                 "\" && "
114                                 command))))
115  (system:call-system-showing-output
116   command
117   :shell-type "/bin/sh"
118   :output-stream output))
119
120#+allegro
121(defun run-shell-command (command &key directory (output *standard-output*))
122  (excl:run-shell-command command :directory directory :input nil :output output))
123
124#+(or sbcl cmu lispworks)
125(defun probe-directory (pathspec)
126  (let* ((truename (probe-file pathspec)) ; TRUENAME is a pathname.
127         (namestring (and truename (namestring truename)))) ; NAMESTRING is a string.
128    (and namestring
129         (> (length namestring) 0)
130         (eql (char namestring (1- (length namestring))) *file-separator-char*)
131         truename)))
132
133(defparameter *build-root*
134  (make-pathname :device (pathname-device *load-truename*)
135                 :directory (pathname-directory *load-truename*)))
136
137(defparameter *customizations-file*
138  (merge-pathnames "customizations.lisp" *build-root*))
139
140(defparameter *abcl-dir*
141  (merge-pathnames "src/org/armedbear/lisp/" *build-root*))
142
143(defparameter *jdk*           nil)
144(defparameter *java-compiler* nil)
145(defparameter *javac-options* nil)
146(defparameter *jikes-options* nil)
147(defparameter *jar*           nil)
148
149(defvar *classpath*)
150(defvar *java*)
151(defvar *java-compiler-options*)
152(defvar *java-compiler-command-line-prefix*)
153
154(defun initialize-build ()
155  (setf *jdk*           nil
156        *java-compiler* nil
157        *javac-options* nil
158        *jikes-options* nil
159        *jar*           nil)
160  (load *customizations-file*)
161  (setf *java* (probe-file (merge-pathnames (if (eq *platform* :windows)
162                                                "bin\\java.exe"
163                                                "bin/java")
164                                            *jdk*)))
165  (unless *java*
166    (error "Can't find Java executable."))
167  (unless *java-compiler*
168    (setf *java-compiler* (merge-pathnames (if (eq *platform* :windows)
169                                               "bin/javac.exe"
170                                               "bin/javac")
171                                           *jdk*)))
172  (unless *jar*
173    (setf *jar* (merge-pathnames (if (eq *platform* :windows)
174                                     "bin/jar.exe"
175                                     "bin/jar")
176                                 *jdk*)))
177  (let ((classpath-components (list (merge-pathnames "src" *build-root*)
178                                    (if (eq *platform* :darwin)
179                                        #p"/System/Library/Frameworks/JavaVM.framework/Classes/classes.jar"
180                                        (merge-pathnames "jre/lib/rt.jar" *jdk*)))))
181    (setf *classpath*
182          (with-output-to-string (s)
183            (do* ((components classpath-components (cdr components))
184                  (component (car components) (car components)))
185                 ((null components))
186              (princ (safe-namestring component) s)
187              (unless (null (cdr components))
188                (write-char *path-separator-char* s))))))
189  (let ((prefix (concatenate 'string
190                             (safe-namestring *java-compiler*)
191                             " -classpath " *classpath*)))
192    (setf *java-compiler-options*
193          (if (string-equal (pathname-name (pathname *java-compiler*)) "jikes")
194              *jikes-options*
195              *javac-options*))
196    (setf prefix
197          (if *java-compiler-options*
198              (concatenate 'string prefix " " *java-compiler-options* " ")
199              (concatenate 'string prefix " ")))
200    (setf *java-compiler-command-line-prefix* prefix)))
201
202(defun substitute-in-string (string substitutions-alist)
203  (dolist (entry substitutions-alist)
204    (let ((index (search (car entry) string :test #'string=)))
205      (when index
206        (setf string (concatenate 'string
207                                  (subseq string 0 index)
208                                  (cdr entry)
209                                  (subseq string (+ index (length (car entry)))))))))
210  string)
211
212(defun copy-with-substitutions (source-file target-file substitutions-alist)
213  (with-open-file (in source-file :direction :input)
214    (with-open-file (out target-file :direction :output :if-exists :supersede)
215      (loop
216        (let ((string (read-line in nil)))
217          (when (null string)
218            (return))
219          (write-line (substitute-in-string string substitutions-alist) out))))))
220
221(defun build-javac-command-line (source-file)
222  (concatenate 'string
223               *java-compiler-command-line-prefix*
224               (namestring source-file)))
225
226(defun java-compile-file (source-file)
227  (let ((cmdline (build-javac-command-line source-file)))
228    (zerop (run-shell-command cmdline :directory *abcl-dir*))))
229
230(defun make-classes (force batch)
231  (let* ((source-files
232          (append (with-current-directory (*abcl-dir*)
233                    (directory "*.java"))
234                  (with-current-directory ((merge-pathnames "java/awt/" *abcl-dir*))
235                    (directory "*.java"))))
236         (to-do ()))
237    (if force
238        (setf to-do source-files)
239        (dolist (source-file source-files)
240          (let ((class-file (merge-pathnames (make-pathname :type "class"
241                                                            :defaults source-file))))
242            (when (or (null (probe-file class-file))
243                      (>= (file-write-date source-file)
244                          (file-write-date class-file)))
245              (push source-file to-do)))))
246    (format t "~&JDK: ~A~%" *jdk*)
247    (format t "Java compiler: ~A~%" *java-compiler*)
248    (format t "Compiler options: ~A~%~%" (if *java-compiler-options* *java-compiler-options* ""))
249    (finish-output)
250    (cond ((null to-do)
251           (format t "Classes are up to date.~%")
252           (finish-output)
253           t)
254          (t
255           (cond (batch
256                  (let* ((dir (pathname-directory *abcl-dir*))
257                         (cmdline (with-output-to-string (s)
258                                    (princ *java-compiler-command-line-prefix* s)
259                                    (dolist (source-file to-do)
260                                      (princ
261                                       (if (equal (pathname-directory source-file) dir)
262                                           (file-namestring source-file)
263                                           (namestring source-file))
264                                       s)
265                                      (princ #\space s))))
266                         (status (run-shell-command cmdline :directory *abcl-dir*)))
267                    (zerop status)))
268                 (t
269                  (dolist (source-file to-do t)
270                    (unless (java-compile-file source-file)
271                      (format t "Build failed.~%")
272                      (return nil)))))))))
273
274(defun make-jar ()
275  (let ((*default-pathname-defaults* *build-root*)
276        (jar-namestring (namestring *jar*)))
277    (when (position #\space jar-namestring)
278      (setf jar-namestring (concatenate 'string "\"" jar-namestring "\"")))
279    (let ((substitutions-alist (acons "@JAR@" jar-namestring nil))
280          (source-file (if (eq *platform* :windows) "make-jar.bat.in" "make-jar.in"))
281          (target-file (if (eq *platform* :windows) "make-jar.bat"    "make-jar"))
282          (command     (if (eq *platform* :windows) "make-jar.bat"    "sh make-jar")))
283      (copy-with-substitutions source-file target-file substitutions-alist)
284      (let ((status (run-shell-command command :directory *build-root*)))
285        (unless (zerop status)
286          (format t "~A returned ~S~%" command status))
287        status))))
288
289(defun do-compile-system ()
290  (terpri)
291  (finish-output)
292  (let* ((java-namestring (safe-namestring *java*))
293         status)
294    (cond ((eq *platform* :windows)
295           (with-open-file (stream
296                            (merge-pathnames "compile-system.bat" *build-root*)
297                            :direction :output
298                            :if-exists :supersede)
299             (princ java-namestring stream)
300             (write-string " -cp " stream)
301             (princ "src" stream)
302             (write-char #\space stream)
303             (write-string "org.armedbear.lisp.Main --eval \"(compile-system :quit t)\"" stream)
304             (terpri stream))
305           (setf status
306                 (run-shell-command "compile-system.bat"
307                                    :directory *build-root*)))
308          (t ; Linux
309           (let ((cmdline
310                  (with-output-to-string (s)
311                    (princ java-namestring s)
312                    (write-string " -cp " s)
313                    (princ "src" s)
314                    (write-char #\space s)
315                    (write-string "org.armedbear.lisp.Main --eval \"(compile-system :quit t)\"" s)
316                    )))
317             (setf status
318                   (run-shell-command cmdline
319                                      :directory *build-root*)))))
320    status))
321
322(defun make-libabcl ()
323  (and (let* ((javah-namestring (namestring (probe-file (merge-pathnames "bin/javah" *jdk*))))
324              (command
325               (format nil "~A -o org/armedbear/lisp/native.h org.armedbear.lisp.Native"
326                       javah-namestring))
327              (status
328               (run-shell-command command :directory (merge-pathnames "src/" *build-root*))))
329         (unless (zerop status)
330           (format t "~A returned ~S~%" command status))
331         (zerop status))
332       (let* ((jdk-namestring (namestring *jdk*))
333              (command
334               (format nil "gcc -shared -o libabcl.so -O -D_REENTRANT -fpic -I~Ainclude -I~Ainclude/~A native.c"
335                       jdk-namestring jdk-namestring
336                       (cond ((eq *platform* :linux)
337                              "linux")
338                             ((search "SunOS" (software-type))
339                              "solaris"))))
340              (status
341               (run-shell-command command :directory *abcl-dir*)))
342         (unless (zerop status)
343           (format t "~A returned ~S~%" command status))
344         (zerop status))))
345
346;; abcl/abcl.bat
347(defun make-launch-script ()
348  (cond ((eq *platform* :windows)
349         (with-open-file (s
350                          (merge-pathnames "abcl.bat" *build-root*)
351                          :direction :output
352                          :if-exists :supersede)
353           (format s "~A -cp ~A;~A org.armedbear.lisp.Main %1 %2 %3 %4 %5 %6 %7 %8 %9~%"
354                   (safe-namestring *java*)
355                   (safe-namestring (merge-pathnames "src" *build-root*))
356                   (safe-namestring (merge-pathnames "abcl.jar" *build-root*)))))
357        (t
358         ;; Use the -Xmx256M flag on non-Windows platforms so that the default
359         ;; launch script can be used to build sbcl.
360         (let ((pathname (merge-pathnames "abcl" *build-root*)))
361           (with-open-file (s pathname :direction :output :if-exists :supersede)
362             (if (eq *platform* :linux)
363                 ;; On Linux, set java.library.path for libabcl.so.
364                 (format s "#!/bin/sh~%exec ~A -Xmx256M -Xrs -Djava.library.path=~A -cp ~A:~A org.armedbear.lisp.Main \"$@\"~%"
365                         (safe-namestring *java*)
366                         (safe-namestring *abcl-dir*)
367                         (safe-namestring (merge-pathnames "src" *build-root*))
368                         (safe-namestring (merge-pathnames "abcl.jar" *build-root*)))
369                 ;; Not Linux.
370                 (format s "#!/bin/sh~%exec ~A -Xmx256M -cp ~A:~A org.armedbear.lisp.Main \"$@\"~%"
371                         (safe-namestring *java*)
372                         (safe-namestring (merge-pathnames "src" *build-root*))
373                         (safe-namestring (merge-pathnames "abcl.jar" *build-root*)))))
374           (run-shell-command (format nil "chmod +x ~A" (safe-namestring pathname))
375                              :directory *build-root*)))))
376
377(defun build-stamp ()
378  (multiple-value-bind
379      (second minute hour date month year day daylight-p zone)
380      (decode-universal-time (get-universal-time))
381    (declare (ignore daylight-p))
382    (setf day (nth day '("Mon" "Tue" "Wed" "Thu" "Fri" "Sat" "Sun")))
383    (setf month (nth (1- month) '("Jan" "Feb" "Mar" "Apr" "May" "Jun"
384                                  "Jul" "Aug" "Sep" "Oct" "Nov" "Dec")))
385    (setf zone (* zone 100)) ;; FIXME
386    (format nil "~A ~A ~D ~D ~2,'0D:~2,'0D:~2,'0D -~4,'0D"
387            day month date year hour minute second zone)))
388
389(defun make-build-stamp ()
390  (with-open-file (s
391                   (merge-pathnames (make-pathname :name "build"
392                                                   :defaults *abcl-dir*))
393                   :direction :output
394                   :if-exists :supersede)
395    (format s "~A" (build-stamp))))
396
397(defun delete-files (pathnames)
398  (dolist (pathname pathnames)
399    (let ((truename (probe-file pathname)))
400      (when truename
401        (delete-file truename)))))
402
403(defun clean ()
404  (with-current-directory (*abcl-dir*)
405    (delete-files (directory "*.class"))
406    (delete-files (directory "*.abcl"))
407    (delete-files (directory "*.cls"))
408    (delete-files '("native.h" "libabcl.so" "build")))
409  (with-current-directory ((merge-pathnames "java/awt/" *abcl-dir*))
410    (delete-files (directory "*.class"))))
411
412(defun safe-namestring (pathname)
413  (let ((string (namestring pathname)))
414    (when (position #\space string)
415      (setf string (concatenate 'string "\"" string "\"")))
416    string))
417
418(defun build-abcl (&key force
419                        (batch t)
420                        compile-system
421                        jar
422                        clean
423                        libabcl
424                        full)
425  (let ((start (get-internal-real-time)))
426
427    #+lispworks
428    (when (eq *platform* :windows)
429      (setf batch nil))
430
431    (initialize-build)
432    (format t "~&Platform: ~A~%"
433            (case *platform*
434              (:windows "Windows")
435              (:linux   "Linux")
436              (:darwin  "Mac OS X")
437              (t        (software-type))))
438    (finish-output)
439    ;; clean
440    (when clean
441      (clean))
442    ;; classes
443    (unless (make-classes force batch)
444      (format t "Build failed.~%")
445      (return-from build-abcl nil))
446    ;; COMPILE-SYSTEM
447    (when (or full compile-system)
448      (let ((status (do-compile-system)))
449        (unless (zerop status)
450          (format t "Build failed.~%")
451          (return-from build-abcl nil))))
452    ;; abcl.jar
453    (when (or full jar)
454      (let ((status (make-jar)))
455        (unless (zerop status)
456          (format t "Build failed.~%")
457          (return-from build-abcl nil))))
458    ;; libabcl.so
459    (when (and (or full libabcl)
460               (or (eq *platform* :linux)
461                   (search "SunOS" (software-type))))
462      ;; A failure here is not fatal.
463      (make-libabcl))
464    ;; abcl/abcl.bat
465    (make-launch-script)
466    (make-build-stamp)
467    (let ((end (get-internal-real-time)))
468      (format t "Build completed successfully in ~A seconds.~%"
469              (/ (float (- end start)) internal-time-units-per-second)))
470    t))
471
472(defun build-abcl-executable ()
473  (let* ((*default-pathname-defaults* *abcl-dir*)
474         (source-files (directory "*.java"))
475         (cmdline (with-output-to-string (s)
476                    (princ "gcj -O2 " s)
477                    (dolist (source-file source-files)
478                      (unless (string= (pathname-name source-file) "ControlC")
479                        (princ (pathname-name source-file) s)
480                        (princ ".java" s)
481                        (princ #\space s)))
482                    (princ "--main=org.armedbear.lisp.Main -o lisp" s)))
483         (result (run-shell-command cmdline :directory *abcl-dir*)))
484    (zerop result)))
485
486(defvar *copy-verbose* nil)
487
488(defun copy-file (source target)
489  (when *copy-verbose*
490    (format t "~A -> ~A~%" source target))
491  (let ((buffer (make-array 4096 :element-type '(unsigned-byte 8))))
492    (with-open-file (in source :direction :input :element-type '(unsigned-byte 8))
493      (with-open-file (out target :direction :output :element-type '(unsigned-byte 8)
494                           :if-exists :supersede)
495        (loop
496          (let ((end (read-sequence buffer in)))
497            (when (zerop end)
498              (return))
499            (write-sequence buffer out :end end)))))))
500
501(defun copy-files (files source-dir target-dir)
502  (dolist (file files)
503    (copy-file (merge-pathnames file source-dir)
504               (merge-pathnames file target-dir))))
505
506(defun make-dist-dir (version-string)
507  (unless (eq *platform* :linux)
508    (error "MAKE-DIST is only supported on Linux."))
509  (let ((target-root (pathname (concatenate 'string "/var/tmp/" version-string "/"))))
510    (when (probe-directory target-root)
511      (error "Target directory ~S already exists." target-root))
512    (ensure-directories-exist
513     (merge-pathnames "src/org/armedbear/lisp/java/awt/" target-root))
514    (let* ((source-dir *build-root*)
515           (target-dir target-root)
516           (files (list "README"
517                        "COPYING"
518                        "build-abcl.lisp"
519                        "customizations.lisp"
520                        "make-jar.bat.in"
521                        "make-jar.in")))
522      (copy-files files source-dir target-dir))
523    (let* ((source-dir (merge-pathnames "src/" *build-root*))
524           (target-dir (merge-pathnames "src/" target-root))
525           (files (list "manifest-abcl")))
526      (copy-files files source-dir target-dir))
527    (let* ((source-dir *abcl-dir*)
528           (target-dir (merge-pathnames "src/org/armedbear/lisp/" target-root))
529           (*default-pathname-defaults* source-dir)
530           (files (mapcar #'file-namestring (append (directory "*.java")
531                                                    (directory "*.lisp")
532                                                    (list "LICENSE" "native.c")))))
533      (copy-files files source-dir target-dir))
534    (let* ((source-dir (merge-pathnames "java/awt/" *abcl-dir*))
535           (target-dir (merge-pathnames "src/org/armedbear/lisp/java/awt/" target-root))
536           (*default-pathname-defaults* source-dir)
537           (files (mapcar #'file-namestring (directory "*.java"))))
538      (copy-files files source-dir target-dir))
539    target-root))
540
541(defun make-dist (version-string)
542  (let* ((dist-dir (make-dist-dir version-string))
543         (parent-dir (merge-pathnames (make-pathname :directory '(:relative :back))
544                                      dist-dir)))
545    (let* ((command (format nil "tar czf ~A~A.tar.gz ~A"
546                            (namestring parent-dir)
547                            version-string version-string))
548           (status (run-shell-command command :directory parent-dir)))
549      (unless (zerop status)
550        (format t "~A returned ~S~%" command status)))
551    (let* ((command (format nil "zip -q -r ~A~A.zip ~A"
552                            (namestring parent-dir)
553                            version-string version-string))
554           (status (run-shell-command command :directory parent-dir)))
555      (unless (zerop status)
556        (format t "~A returned ~S~%" command status)))))
Note: See TracBrowser for help on using the repository browser.