doc: Fix typos, and improve daemon documentation.
[jackhill/guix/guix.git] / guix / derivations.scm
CommitLineData
233e7676
LC
1;;; GNU Guix --- Functional package management for GNU
2;;; Copyright © 2012, 2013 Ludovic Courtès <ludo@gnu.org>
77d3cf08 3;;;
233e7676 4;;; This file is part of GNU Guix.
77d3cf08 5;;;
233e7676 6;;; GNU Guix is free software; you can redistribute it and/or modify it
77d3cf08
LC
7;;; under the terms of the GNU General Public License as published by
8;;; the Free Software Foundation; either version 3 of the License, or (at
9;;; your option) any later version.
10;;;
233e7676 11;;; GNU Guix is distributed in the hope that it will be useful, but
77d3cf08
LC
12;;; WITHOUT ANY WARRANTY; without even the implied warranty of
13;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14;;; GNU General Public License for more details.
15;;;
16;;; You should have received a copy of the GNU General Public License
233e7676 17;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
77d3cf08
LC
18
19(define-module (guix derivations)
20 #:use-module (srfi srfi-1)
21 #:use-module (srfi srfi-9)
22 #:use-module (srfi srfi-26)
23 #:use-module (rnrs io ports)
24 #:use-module (rnrs bytevectors)
25 #:use-module (ice-9 match)
26 #:use-module (ice-9 rdelim)
69f90f5c 27 #:use-module (guix store)
26bbbb95 28 #:use-module (guix utils)
ddc29a78 29 #:use-module (guix base32)
9a20830e
LC
30 #:export (<derivation>
31 derivation?
77d3cf08
LC
32 derivation-outputs
33 derivation-inputs
34 derivation-sources
35 derivation-system
36 derivation-builder-arguments
37 derivation-builder-environment-vars
9a20830e
LC
38 derivation-prerequisites
39 derivation-prerequisites-to-build
77d3cf08 40
9a20830e 41 <derivation-output>
77d3cf08
LC
42 derivation-output?
43 derivation-output-path
44 derivation-output-hash-algo
45 derivation-output-hash
46
9a20830e 47 <derivation-input>
77d3cf08
LC
48 derivation-input?
49 derivation-input-path
50 derivation-input-sub-derivations
51
52 fixed-output-derivation?
341c6fdd
LC
53 derivation-hash
54
55 read-derivation
26bbbb95 56 write-derivation
de4c3f26 57 derivation-path->output-path
7244a5f7 58 derivation-path->output-paths
d9085c23
LC
59 derivation
60
61 %guile-for-build
99634e3f
LC
62 build-expression->derivation
63 imported-files))
77d3cf08
LC
64
65;;;
66;;; Nix derivations, as implemented in Nix's `derivations.cc'.
67;;;
68
69(define-record-type <derivation>
70 (make-derivation outputs inputs sources system builder args env-vars)
71 derivation?
72 (outputs derivation-outputs) ; list of name/<derivation-output> pairs
73 (inputs derivation-inputs) ; list of <derivation-input>
74 (sources derivation-sources) ; list of store paths
75 (system derivation-system) ; string
76 (builder derivation-builder) ; store path
77 (args derivation-builder-arguments) ; list of strings
78 (env-vars derivation-builder-environment-vars)) ; list of name/value pairs
79
80(define-record-type <derivation-output>
81 (make-derivation-output path hash-algo hash)
82 derivation-output?
83 (path derivation-output-path) ; store path
84 (hash-algo derivation-output-hash-algo) ; symbol | #f
749c6567 85 (hash derivation-output-hash)) ; bytevector | #f
77d3cf08
LC
86
87(define-record-type <derivation-input>
88 (make-derivation-input path sub-derivations)
89 derivation-input?
90 (path derivation-input-path) ; store path
91 (sub-derivations derivation-input-sub-derivations)) ; list of strings
92
93(define (fixed-output-derivation? drv)
94 "Return #t if DRV is a fixed-output derivation, such as the result of a
95download with a fixed hash (aka. `fetchurl')."
96 (match drv
97 (($ <derivation>
98 (($ <derivation-output> _ (? symbol?) (? string?))))
99 #t)
100 (_ #f)))
101
9a20830e
LC
102(define (derivation-prerequisites drv)
103 "Return the list of derivation-inputs required to build DRV, recursively."
104 (let loop ((drv drv)
105 (result '()))
106 (let ((inputs (remove (cut member <> result) ; XXX: quadratic
107 (derivation-inputs drv))))
108 (fold loop
109 (append inputs result)
110 (map (lambda (i)
111 (call-with-input-file (derivation-input-path i)
112 read-derivation))
113 inputs)))))
114
784bb1f3
LC
115(define* (derivation-prerequisites-to-build store drv
116 #:key (outputs
117 (map
118 car
119 (derivation-outputs drv))))
120 "Return the list of derivation-inputs required to build the OUTPUTS of
121DRV and not already available in STORE, recursively."
122 (define built?
123 (cut valid-path? store <>))
124
9a20830e
LC
125 (define input-built?
126 (match-lambda
127 (($ <derivation-input> path sub-drvs)
128 (let ((out (map (cut derivation-path->output-path path <>)
129 sub-drvs)))
784bb1f3
LC
130 (any built? out)))))
131
132 (define (derivation-built? drv sub-drvs)
133 (match drv
134 (($ <derivation> outputs)
135 (let ((paths (map (lambda (sub-drv)
136 (derivation-output-path
137 (assoc-ref outputs sub-drv)))
138 sub-drvs)))
139 (every built? paths)))))
140
141 (let loop ((drv drv)
142 (sub-drvs outputs)
143 (result '()))
144 (if (derivation-built? drv sub-drvs)
145 result
146 (let ((inputs (remove (lambda (i)
147 (or (member i result) ; XXX: quadratic
148 (input-built? i)))
149 (derivation-inputs drv))))
150 (fold loop
151 (append inputs result)
152 (map (lambda (i)
153 (call-with-input-file (derivation-input-path i)
154 read-derivation))
155 inputs)
156 (map derivation-input-sub-derivations inputs))))))
9a20830e 157
77d3cf08
LC
158(define (read-derivation drv-port)
159 "Read the derivation from DRV-PORT and return the corresponding
160<derivation> object."
161
162 (define comma (string->symbol ","))
163
164 (define (ununquote x)
165 (match x
166 (('unquote x) (ununquote x))
167 ((x ...) (map ununquote x))
168 (_ x)))
169
170 (define (outputs->alist x)
171 (fold-right (lambda (output result)
172 (match output
173 ((name path "" "")
174 (alist-cons name
175 (make-derivation-output path #f #f)
176 result))
177 ((name path hash-algo hash)
178 ;; fixed-output
749c6567
LC
179 (let ((algo (string->symbol hash-algo))
180 (hash (base16-string->bytevector hash)))
77d3cf08
LC
181 (alist-cons name
182 (make-derivation-output path algo hash)
183 result)))))
184 '()
185 x))
186
187 (define (make-input-drvs x)
188 (fold-right (lambda (input result)
189 (match input
190 ((path (sub-drvs ...))
191 (cons (make-derivation-input path sub-drvs)
192 result))))
193 '()
194 x))
195
df7bbd38
LC
196 ;; The contents of a derivation are typically ASCII, but choosing
197 ;; UTF-8 allows us to take the fast path for Guile's `scm_getc'.
198 (set-port-encoding! drv-port "UTF-8")
199
77d3cf08
LC
200 (let loop ((exp (read drv-port))
201 (result '()))
202 (match exp
203 ((? eof-object?)
204 (let ((result (reverse result)))
205 (match result
206 (('Derive ((outputs ...) (input-drvs ...)
207 (input-srcs ...)
208 (? string? system)
209 (? string? builder)
210 ((? string? args) ...)
211 ((var value) ...)))
212 (make-derivation (outputs->alist outputs)
213 (make-input-drvs input-drvs)
214 input-srcs
215 system builder args
216 (fold-right alist-cons '() var value)))
217 (_
218 (error "failed to parse derivation" drv-port result)))))
219 ((? (cut eq? <> comma))
220 (loop (read drv-port) result))
221 (_
222 (loop (read drv-port)
223 (cons (ununquote exp) result))))))
224
225(define (write-derivation drv port)
226 "Write the ATerm-like serialization of DRV to PORT. See Section 2.4 of
227Eelco Dolstra's PhD dissertation for an overview of a previous version of
228that form."
aaa848f3
LC
229
230 ;; Make sure we're using the faster implementation.
231 (define format simple-format)
232
77d3cf08
LC
233 (define (list->string lst)
234 (string-append "[" (string-join lst ",") "]"))
235
236 (define (write-list lst)
237 (display (list->string lst) port))
238
d66ac374
LC
239 (define (coalesce-duplicate-inputs inputs)
240 ;; Return a list of inputs, such that when INPUTS contains the same DRV
241 ;; twice, they are coalesced, with their sub-derivations merged. This is
242 ;; needed because Nix itself keeps only one of them.
243 (fold (lambda (input result)
244 (match input
245 (($ <derivation-input> path sub-drvs)
246 ;; XXX: quadratic
247 (match (find (match-lambda
248 (($ <derivation-input> p s)
249 (string=? p path)))
250 result)
251 (#f
252 (cons input result))
253 ((and dup ($ <derivation-input> _ sub-drvs2))
254 ;; Merge DUP with INPUT.
255 (let ((sub-drvs (delete-duplicates
256 (append sub-drvs sub-drvs2))))
257 (cons (make-derivation-input path sub-drvs)
258 (delq dup result))))))))
259 '()
260 inputs))
261
561eaf71
LC
262 ;; Note: lists are sorted alphabetically, to conform with the behavior of
263 ;; C++ `std::map' in Nix itself.
264
77d3cf08
LC
265 (match drv
266 (($ <derivation> outputs inputs sources
267 system builder args env-vars)
268 (display "Derive(" port)
269 (write-list (map (match-lambda
270 ((name . ($ <derivation-output> path hash-algo hash))
271 (format #f "(~s,~s,~s,~s)"
749c6567
LC
272 name path
273 (or (and=> hash-algo symbol->string) "")
274 (or (and=> hash bytevector->base16-string)
275 ""))))
561eaf71
LC
276 (sort outputs
277 (lambda (o1 o2)
278 (string<? (car o1) (car o2))))))
77d3cf08
LC
279 (display "," port)
280 (write-list (map (match-lambda
281 (($ <derivation-input> path sub-drvs)
282 (format #f "(~s,~a)" path
561eaf71
LC
283 (list->string (map object->string
284 (sort sub-drvs string<?))))))
d66ac374 285 (sort (coalesce-duplicate-inputs inputs)
561eaf71
LC
286 (lambda (i1 i2)
287 (string<? (derivation-input-path i1)
288 (derivation-input-path i2))))))
77d3cf08 289 (display "," port)
561eaf71 290 (write-list (map object->string (sort sources string<?)))
77d3cf08
LC
291 (format port ",~s,~s," system builder)
292 (write-list (map object->string args))
293 (display "," port)
294 (write-list (map (match-lambda
295 ((name . value)
296 (format #f "(~s,~s)" name value)))
561eaf71
LC
297 (sort env-vars
298 (lambda (e1 e2)
299 (string<? (car e1) (car e2))))))
77d3cf08
LC
300 (display ")" port))))
301
aaa848f3
LC
302(define derivation-path->output-path
303 ;; This procedure is called frequently, so memoize it.
304 (memoize
305 (lambda* (path #:optional (output "out"))
306 "Read the derivation from PATH (`/nix/store/xxx.drv'), and return the store
de4c3f26 307path of its output OUTPUT."
aaa848f3
LC
308 (let* ((drv (call-with-input-file path read-derivation))
309 (outputs (derivation-outputs drv)))
310 (and=> (assoc-ref outputs output) derivation-output-path)))))
de4c3f26 311
7244a5f7
LC
312(define (derivation-path->output-paths path)
313 "Read the derivation from PATH (`/nix/store/xxx.drv'), and return the
314list of name/path pairs of its outputs."
315 (let* ((drv (call-with-input-file path read-derivation))
316 (outputs (derivation-outputs drv)))
317 (map (match-lambda
318 ((name . output)
319 (cons name (derivation-output-path output))))
320 outputs)))
321
de4c3f26
LC
322\f
323;;;
324;;; Derivation primitive.
325;;;
326
26bbbb95
LC
327(define (compressed-hash bv size) ; `compressHash'
328 "Given the hash stored in BV, return a compressed version thereof that fits
329in SIZE bytes."
330 (define new (make-bytevector size 0))
331 (define old-size (bytevector-length bv))
332 (let loop ((i 0))
333 (if (= i old-size)
334 new
335 (let* ((j (modulo i size))
336 (o (bytevector-u8-ref new j)))
337 (bytevector-u8-set! new j
338 (logxor o (bytevector-u8-ref bv i)))
339 (loop (+ 1 i))))))
77d3cf08 340
de4c3f26
LC
341(define derivation-hash ; `hashDerivationModulo' in derivations.cc
342 (memoize
343 (lambda (drv)
344 "Return the hash of DRV, modulo its fixed-output inputs, as a bytevector."
345 (match drv
346 (($ <derivation> ((_ . ($ <derivation-output> path
749c6567 347 (? symbol? hash-algo) (? bytevector? hash)))))
de4c3f26 348 ;; A fixed-output derivation.
77d3cf08 349 (sha256
de4c3f26
LC
350 (string->utf8
351 (string-append "fixed:out:" (symbol->string hash-algo)
749c6567
LC
352 ":" (bytevector->base16-string hash)
353 ":" path))))
de4c3f26
LC
354 (($ <derivation> outputs inputs sources
355 system builder args env-vars)
356 ;; A regular derivation: replace the path of each input with that
357 ;; input's hash; return the hash of serialization of the resulting
561eaf71
LC
358 ;; derivation.
359 (let* ((inputs (map (match-lambda
360 (($ <derivation-input> path sub-drvs)
361 (let ((hash (call-with-input-file path
362 (compose bytevector->base16-string
363 derivation-hash
364 read-derivation))))
365 (make-derivation-input hash sub-drvs))))
366 inputs))
367 (drv (make-derivation outputs inputs sources
368 system builder args env-vars)))
de4c3f26
LC
369 (sha256
370 (string->utf8 (call-with-output-string
371 (cut write-derivation drv <>))))))))))
77d3cf08 372
26bbbb95
LC
373(define (store-path type hash name) ; makeStorePath
374 "Return the store path for NAME/HASH/TYPE."
375 (let* ((s (string-append type ":sha256:"
376 (bytevector->base16-string hash) ":"
377 (%store-prefix) ":" name))
378 (h (sha256 (string->utf8 s)))
379 (c (compressed-hash h 20)))
380 (string-append (%store-prefix) "/"
381 (bytevector->nix-base32-string c) "-"
382 name)))
383
384(define (output-path output hash name) ; makeOutputPath
385 "Return an output path for OUTPUT (the name of the output as a string) of
386the derivation called NAME with hash HASH."
387 (store-path (string-append "output:" output) hash
388 (if (string=? output "out")
389 name
390 (string-append name "-" output))))
391
392(define* (derivation store name system builder args env-vars inputs
393 #:key (outputs '("out")) hash hash-algo hash-mode)
394 "Build a derivation with the given arguments. Return the resulting
fb3eec83 395store path and <derivation> object. When HASH, HASH-ALGO, and HASH-MODE
26bbbb95
LC
396are given, a fixed-output derivation is created---i.e., one whose result is
397known in advance, such as a file download."
200dc937
LC
398 (define direct-store-path?
399 (let ((len (+ 1 (string-length (%store-prefix)))))
400 (lambda (p)
401 ;; Return #t if P is a store path, and not a sub-directory of a
402 ;; store path. This predicate is needed because files *under* a
403 ;; store path are not valid inputs.
404 (and (store-path? p)
405 (not (string-index (substring p len) #\/))))))
406
26bbbb95
LC
407 (define (add-output-paths drv)
408 ;; Return DRV with an actual store path for each of its output and the
409 ;; corresponding environment variable.
410 (match drv
411 (($ <derivation> outputs inputs sources
412 system builder args env-vars)
413 (let* ((drv-hash (derivation-hash drv))
414 (outputs (map (match-lambda
d9085c23
LC
415 ((output-name . ($ <derivation-output>
416 _ algo hash))
417 (let ((path (output-path output-name
418 drv-hash name)))
419 (cons output-name
420 (make-derivation-output path algo
421 hash)))))
422 outputs)))
26bbbb95
LC
423 (make-derivation outputs inputs sources system builder args
424 (map (match-lambda
425 ((name . value)
426 (cons name
427 (or (and=> (assoc-ref outputs name)
428 derivation-output-path)
429 value))))
430 env-vars))))))
431
432 (define (env-vars-with-empty-outputs)
433 ;; Return a variant of ENV-VARS where each OUTPUTS is associated with an
561eaf71 434 ;; empty string, even outputs that do not appear in ENV-VARS.
26bbbb95
LC
435 (let ((e (map (match-lambda
436 ((name . val)
437 (if (member name outputs)
438 (cons name "")
439 (cons name val))))
440 env-vars)))
561eaf71
LC
441 (fold (lambda (output-name env-vars)
442 (if (assoc output-name env-vars)
443 env-vars
444 (append env-vars `((,output-name . "")))))
445 e
446 outputs)))
26bbbb95
LC
447
448 (let* ((outputs (map (lambda (name)
449 ;; Return outputs with an empty path.
450 (cons name
451 (make-derivation-output "" hash-algo hash)))
452 outputs))
453 (inputs (map (match-lambda
200dc937 454 (((? direct-store-path? input))
de4c3f26 455 (make-derivation-input input '("out")))
200dc937 456 (((? direct-store-path? input) sub-drvs ...)
26bbbb95
LC
457 (make-derivation-input input sub-drvs))
458 ((input . _)
459 (let ((path (add-to-store store
460 (basename input)
860a6f1a 461 #t #t "sha256" input)))
26bbbb95 462 (make-derivation-input path '()))))
d26ad5e4 463 (delete-duplicates inputs)))
26bbbb95
LC
464 (env-vars (env-vars-with-empty-outputs))
465 (drv-masked (make-derivation outputs
466 (filter (compose derivation-path?
467 derivation-input-path)
468 inputs)
469 (filter-map (lambda (i)
470 (let ((p (derivation-input-path i)))
471 (and (not (derivation-path? p))
472 p)))
473 inputs)
474 system builder args env-vars))
475 (drv (add-output-paths drv-masked)))
de4c3f26 476
d66ac374
LC
477 ;; (write-derivation drv-masked (current-error-port))
478 ;; (newline (current-error-port))
fb3eec83
LC
479 (values (add-text-to-store store (string-append name ".drv")
480 (call-with-output-string
481 (cut write-derivation drv <>))
482 (map derivation-input-path
483 inputs))
484 drv)))
d9085c23
LC
485
486\f
487;;;
488;;; Guile-based builders.
489;;;
490
491(define %guile-for-build
492 ;; The derivation of the Guile to be used within the build environment,
493 ;; when using `build-expression->derivation'.
b272c474 494 (make-parameter #f))
d9085c23 495
d9024884
LC
496(define (parent-directories file-name)
497 "Return the list of parent dirs of FILE-NAME, in the order in which an
498`mkdir -p' implementation would make them."
499 (let ((not-slash (char-set-complement (char-set #\/))))
500 (reverse
501 (fold (lambda (dir result)
502 (match result
503 (()
504 (list dir))
505 ((prev _ ...)
506 (cons (string-append prev "/" dir)
507 result))))
508 '()
509 (remove (cut string=? <> ".")
510 (string-tokenize (dirname file-name) not-slash))))))
511
99634e3f 512(define* (imported-files store files
b272c474
LC
513 #:key (name "file-import")
514 (system (%current-system))
515 (guile (%guile-for-build)))
99634e3f
LC
516 "Return a derivation that imports FILES into STORE. FILES must be a list
517of (FINAL-PATH . FILE-NAME) pairs; each FILE-NAME is read from the file
518system, imported, and appears under FINAL-PATH in the resulting store path."
99634e3f
LC
519 (let* ((files (map (match-lambda
520 ((final-path . file-name)
2acb2cb6 521 (list final-path
99634e3f
LC
522 (add-to-store store (basename final-path) #t #f
523 "sha256" file-name))))
524 files))
525 (builder
526 `(begin
527 (mkdir %output) (chdir %output)
528 ,@(append-map (match-lambda
2acb2cb6 529 ((final-path store-path)
d9024884 530 (append (match (parent-directories final-path)
99634e3f
LC
531 (() '())
532 ((head ... tail)
533 (append (map (lambda (d)
534 `(false-if-exception
535 (mkdir ,d)))
536 head)
224f7ad6
LC
537 `((or (file-exists? ,tail)
538 (mkdir ,tail))))))
99634e3f
LC
539 `((symlink ,store-path ,final-path)))))
540 files))))
ae39d1b2 541 (build-expression->derivation store name system
b272c474
LC
542 builder files
543 #:guile-for-build guile)))
99634e3f 544
3eb98237
LC
545(define* (imported-modules store modules
546 #:key (name "module-import")
b272c474
LC
547 (system (%current-system))
548 (guile (%guile-for-build)))
3eb98237
LC
549 "Return a derivation that contains the source files of MODULES, a list of
550module names such as `(ice-9 q)'. All of MODULES must be in the current
551search path."
552 ;; TODO: Determine the closure of MODULES, build the `.go' files,
553 ;; canonicalize the source files through read/write, etc.
554 (let ((files (map (lambda (m)
555 (let ((f (string-append
556 (string-join (map symbol->string m) "/")
557 ".scm")))
558 (cons f (search-path %load-path f))))
559 modules)))
b272c474
LC
560 (imported-files store files #:name name #:system system
561 #:guile guile)))
3eb98237 562
d9024884
LC
563(define* (compiled-modules store modules
564 #:key (name "module-import-compiled")
b272c474
LC
565 (system (%current-system))
566 (guile (%guile-for-build)))
d9024884
LC
567 "Return a derivation that builds a tree containing the `.go' files
568corresponding to MODULES. All the MODULES are built in a context where
569they can refer to each other."
570 (let* ((module-drv (imported-modules store modules
b272c474
LC
571 #:system system
572 #:guile guile))
d9024884
LC
573 (module-dir (derivation-path->output-path module-drv))
574 (files (map (lambda (m)
575 (let ((f (string-join (map symbol->string m)
576 "/")))
577 (cons (string-append f ".go")
578 (string-append module-dir "/" f ".scm"))))
579 modules)))
580 (define builder
581 `(begin
582 (use-modules (system base compile))
583 (let ((out (assoc-ref %outputs "out")))
584 (mkdir out)
585 (chdir out))
586
587 (set! %load-path
588 (cons ,module-dir %load-path))
589
590 ,@(map (match-lambda
591 ((output . input)
592 (let ((make-parent-dirs (map (lambda (dir)
593 `(unless (file-exists? ,dir)
594 (mkdir ,dir)))
595 (parent-directories output))))
596 `(begin
597 ,@make-parent-dirs
598 (compile-file ,input
599 #:output-file ,output
600 #:opts %auto-compilation-options)))))
601 files)))
602
603 (build-expression->derivation store name system builder
b272c474
LC
604 `(("modules" ,module-drv))
605 #:guile-for-build guile)))
3eb98237 606
d9085c23 607(define* (build-expression->derivation store name system exp inputs
9bc07f4d 608 #:key (outputs '("out"))
3eb98237 609 hash hash-algo
4c1eddf7 610 (env-vars '())
6dd7787c
LC
611 (modules '())
612 guile-for-build)
d9085c23 613 "Return a derivation that executes Scheme expression EXP as a builder for
2acb2cb6
LC
614derivation NAME. INPUTS must be a list of (NAME DRV-PATH SUB-DRV) tuples;
615when SUB-DRV is omitted, \"out\" is assumed. EXP is evaluated in an
616environment where %OUTPUT is bound to the main output path, %OUTPUTS is bound
617to a list of output/path pairs, and where %BUILD-INPUTS is bound to an alist
4c1eddf7
LC
618of string/output-path pairs made from INPUTS. Optionally, ENV-VARS is a list
619of string pairs specifying the name and value of environment variables
620visible to the builder. The builder terminates by passing the result of EXP
621to `exit'; thus, when EXP returns #f, the build is considered to have
6dd7787c
LC
622failed.
623
624EXP is built using GUILE-FOR-BUILD (a derivation). When GUILE-FOR-BUILD is
625omitted or is #f, the value of the `%guile-for-build' fluid is used instead."
b272c474
LC
626 (define guile-drv
627 (or guile-for-build (%guile-for-build)))
628
d9085c23 629 (define guile
b272c474 630 (string-append (derivation-path->output-path guile-drv)
d9085c23
LC
631 "/bin/guile"))
632
0d56a551
LC
633 (define module-form?
634 (match-lambda
635 (((or 'define-module 'use-modules) _ ...) #t)
636 (_ #f)))
637
7bdd1f0e
LC
638 (define source-path
639 ;; When passed an input that is a source, return its path; otherwise
640 ;; return #f.
641 (match-lambda
642 ((_ path _ ...)
643 (and (not (derivation-path? path))
644 path))))
645
d9085c23 646 (let* ((prologue `(begin
0d56a551
LC
647 ,@(match exp
648 ((_ ...)
649 ;; Module forms must appear at the top-level so
650 ;; that any macros they export can be expanded.
651 (filter module-form? exp))
652 (_ `(,exp)))
653
d9085c23 654 (define %output (getenv "out"))
9bc07f4d
LC
655 (define %outputs
656 (map (lambda (o)
657 (cons o (getenv o)))
658 ',outputs))
d9085c23
LC
659 (define %build-inputs
660 ',(map (match-lambda
2acb2cb6
LC
661 ((name drv . rest)
662 (let ((sub (match rest
663 (() "out")
664 ((x) x))))
665 (cons name
666 (if (derivation-path? drv)
667 (derivation-path->output-path drv
668 sub)
669 drv)))))
d44bc84b
LC
670 inputs))
671
d9024884
LC
672 ,@(if (null? modules)
673 '()
674 ;; Remove our own settings.
675 '((unsetenv "GUILE_LOAD_COMPILED_PATH")))
676
d44bc84b
LC
677 ;; Guile sets it, but remove it to avoid conflicts when
678 ;; building Guile-using packages.
679 (unsetenv "LD_LIBRARY_PATH")))
d9085c23
LC
680 (builder (add-text-to-store store
681 (string-append name "-guile-builder")
0d56a551
LC
682 (string-append
683 (object->string prologue)
684 (object->string
685 `(exit
686 ,(match exp
687 ((_ ...)
688 (remove module-form? exp))
689 (_ `(,exp))))))
7bdd1f0e
LC
690
691 ;; The references don't really matter
692 ;; since the builder is always used in
693 ;; conjunction with the drv that needs
694 ;; it. For clarity, we add references
695 ;; to the subset of INPUTS that are
696 ;; sources, avoiding references to other
697 ;; .drv; otherwise, BUILDER's hash would
698 ;; depend on those, even if they are
699 ;; fixed-output.
700 (filter-map source-path inputs)))
701
d9024884 702 (mod-drv (and (pair? modules)
ae39d1b2
LC
703 (imported-modules store modules
704 #:guile guile-drv
705 #:system system)))
3eb98237 706 (mod-dir (and mod-drv
d9024884
LC
707 (derivation-path->output-path mod-drv)))
708 (go-drv (and (pair? modules)
ae39d1b2
LC
709 (compiled-modules store modules
710 #:guile guile-drv
711 #:system system)))
d9024884
LC
712 (go-dir (and go-drv
713 (derivation-path->output-path go-drv))))
3eb98237
LC
714 (derivation store name system guile
715 `("--no-auto-compile"
716 ,@(if mod-dir `("-L" ,mod-dir) '())
717 ,builder)
d9024884
LC
718
719 ;; When MODULES is non-empty, shamelessly clobber
720 ;; $GUILE_LOAD_COMPILED_PATH.
721 (if go-dir
722 `(("GUILE_LOAD_COMPILED_PATH" . ,go-dir)
723 ,@(alist-delete "GUILE_LOAD_COMPILED_PATH"
724 env-vars))
725 env-vars)
726
6dd7787c 727 `((,(or guile-for-build (%guile-for-build)))
3eb98237 728 (,builder)
2acb2cb6 729 ,@(map cdr inputs)
d9024884 730 ,@(if mod-drv `((,mod-drv) (,go-drv)) '()))
9bc07f4d
LC
731 #:hash hash #:hash-algo hash-algo
732 #:outputs outputs)))