Skip to content

Commit b289066

Browse files
committed
Allow building a executable with Kiln
1 parent bbafda5 commit b289066

12 files changed

+144
-58
lines changed

bootstrap/build0.lisp

+19-15
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,24 @@
1818
required-version)
1919
(finish-output *error-output*)
2020
(uiop:quit 1)))
21-
(defparameter *target-system* (uiop:getenv "KILN_TARGET_SYSTEM"))
22-
(assert (stringp *target-system*))
23-
(assert (not (= 0 (length *target-system*))))
24-
(if (find-package :ql)
25-
(progn
26-
(format *error-output* "Found Quicklisp~%")
27-
(uiop:symbol-call :ql :register-local-projects)
28-
(multiple-value-call #'uiop:symbol-call
29-
:ql :quickload *target-system*
30-
(if (uiop:getenvp "KILN_DEBUG") (values)
31-
(values :silent t))))
32-
(progn
33-
(format *error-output* "Quicklisp not found~%")
34-
(asdf:load-system *target-system*)))
35-
(kiln/image:load-all-script-systems)
21+
(defun load-system (system)
22+
(assert (stringp system))
23+
(assert (not (= 0 (length system))))
24+
(if (find-package :ql)
25+
(progn
26+
(format *error-output* "Found Quicklisp~%")
27+
(uiop:symbol-call :ql :register-local-projects)
28+
(multiple-value-call #'uiop:symbol-call
29+
:ql :quickload system
30+
(if (uiop:getenvp "KILN_DEBUG") (values)
31+
(values :silent t))))
32+
(progn
33+
(format *error-output* "Quicklisp not found~%")
34+
(asdf:load-system system))))
35+
(load-system "kiln/build")
36+
(let ((target-system (uiop:getenvp "KILN_TARGET_SYSTEM")))
37+
(if target-system
38+
(load-system target-system)
39+
(kiln/image:load-all-script-systems)))
3640
(finish-output *error-output*)
3741
(uiop:quit)

bootstrap/build1.lisp

+2-5
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,11 @@
1919
"2.2.6")
2020
-7
2121
1)))
22-
(defparameter *target-system* (uiop:getenv "KILN_TARGET_SYSTEM"))
23-
(assert (stringp *target-system*))
24-
(assert (not (= 0 (length *target-system*))))
2522
(setf (asdf/system:component-build-pathname
26-
(asdf:find-system *target-system*))
23+
(asdf:find-system "kiln/build"))
2724
(let ((string (uiop:getenvp "KILN_TARGET_FILE")))
2825
(if string
2926
(uiop:parse-unix-namestring string)
3027
#p"kiln")))
31-
(asdf:make *target-system* :type :program :monolithic t)
28+
(asdf:make "kiln/build" :type :program :monolithic t)
3229
(uiop:quit)

build.sh

+7-3
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,14 @@ set -eu
66
: "${KILN_LISP:=sbcl}"
77
: "${KILN_HEAP_SIZE:=32768}"
88
: "${KILN_STACK_SIZE:=}"
9+
: "${KILN_TARGET_PACKAGE:=}"
10+
: "${KILN_TARGET_SYSTEM:=}"
911

1012
if test -n "$KILN_DEBUG"; then
1113
set -x
14+
env | grep ^KILN_ >&2
1215
fi
1316

14-
export KILN_TARGET_SYSTEM="${KILN_TARGET_SYSTEM:-"kiln/build"}"
15-
1617
# We will rebind KILN_TARGET_FILE to a tmpfile during the build.
1718
real_target_file="${KILN_TARGET_FILE:-"kiln"}"
1819

@@ -59,6 +60,9 @@ fi
5960
: "${CL_SOURCE_REGISTRY:="$(pwd):"}"
6061
export CL_SOURCE_REGISTRY
6162

63+
export KILN_TARGET_PACKAGE
64+
export KILN_TARGET_SYSTEM
65+
6266
# Load once, then dump to avoid serializing foreign pointers.
6367

6468
echo "Updating fasls" >&2
@@ -70,7 +74,7 @@ ${LISP_CMD} --load bootstrap/build1.lisp
7074
chmod +x "$tmpfile"
7175
test -n "$("$tmpfile" version)"
7276
mv -f "$tmpfile" "$real_target_file"
73-
if test -z "${NO_PRINT_VERSION:-}"; then
77+
if test -z "${KILN_NO_PRINT_VERSION:-}"; then
7478
# real_target_file may be a relative path.
7579
PATH=$(pwd):$PATH "${real_target_file}" version
7680
fi

dispatch.lisp

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
(:import-from :kiln/user)
1111
(:import-from :uiop)
1212
(:export
13+
:*entry-point*
1314
:dispatch
1415
:exec
1516
:invoke-entry-point

flags.lisp

+23
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
11
(defpackage :kiln/flags
22
(:use :cl :serapeum :alexandria)
33
(:export
4+
:+kiln-debug+
5+
:+kiln-heap-size+
6+
:+kiln-lisp+
7+
:+kiln-no-print-version+
8+
:+kiln-stack-size+
9+
:+kiln-path-systems+
10+
:+kiln-quicklisp+
11+
:+kiln-target-file+
12+
:+kiln-target-package+
13+
:+kiln-target-system+
14+
:+kiln-tolerant+
415
:*flags*
516
:dbg?
617
:dbg
@@ -16,6 +27,18 @@
1627

1728
(defvar *exit-code* 0)
1829

30+
(def +kiln-debug+ "KILN_DEBUG")
31+
(def +kiln-heap-size+ "KILN_HEAP_SIZE")
32+
(def +kiln-lisp+ "KILN_LISP")
33+
(def +kiln-no-print-version+ "KILN_NO_PRINT_VERSION")
34+
(def +kiln-stack-size+ "KILN_STACK_SIZE")
35+
(def +kiln-path-systems+ "KILN_PATH_SYSTEMS")
36+
(def +kiln-quicklisp+ "KILN_QUICKLISP")
37+
(def +kiln-target-file+ "KILN_TARGET_FILE")
38+
(def +kiln-target-package+ "KILN_TARGET_PACKAGE")
39+
(def +kiln-target-system+ "KILN_TARGET_SYSTEM")
40+
(def +kiln-tolerant+ "KILN_TOLERANT")
41+
1942
(defplace exit-code ()
2043
*exit-code*)
2144

image.lisp

+43-13
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,17 @@
66
(:local-nicknames (:bt :bordeaux-threads))
77
(:shadowing-import-from :closer-mop :ensure-finalized)
88
(:import-from :cffi)
9-
(:import-from :kiln/dispatch)
9+
(:import-from :kiln/dispatch :*entry-point*)
10+
(:import-from
11+
:kiln/flags
12+
:dbg
13+
:+kiln-target-package+
14+
:+kiln-target-system+)
1015
(:import-from :kiln/script-cache :populate-script-cache)
1116
(:import-from :kiln/script-cache :populate-script-cache)
1217
(:import-from :kiln/utils :setpgrp)
1318
(:export
14-
:load-all-script-systems))
19+
:load-all-script-systems))
1520
(in-package :kiln/image)
1621

1722
(let (lib-names)
@@ -33,6 +38,10 @@
3338
script-systems
3439
:test #'equal)))
3540

41+
(defun mark-all-systems-immutable ()
42+
(map nil 'asdf:register-immutable-system
43+
(asdf:already-loaded-systems)))
44+
3645
(defun record-builtins ()
3746
(setf *builtins-by-system*
3847
(list-all-scripts-by-system)
@@ -54,6 +63,14 @@
5463
(unless (typep cls 'built-in-class)
5564
(ensure-finalized cls)))))
5665

66+
(defparameter *target-system*
67+
(uiop:getenvp +kiln-target-system+))
68+
69+
(defparameter *target-package*
70+
(or (uiop:getenvp +kiln-target-package+)
71+
(and *target-system*
72+
(string-invert-case *target-system*))))
73+
5774
(defun kiln-before-dump-image ()
5875
(setf uiop/image::*lisp-interaction* nil)
5976
#+sbcl (setf sb-ext:*derive-function-types* t)
@@ -65,14 +82,27 @@
6582
(record-builtins)
6683
;; NB Quicklisp doesn't work if it's called inside of the ASDF
6784
;; build-op. So we run it in a separate thread. (Is this still true?)
68-
(let* ((subsystems (list-builtin-script-subsystems)))
69-
(load-all-script-systems :script-systems subsystems)
70-
;; Mark systems immutable twice: first anything loaded by the
71-
;; package scripts (so the shebang scripts load faster), then
72-
;; again for anything loaded after the shebang scripts.
73-
(mark-other-systems-immutable :script-systems subsystems)
74-
(populate-script-cache)
75-
(mark-other-systems-immutable :script-systems subsystems))
85+
(if *target-system*
86+
(let ((package-name
87+
(or *target-package*
88+
(error "No target package name in environment"))))
89+
(load-system *target-system*)
90+
(mark-all-systems-immutable)
91+
(let ((package
92+
(or (find-package package-name)
93+
(error "No such package as ~a" package-name))))
94+
(setf *entry-point*
95+
(or (find-symbol (string 'main) package)
96+
(error "No main function for package ~a"
97+
package-name)))))
98+
(let* ((subsystems (list-builtin-script-subsystems)))
99+
(load-all-script-systems :script-systems subsystems)
100+
;; Mark systems immutable twice: first anything loaded by the
101+
;; package scripts (so the shebang scripts load faster), then
102+
;; again for anything loaded after the shebang scripts.
103+
(mark-other-systems-immutable :script-systems subsystems)
104+
(populate-script-cache)
105+
(mark-other-systems-immutable :script-systems subsystems)))
76106
(finalize-all-classes)
77107
(asdf:clear-configuration)
78108
(unload-all-foreign-libraries))))
@@ -83,12 +113,12 @@
83113
#+sbcl
84114
(defvar *sbcl-home* (sb-int:sbcl-homedir-pathname))
85115

86-
87116
(defun kiln-after-restore-image ()
88117
#+sbcl (sb-ext:disable-debugger)
89118
;; TODO Would it be better to preload them all?
90-
#+sbcl (setf sb-sys::*sbcl-homedir-pathname* *sbcl-home*)
91-
#+sbcl (setf sb-ext:*derive-function-types* nil)
119+
(unless *target-system*
120+
#+sbcl (setf sb-sys::*sbcl-homedir-pathname* *sbcl-home*)
121+
#+sbcl (setf sb-ext:*derive-function-types* nil))
92122
(setf uiop/image::*lisp-interaction* nil)
93123
(setpgrp)
94124
(reload-all-foreign-libraries))

path.lisp

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
(defpackage :kiln/path
22
(:use :cl :alexandria :serapeum :kiln/stamp)
3+
(:import-from :kiln/flags :+kiln-path-systems+)
34
(:import-from :uiop
45
:file-exists-p :getenv :getenvp :parse-unix-namestring)
56
(:import-from :trivia :match)
@@ -56,7 +57,7 @@
5657
(-> scripts-path () path-list)
5758
(defun scripts-path ()
5859
(append *local-scripts-path*
59-
(when-let (env (getenvp "KILN_PATH_SYSTEMS"))
60+
(when-let (env (getenvp +kiln-path-systems+))
6061
(split-sequence-if (op (find _ ",;:"))
6162
env
6263
:remove-empty-subseqs t))

scripts/rebuild.lisp

+28-16
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,23 @@
1616
:string
1717
:description "Lisp implementation"
1818
:long-name "lisp"
19-
:env-vars '("KILN_LISP")
19+
:env-vars (list +kiln-lisp+)
2020
:key :lisp)
2121
(cli:make-option
2222
:string
2323
:description "Target system"
2424
:long-name "target-system"
2525
:key :target-system)
26+
(cli:make-option
27+
:string
28+
:description "Target package (defaults to system)"
29+
:long-name "target-package"
30+
:key :target-package)
2631
(cli:make-option
2732
:string
2833
:description "Executable to generate"
2934
:long-name "target-file"
35+
:short-name #\o
3036
:key :target-file)
3137
(cli:make-option
3238
:flag
@@ -39,28 +45,28 @@
3945
:long-name "heap-size"
4046
:description "Lisp heap size (MB)"
4147
:initial-value nil
42-
:env-vars '("KILN_HEAP_SIZE")
48+
:env-vars (list +kiln-heap-size+)
4349
:key :heap-size)
4450
(cli:make-option
4551
:integer
4652
:long-name "stack-size"
4753
:description "Lisp stack size (MB)"
4854
:initial-value nil
49-
:env-vars '("KILN_STACK_SIZE")
55+
:env-vars (list +kiln-stack-size+)
5056
:key :stack-size)
5157
(cli:make-option
5258
:flag
5359
:description "Use Quicklisp"
5460
:long-name "quicklisp"
5561
:initial-value :false
56-
:env-vars '("KILN_QUICKLISP")
62+
:env-vars (list +kiln-quicklisp+)
5763
:key :quicklisp)
5864
(cli:make-option
5965
:flag
6066
:description "Skip systems that fail to compile"
6167
:long-name "tolerant"
6268
:initial-value :false
63-
:env-vars '("KILN_TOLERANT")
69+
:env-vars (list +kiln-tolerant+)
6470
:key :tolerant)))
6571

6672
(def command
@@ -75,28 +81,34 @@
7581
(cli:getopt opts :target-file))
7682
(force-output *error-output*)
7783
(when-let (lisp (cli:getopt opts :lisp))
78-
(setf (getenv "KILN_LISP") lisp))
79-
(when-let (target-system (cli:getopt opts :target-system))
80-
(setf (getenv "KILN_TARGET_SYSTEM") target-system))
84+
(setf (getenv +kiln-lisp+) lisp))
85+
(when-let* ((target-system (cli:getopt opts :target-system))
86+
(target-package
87+
(or (cli:getopt opts :target-package)
88+
(string-invert-case target-system))))
89+
(setf (getenv +kiln-target-system+) target-system
90+
(getenv +kiln-target-package+) target-package))
91+
(when (cli:getopt opts :target-package)
92+
(error "Cannot provide --target-package without --target-system"))
8193
(when-let (target-file (cli:getopt opts :target-file))
82-
(setf (getenv "KILN_TARGET_FILE") target-file))
83-
(when (cli:getopt opts :no-version)
84-
(setf (getenv "NO_PRINT_VERSION") "1"))
94+
(setf (getenv +kiln-target-file+) target-file))
95+
(when (or (cli:getopt opts :no-version)
96+
(cli:getopt opts :target-system))
97+
(setf (getenv +kiln-no-print-version+) "1"))
8598
(when-let (heap-size (cli:getopt opts :heap-size))
86-
(setf (getenv "KILN_HEAP_SIZE")
99+
(setf (getenv +kiln-heap-size+)
87100
(princ-to-string heap-size)))
88101
(when-let (stack-size (cli:getopt opts :stack-size))
89-
(setf (getenv "KILN_STACK_SIZE")
102+
(setf (getenv +kiln-stack-size+)
90103
(princ-to-string stack-size)))
91104
(when (cli:getopt opts :quicklisp)
92-
(setf (getenv "KILN_QUICKLISP")
105+
(setf (getenv +kiln-quicklisp+)
93106
(if (find-package :ql)
94107
(asdf:system-relative-pathname "quicklisp"
95108
"../setup.lisp")
96109
(error "Quicklisp requested but not available"))))
97110
(when (cli:getopt opts :tolerant)
98-
(setf (getenv "KILN_TOLERANT") "1"))
99-
111+
(setf (getenv +kiln-tolerant+) "1"))
100112
(let ((path (asdf:system-relative-pathname "kiln" "")))
101113
(uiop:chdir (namestring path))
102114
(exec "sh build.sh"))))

scripts/self-test.lisp

+11
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,17 @@ This is useful when we need to test the exact output."
220220
(is (equal (fmt "Before exec~%Unwinding happened~%exec happened")
221221
result))))
222222

223+
(5am:test entry-point
224+
(with-templated-test-system (:name "kiln-entry-point-system"
225+
:path path
226+
:kiln-path nil)
227+
(uiop:with-temporary-file (:pathname tmp)
228+
(cmd *self*
229+
"rebuild --target-file" tmp
230+
"--target-system kiln-entry-point-system")
231+
(is (uiop:file-exists-p tmp))
232+
(is (equal "Hello, world" ($cmd tmp))))))
233+
223234
(defun main (args)
224235
(destructuring-bind (&optional (test 'test)) args
225236
(when (stringp test)
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1+
;;; -*- mode: lisp -*-
12
(defsystem "kiln-entry-point-system"
2-
:build-operation "asdf:program-op"
3-
:entry-point "kiln-entry-point-system:entry-point")
3+
:components ((:file "kiln-entry-point-system")))
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
;;; -*- mode: lisp -*-
12
(defpackage :kiln-entry-point-system
2-
(:use :cl))
3+
(:use :cl)
4+
(:export :main))
35
(in-package :kiln-entry-point-system)
46

5-
(defun entry-point ()
6-
(format *error-output* "Hello, world"))
7+
(defun main ()
8+
(format t "Hello, world~%"))
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1+
;;; -*- mode: lisp -*-
12
(defpackage :other-test-system)

0 commit comments

Comments
 (0)