-
-
Notifications
You must be signed in to change notification settings - Fork 29
/
Copy pathimage.zuo
186 lines (168 loc) · 7.07 KB
/
image.zuo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
#lang zuo
;; This module works in three modes:
;; * as a library to provide `embed-image`
;; - that's the `embed-image` provided function, obviously
;; * as a script that parses command-line arguments to drive `embed-image`
;; - that's the `(module+ main ...)` below
;; * as a build component that provides a target to drive `embed-image`
;; - that's the `image-target` provided function, which takes
;; the same hash-table specification as `embed-image`, but returns a
;; target instead of immediately generating output
(provide embed-image ; hash? -> void?
image-target) ; hash? -> target?
;; `embed-image` recognizes the following keys in its argument:
;;
;; * 'output : #f or destination path string; #f (default) means to stdout
;;
;; * 'libs: list of module-path symbols; default is '(zuo)
;;
;; * 'image-file: an existing image, causing 'libs to be ignored;
;; default is #f
;;
;; * 'deps: a file to record files reda to create the image; presence
;; along with non-#f 'output enables a potetial 'up-to-date result
;;
;; * 'keep-collects?: boolean for whether to keep the collection library
;; path enabled; default is #f
(module+ main
(define cmd
(command-line
:once-each
[cmd "-o" file "Output to <file> instead of stdout"
(hash-set cmd 'output file)]
:multi
[cmd "++lib" module-path "Embed <module-path> and its dependencies"
(hash-set cmd 'libs (cons (string->symbol module-path)
(hash-ref cmd 'libs '())))]
:once-each
[cmd "--image" file "Use <file> instead of creating a new image"
(hash-set cmd 'image-file file)]
[cmd "--deps" file "Write dependencies to <file>"
(hash-set cmd 'deps file)]
[cmd "--keep-collects" "Keep library collection path enabled"
(hash-set cmd 'keep-collects? #t)]))
(embed-image cmd))
(define (image-target cmd)
(target
(hash-ref cmd 'output) ; the output file; `target` uses SHA-256 on this
(lambda (path token)
;; when a target is demanded, we report dependencies and more via `rule`
(rule
;; dependencies:
(list (at-source ".." "zuo.c") ; original "zuo.c" that is converted to embed libraries
(quote-module-path) ; this script
(input-data-target 'config (hash-remove cmd 'output))) ; configuration
;; rebuild function (called if the output file is out of date):
(lambda ()
;; get `embed-image` to tell us which module files it used:
(define deps-file (path-replace-extension path ".dep"))
;; generated the output file
(embed-image (let* ([cmd (hash-set cmd 'output path)]
[cmd (hash-set cmd 'deps deps-file)])
cmd))
;; register each source module as a discovered dependency:
(for-each (lambda (p) (build/dep p token))
(string-read (file->string deps-file) 0 deps-file)))))))
(define (embed-image cmd)
(define given-libs (hash-ref cmd 'libs '()))
(define libs (if (null? given-libs)
'(zuo)
given-libs))
(define deps-file (hash-ref cmd 'deps #f))
(define c-file (hash-ref cmd 'output #f))
(define image-file (hash-ref cmd 'image-file #f))
(when (and image-file (pair? given-libs))
(error "Don't provide both libraries and an image file"))
(when c-file
(if image-file
(displayln (~a "generating " c-file " embedding " (~s image-file)))
(displayln (~a "generating " c-file " embedding these libraries: " (string-join (map ~s libs))))))
(when deps-file
(display-to-file "" deps-file :truncate))
(define deps-h (and deps-file (cleanable-file deps-file)))
(define image
(cond
[image-file
(define in (fd-open-input image-file))
(define image (fd-read in eof))
(fd-close in)
image]
[else
(let ([ht (apply process
(append
(list (hash-ref (runtime-env) 'exe))
(if deps-file
(list "-M" deps-file)
(list))
(list "" (hash 'stdin 'pipe 'stdout 'pipe))))])
(define p (hash-ref ht 'process))
(define in (hash-ref ht 'stdin))
(define out (hash-ref ht 'stdout))
(fd-write in "#lang zuo/kernel\n")
(fd-write in "(begin\n")
(for-each (lambda (lib)
(fd-write in (~a "(module->hash '" lib ")\n")))
libs)
(fd-write in "(dump-image-and-exit (fd-open-output 'stdout (hash))))\n")
(fd-close in)
(let ([image (fd-read out eof)])
(fd-close out)
(process-wait p)
(unless (= 0 (process-status p))
(error "image dump failed"))
image))]))
(define zuo.c (fd-read (fd-open-input (at-source ".." "zuo.c")) eof))
(define out (if c-file
(fd-open-output c-file (hash 'exists 'truncate))
(fd-open-output 'stdout (hash))))
(define lines (let ([l (reverse (string-split zuo.c "\n"))])
;; splitting on newlines should leave us with an empty last string
;; that doesn't represent a line
(reverse (if (and (pair? l) (equal? "" (car l)))
(cdr l)
l))))
(define (~hex v)
(if (= v 0)
"0"
(let loop ([v v] [accum '()])
(if (= v 0)
(apply ~a accum)
(loop (quotient v 16)
(cons (let ([i (bitwise-and v 15)])
(substring "0123456789abcdef" i (+ i 1)))
accum))))))
(define embedded-image-line "#define EMBEDDED_IMAGE 0")
(define embedded-image-line/cr (~a embedded-image-line "\r"))
(for-each
(lambda (line)
(cond
[(or (string=? line embedded-image-line)
(string=? line embedded-image-line/cr))
(define nl (if (string=? line embedded-image-line/cr) "\r\n" "\n"))
(unless (hash-ref cmd 'keep-collects? #f)
(fd-write out (~a "#define ZUO_LIB_PATH NULL" nl)))
(fd-write out (~a "#define EMBEDDED_IMAGE 1" nl))
(fd-write out (~a "static zuo_uint32_t emedded_boot_image_len = "
(quotient (string-length image) 4)
";" nl))
(fd-write out (~a "static zuo_uint32_t emedded_boot_image[] = {" nl))
(let ([accum->line (lambda (accum) (apply ~a (reverse (cons nl accum))))])
(let loop ([i 0] [col 0] [accum '()])
(cond
[(= i (string-length image))
(unless (null? accum)
(fd-write out (accum->line accum)))]
[(= col 8)
(fd-write out (accum->line accum))
(loop i 0 '())]
[else
(loop (+ i 4) (+ col 1)
(cons (~a " 0x" (~hex (string-u32-ref image i)) ",")
accum))])))
(fd-write out (~a " 0 };" nl))]
[else
(fd-write out (~a line "\n"))]))
lines)
(when c-file (fd-close out))
(when deps-h
(cleanable-cancel deps-h)))