derivations: Split 'derivation-hash' in two procedures.
[jackhill/guix/guix.git] / guix / derivations.scm
CommitLineData
233e7676 1;;; GNU Guix --- Functional package management for GNU
6d943e55 2;;; Copyright © 2012, 2013, 2014, 2015, 2016, 2017 Ludovic Courtès <ludo@gnu.org>
dc673fa1 3;;; Copyright © 2016, 2017 Mathieu Lirzin <mthl@gnu.org>
77d3cf08 4;;;
233e7676 5;;; This file is part of GNU Guix.
77d3cf08 6;;;
233e7676 7;;; GNU Guix is free software; you can redistribute it and/or modify it
77d3cf08
LC
8;;; under the terms of the GNU General Public License as published by
9;;; the Free Software Foundation; either version 3 of the License, or (at
10;;; your option) any later version.
11;;;
233e7676 12;;; GNU Guix is distributed in the hope that it will be useful, but
77d3cf08
LC
13;;; WITHOUT ANY WARRANTY; without even the implied warranty of
14;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15;;; GNU General Public License for more details.
16;;;
17;;; You should have received a copy of the GNU General Public License
233e7676 18;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
77d3cf08
LC
19
20(define-module (guix derivations)
21 #:use-module (srfi srfi-1)
22 #:use-module (srfi srfi-9)
07c86312 23 #:use-module (srfi srfi-9 gnu)
77d3cf08 24 #:use-module (srfi srfi-26)
f304c9c2
LC
25 #:use-module (srfi srfi-34)
26 #:use-module (srfi srfi-35)
2535635f 27 #:use-module (ice-9 binary-ports)
77d3cf08
LC
28 #:use-module (rnrs bytevectors)
29 #:use-module (ice-9 match)
30 #:use-module (ice-9 rdelim)
e387ab7c 31 #:use-module (ice-9 vlist)
69f90f5c 32 #:use-module (guix store)
26bbbb95 33 #:use-module (guix utils)
4c0c4db0 34 #:use-module (guix base16)
f9704f17 35 #:use-module (guix memoization)
958dd3ce 36 #:use-module (guix combinators)
e87f0591 37 #:use-module (guix monads)
72626a71 38 #:use-module (guix hash)
ddc29a78 39 #:use-module (guix base32)
969df974 40 #:use-module (guix records)
ed3592a9 41 #:use-module (guix sets)
9a20830e
LC
42 #:export (<derivation>
43 derivation?
77d3cf08
LC
44 derivation-outputs
45 derivation-inputs
46 derivation-sources
47 derivation-system
7ce7361b 48 derivation-builder
77d3cf08
LC
49 derivation-builder-arguments
50 derivation-builder-environment-vars
6a446d56 51 derivation-file-name
9a20830e
LC
52 derivation-prerequisites
53 derivation-prerequisites-to-build
77d3cf08 54
9a20830e 55 <derivation-output>
77d3cf08
LC
56 derivation-output?
57 derivation-output-path
58 derivation-output-hash-algo
59 derivation-output-hash
36bbbbd1 60 derivation-output-recursive?
77d3cf08 61
9a20830e 62 <derivation-input>
77d3cf08
LC
63 derivation-input?
64 derivation-input-path
65 derivation-input-sub-derivations
dd36b51b 66 derivation-input-output-paths
3681db5d 67 valid-derivation-input?
77d3cf08 68
f304c9c2
LC
69 &derivation-error
70 derivation-error?
71 derivation-error-derivation
72 &derivation-missing-output-error
73 derivation-missing-output-error?
74 derivation-missing-output
75
e786293e 76 derivation-name
0b6af195 77 derivation-output-names
77d3cf08 78 fixed-output-derivation?
fc93e309
LC
79 offloadable-derivation?
80 substitutable-derivation?
e9651e39 81 substitution-oracle
341c6fdd
LC
82 derivation-hash
83
84 read-derivation
015f17e8 85 read-derivation-from-file
26bbbb95 86 write-derivation
59688fc4
LC
87 derivation->output-path
88 derivation->output-paths
de4c3f26 89 derivation-path->output-path
7244a5f7 90 derivation-path->output-paths
d9085c23 91 derivation
713335fa 92 raw-derivation
969df974 93
e387ab7c 94 map-derivation
d9085c23 95
01d8ac64 96 build-derivations
e87f0591 97 built-derivations
e87f0591 98
d26e1967
LC
99 file-search-error?
100 file-search-error-file-name
101 file-search-error-search-path
9d8100f4 102
d26e1967 103 search-path*
6985335f 104 module->source-file-name
aa72d9af 105 build-expression->derivation)
e87f0591
LC
106
107 ;; Re-export it from here for backward compatibility.
01d8ac64 108 #:re-export (%guile-for-build))
77d3cf08 109
f304c9c2
LC
110;;;
111;;; Error conditions.
112;;;
113
114(define-condition-type &derivation-error &nix-error
115 derivation-error?
116 (derivation derivation-error-derivation))
117
118(define-condition-type &derivation-missing-output-error &derivation-error
119 derivation-missing-output-error?
120 (output derivation-missing-output))
121
77d3cf08
LC
122;;;
123;;; Nix derivations, as implemented in Nix's `derivations.cc'.
124;;;
125
dc673fa1 126(define-immutable-record-type <derivation>
6a446d56
LC
127 (make-derivation outputs inputs sources system builder args env-vars
128 file-name)
77d3cf08
LC
129 derivation?
130 (outputs derivation-outputs) ; list of name/<derivation-output> pairs
131 (inputs derivation-inputs) ; list of <derivation-input>
132 (sources derivation-sources) ; list of store paths
133 (system derivation-system) ; string
134 (builder derivation-builder) ; store path
135 (args derivation-builder-arguments) ; list of strings
6a446d56
LC
136 (env-vars derivation-builder-environment-vars) ; list of name/value pairs
137 (file-name derivation-file-name)) ; the .drv file name
77d3cf08 138
3d19b7fb 139(define-immutable-record-type <derivation-output>
36bbbbd1 140 (make-derivation-output path hash-algo hash recursive?)
77d3cf08
LC
141 derivation-output?
142 (path derivation-output-path) ; store path
143 (hash-algo derivation-output-hash-algo) ; symbol | #f
36bbbbd1
LC
144 (hash derivation-output-hash) ; bytevector | #f
145 (recursive? derivation-output-recursive?)) ; Boolean
77d3cf08 146
3d19b7fb 147(define-immutable-record-type <derivation-input>
77d3cf08
LC
148 (make-derivation-input path sub-derivations)
149 derivation-input?
150 (path derivation-input-path) ; store path
151 (sub-derivations derivation-input-sub-derivations)) ; list of strings
152
07c86312
LC
153(set-record-type-printer! <derivation>
154 (lambda (drv port)
155 (format port "#<derivation ~a => ~a ~a>"
156 (derivation-file-name drv)
157 (string-join
158 (map (match-lambda
159 ((_ . output)
160 (derivation-output-path output)))
161 (derivation-outputs drv)))
162 (number->string (object-address drv) 16))))
163
e786293e
LC
164(define (derivation-name drv)
165 "Return the base name of DRV."
166 (let ((base (store-path-package-name (derivation-file-name drv))))
167 (string-drop-right base 4)))
168
0b6af195
LC
169(define (derivation-output-names drv)
170 "Return the names of the outputs of DRV."
171 (match (derivation-outputs drv)
172 (((names . _) ...)
173 names)))
174
77d3cf08
LC
175(define (fixed-output-derivation? drv)
176 "Return #t if DRV is a fixed-output derivation, such as the result of a
177download with a fixed hash (aka. `fetchurl')."
178 (match drv
179 (($ <derivation>
99e17dc9 180 (("out" . ($ <derivation-output> _ (? symbol?) (? bytevector?)))))
77d3cf08
LC
181 #t)
182 (_ #f)))
183
97507ebe
LC
184(define (derivation-input<? input1 input2)
185 "Compare INPUT1 and INPUT2, two <derivation-input>."
186 (string<? (derivation-input-path input1)
187 (derivation-input-path input2)))
188
dd36b51b
LC
189(define (derivation-input-output-paths input)
190 "Return the list of output paths corresponding to INPUT, a
191<derivation-input>."
192 (match input
193 (($ <derivation-input> path sub-drvs)
194 (map (cut derivation-path->output-path path <>)
195 sub-drvs))))
196
3681db5d
LC
197(define (valid-derivation-input? store input)
198 "Return true if INPUT is valid--i.e., if all the outputs it requests are in
199the store."
200 (every (cut valid-path? store <>)
201 (derivation-input-output-paths input)))
202
97507ebe
LC
203(define (coalesce-duplicate-inputs inputs)
204 "Return a list of inputs, such that when INPUTS contains the same DRV twice,
205they are coalesced, with their sub-derivations merged. This is needed because
206Nix itself keeps only one of them."
207 (fold (lambda (input result)
208 (match input
209 (($ <derivation-input> path sub-drvs)
210 ;; XXX: quadratic
211 (match (find (match-lambda
212 (($ <derivation-input> p s)
213 (string=? p path)))
214 result)
215 (#f
216 (cons input result))
217 ((and dup ($ <derivation-input> _ sub-drvs2))
218 ;; Merge DUP with INPUT.
219 (let ((sub-drvs (delete-duplicates
220 (append sub-drvs sub-drvs2))))
221 (cons (make-derivation-input path
222 (sort sub-drvs string<?))
223 (delq dup result))))))))
224 '()
225 inputs))
226
3681db5d
LC
227(define* (derivation-prerequisites drv #:optional (cut? (const #f)))
228 "Return the list of derivation-inputs required to build DRV, recursively.
229
230CUT? is a predicate that is passed a derivation-input and returns true to
231eliminate the given input and its dependencies from the search. An example of
232search a predicate is 'valid-derivation-input?'; when it is used as CUT?, the
233result is the set of prerequisites of DRV not already in valid."
ed3592a9
LC
234 (let loop ((drv drv)
235 (result '())
236 (input-set (set)))
3681db5d
LC
237 (let ((inputs (remove (lambda (input)
238 (or (set-contains? input-set input)
239 (cut? input)))
9a20830e 240 (derivation-inputs drv))))
ed3592a9
LC
241 (fold2 loop
242 (append inputs result)
243 (fold set-insert input-set inputs)
244 (map (lambda (i)
015f17e8 245 (read-derivation-from-file (derivation-input-path i)))
ed3592a9 246 inputs)))))
9a20830e 247
fc93e309
LC
248(define (offloadable-derivation? drv)
249 "Return true if DRV can be offloaded, false otherwise."
250 (match (assoc "preferLocalBuild"
251 (derivation-builder-environment-vars drv))
252 (("preferLocalBuild" . "1") #f)
253 (_ #t)))
254
4a6aeb67
LC
255(define (substitutable-derivation? drv)
256 "Return #t if DRV can be substituted."
257 (match (assoc "allowSubstitutes"
258 (derivation-builder-environment-vars drv))
259 (("allowSubstitutes" . value)
260 (string=? value "1"))
261 (_ #t)))
fc93e309 262
e9651e39
LC
263(define (derivation-output-paths drv sub-drvs)
264 "Return the output paths of outputs SUB-DRVS of DRV."
265 (match drv
266 (($ <derivation> outputs)
267 (map (lambda (sub-drv)
268 (derivation-output-path (assoc-ref outputs sub-drv)))
269 sub-drvs))))
270
58c08df0
LC
271(define* (substitution-oracle store drv
272 #:key (mode (build-mode normal)))
e9651e39 273 "Return a one-argument procedure that, when passed a store file name,
ef51ac21
LC
274returns a 'substitutable?' if it's substitutable and #f otherwise.
275The returned procedure
1eabf4ec
LC
276knows about all substitutes for all the derivations listed in DRV, *except*
277those that are already valid (that is, it won't bother checking whether an
278item is substitutable if it's already on disk); it also knows about their
279prerequisites, unless they are themselves substitutable.
e9651e39 280
ef51ac21 281Creating a single oracle (thus making a single 'substitutable-path-info' call) and
e9651e39
LC
282reusing it is much more efficient than calling 'has-substitutes?' or similar
283repeatedly, because it avoids the costs associated with launching the
284substituter many times."
c7d1d88f
LC
285 (define valid?
286 (cut valid-path? store <>))
287
c3a450fb
LC
288 (define valid-input?
289 (cut valid-derivation-input? store <>))
290
291 (define (dependencies drv)
292 ;; Skip prerequisite sub-trees of DRV whose root is valid. This allows us
293 ;; to ask the substituter for just as much as needed, instead of asking it
294 ;; for the whole world, which can be significantly faster when substitute
295 ;; info is not already in cache.
bdb59b33
LC
296 ;; Also, skip derivations marked as non-substitutable.
297 (append-map (lambda (input)
015f17e8
LC
298 (let ((drv (read-derivation-from-file
299 (derivation-input-path input))))
bdb59b33
LC
300 (if (substitutable-derivation? drv)
301 (derivation-input-output-paths input)
302 '())))
c3a450fb
LC
303 (derivation-prerequisites drv valid-input?)))
304
e9651e39 305 (let* ((paths (delete-duplicates
b59df243
LC
306 (concatenate
307 (fold (lambda (drv result)
308 (let ((self (match (derivation->output-paths drv)
309 (((names . paths) ...)
310 paths))))
58c08df0
LC
311 (cond ((eqv? mode (build-mode check))
312 (cons (dependencies drv) result))
bdb59b33
LC
313 ((not (substitutable-derivation? drv))
314 (cons (dependencies drv) result))
58c08df0
LC
315 ((every valid? self)
316 result)
317 (else
318 (cons* self (dependencies drv) result)))))
b59df243
LC
319 '()
320 drv))))
ef51ac21
LC
321 (subst (fold (lambda (subst vhash)
322 (vhash-cons (substitutable-path subst) subst
323 vhash))
324 vlist-null
325 (substitutable-path-info store paths))))
326 (lambda (item)
327 (match (vhash-assoc item subst)
328 (#f #f)
329 ((key . value) value)))))
e9651e39 330
784bb1f3 331(define* (derivation-prerequisites-to-build store drv
dd36b51b 332 #:key
58c08df0 333 (mode (build-mode normal))
dd36b51b 334 (outputs
0b6af195 335 (derivation-output-names drv))
2dc98729 336 (substitutable-info
e9651e39 337 (substitution-oracle store
58c08df0
LC
338 (list drv)
339 #:mode mode)))
dd36b51b
LC
340 "Return two values: the list of derivation-inputs required to build the
341OUTPUTS of DRV and not already available in STORE, recursively, and the list
2dc98729 342of required store paths that can be substituted. SUBSTITUTABLE-INFO must be a
e9651e39 343one-argument procedure similar to that returned by 'substitution-oracle'."
784bb1f3
LC
344 (define built?
345 (cut valid-path? store <>))
346
9a20830e 347 (define input-built?
dd36b51b
LC
348 (compose (cut any built? <>) derivation-input-output-paths))
349
350 (define input-substitutable?
351 ;; Return true if and only if all of SUB-DRVS are subsitutable. If at
352 ;; least one is missing, then everything must be rebuilt.
2dc98729 353 (compose (cut every substitutable-info <>) derivation-input-output-paths))
784bb1f3 354
58c08df0
LC
355 (define (derivation-built? drv* sub-drvs)
356 ;; In 'check' mode, assume that DRV is not built.
357 (and (not (and (eqv? mode (build-mode check))
358 (eq? drv* drv)))
359 (every built? (derivation-output-paths drv* sub-drvs))))
dd36b51b 360
2dc98729 361 (define (derivation-substitutable-info drv sub-drvs)
d2d0514b 362 (and (substitutable-derivation? drv)
2dc98729
LC
363 (let ((info (filter-map substitutable-info
364 (derivation-output-paths drv sub-drvs))))
365 (and (= (length info) (length sub-drvs))
366 info))))
dd36b51b
LC
367
368 (let loop ((drv drv)
369 (sub-drvs outputs)
2dc98729
LC
370 (build '()) ;list of <derivation-input>
371 (substitute '())) ;list of <substitutable>
dd36b51b
LC
372 (cond ((derivation-built? drv sub-drvs)
373 (values build substitute))
2dc98729
LC
374 ((derivation-substitutable-info drv sub-drvs)
375 =>
376 (lambda (substitutables)
377 (values build
378 (append substitutables substitute))))
dd36b51b 379 (else
d2d0514b
LC
380 (let ((build (if (substitutable-derivation? drv)
381 build
382 (cons (make-derivation-input
383 (derivation-file-name drv) sub-drvs)
384 build)))
385 (inputs (remove (lambda (i)
dd36b51b
LC
386 (or (member i build) ; XXX: quadratic
387 (input-built? i)
388 (input-substitutable? i)))
389 (derivation-inputs drv))))
390 (fold2 loop
391 (append inputs build)
392 (append (append-map (lambda (input)
393 (if (and (not (input-built? input))
394 (input-substitutable? input))
2dc98729
LC
395 (map substitutable-info
396 (derivation-input-output-paths
397 input))
dd36b51b
LC
398 '()))
399 (derivation-inputs drv))
400 substitute)
401 (map (lambda (i)
015f17e8
LC
402 (read-derivation-from-file
403 (derivation-input-path i)))
dd36b51b
LC
404 inputs)
405 (map derivation-input-sub-derivations inputs)))))))
9a20830e 406
015f17e8
LC
407(define (read-derivation drv-port)
408 "Read the derivation from DRV-PORT and return the corresponding <derivation>
409object. Most of the time you'll want to use 'read-derivation-from-file',
410which caches things as appropriate and is thus more efficient."
77d3cf08
LC
411
412 (define comma (string->symbol ","))
413
414 (define (ununquote x)
415 (match x
416 (('unquote x) (ununquote x))
417 ((x ...) (map ununquote x))
418 (_ x)))
419
420 (define (outputs->alist x)
421 (fold-right (lambda (output result)
422 (match output
423 ((name path "" "")
424 (alist-cons name
36bbbbd1 425 (make-derivation-output path #f #f #f)
77d3cf08
LC
426 result))
427 ((name path hash-algo hash)
428 ;; fixed-output
36bbbbd1
LC
429 (let* ((rec? (string-prefix? "r:" hash-algo))
430 (algo (string->symbol
431 (if rec?
432 (string-drop hash-algo 2)
433 hash-algo)))
434 (hash (base16-string->bytevector hash)))
77d3cf08 435 (alist-cons name
36bbbbd1
LC
436 (make-derivation-output path algo
437 hash rec?)
77d3cf08
LC
438 result)))))
439 '()
440 x))
441
442 (define (make-input-drvs x)
443 (fold-right (lambda (input result)
444 (match input
445 ((path (sub-drvs ...))
446 (cons (make-derivation-input path sub-drvs)
447 result))))
448 '()
449 x))
450
df7bbd38
LC
451 ;; The contents of a derivation are typically ASCII, but choosing
452 ;; UTF-8 allows us to take the fast path for Guile's `scm_getc'.
453 (set-port-encoding! drv-port "UTF-8")
454
77d3cf08
LC
455 (let loop ((exp (read drv-port))
456 (result '()))
457 (match exp
458 ((? eof-object?)
459 (let ((result (reverse result)))
460 (match result
461 (('Derive ((outputs ...) (input-drvs ...)
462 (input-srcs ...)
463 (? string? system)
464 (? string? builder)
465 ((? string? args) ...)
466 ((var value) ...)))
467 (make-derivation (outputs->alist outputs)
468 (make-input-drvs input-drvs)
469 input-srcs
470 system builder args
6a446d56
LC
471 (fold-right alist-cons '() var value)
472 (port-filename drv-port)))
77d3cf08
LC
473 (_
474 (error "failed to parse derivation" drv-port result)))))
475 ((? (cut eq? <> comma))
476 (loop (read drv-port) result))
477 (_
478 (loop (read drv-port)
479 (cons (ununquote exp) result))))))
480
76c31074
LC
481(define %derivation-cache
482 ;; Maps derivation file names to <derivation> objects.
483 ;; XXX: This is redundant with 'atts-cache' in the store.
484 (make-weak-value-hash-table 200))
485
015f17e8
LC
486(define (read-derivation-from-file file)
487 "Read the derivation in FILE, a '.drv' file, and return the corresponding
d0840e4a 488<derivation> object."
015f17e8 489 ;; Memoize that operation because 'read-derivation' is quite expensive,
76c31074
LC
490 ;; and because the same argument is read more than 15 times on average
491 ;; during something like (package-derivation s gdb).
015f17e8
LC
492 (or (and file (hash-ref %derivation-cache file))
493 (let ((drv (call-with-input-file file read-derivation)))
494 (hash-set! %derivation-cache file drv)
495 drv)))
d0840e4a 496
d8085599
LC
497(define-inlinable (write-sequence lst write-item port)
498 ;; Write each element of LST with WRITE-ITEM to PORT, separating them with a
499 ;; comma.
500 (match lst
501 (()
502 #t)
503 ((prefix (... ...) last)
504 (for-each (lambda (item)
505 (write-item item port)
506 (display "," port))
507 prefix)
508 (write-item last port))))
509
510(define-inlinable (write-list lst write-item port)
511 ;; Write LST as a derivation list to PORT, using WRITE-ITEM to write each
512 ;; element.
513 (display "[" port)
514 (write-sequence lst write-item port)
515 (display "]" port))
516
517(define-inlinable (write-tuple lst write-item port)
518 ;; Same, but write LST as a tuple.
519 (display "(" port)
520 (write-sequence lst write-item port)
521 (display ")" port))
522
77d3cf08
LC
523(define (write-derivation drv port)
524 "Write the ATerm-like serialization of DRV to PORT. See Section 2.4 of
525Eelco Dolstra's PhD dissertation for an overview of a previous version of
526that form."
aaa848f3
LC
527
528 ;; Make sure we're using the faster implementation.
529 (define format simple-format)
530
d8085599
LC
531 (define (write-string-list lst)
532 (write-list lst write port))
77d3cf08 533
d8085599
LC
534 (define (write-output output port)
535 (match output
36bbbbd1 536 ((name . ($ <derivation-output> path hash-algo hash recursive?))
d8085599 537 (write-tuple (list name path
36bbbbd1
LC
538 (if hash-algo
539 (string-append (if recursive? "r:" "")
540 (symbol->string hash-algo))
541 "")
d8085599
LC
542 (or (and=> hash bytevector->base16-string)
543 ""))
544 write
545 port))))
546
547 (define (write-input input port)
548 (match input
549 (($ <derivation-input> path sub-drvs)
6d943e55
LC
550 (display "(\"" port)
551 (display path port)
552 (display "\"," port)
97507ebe 553 (write-string-list sub-drvs)
d8085599
LC
554 (display ")" port))))
555
556 (define (write-env-var env-var port)
557 (match env-var
558 ((name . value)
559 (display "(" port)
560 (write name port)
561 (display "," port)
562 (write value port)
563 (display ")" port))))
564
97507ebe 565 ;; Assume all the lists we are writing are already sorted.
77d3cf08
LC
566 (match drv
567 (($ <derivation> outputs inputs sources
568 system builder args env-vars)
569 (display "Derive(" port)
97507ebe 570 (write-list outputs write-output port)
77d3cf08 571 (display "," port)
97507ebe 572 (write-list inputs write-input port)
77d3cf08 573 (display "," port)
97507ebe 574 (write-string-list sources)
6d943e55 575 (simple-format port ",\"~a\",\"~a\"," system builder)
d8085599 576 (write-string-list args)
77d3cf08 577 (display "," port)
97507ebe 578 (write-list env-vars write-env-var port)
77d3cf08
LC
579 (display ")" port))))
580
2dce88d5 581(define derivation->bytevector
55b2d921 582 (mlambda (drv)
2dce88d5 583 "Return the external representation of DRV as a UTF-8-encoded string."
55b2d921 584 (with-fluids ((%default-port-encoding "UTF-8"))
2dce88d5
LC
585 (call-with-values open-bytevector-output-port
586 (lambda (port get-bytevector)
587 (write-derivation drv port)
588 (get-bytevector))))))
be4e38fb 589
59688fc4 590(define* (derivation->output-path drv #:optional (output "out"))
f304c9c2
LC
591 "Return the store path of its output OUTPUT. Raise a
592'&derivation-missing-output-error' condition if OUTPUT is not an output of
593DRV."
594 (let ((output* (assoc-ref (derivation-outputs drv) output)))
595 (if output*
596 (derivation-output-path output*)
597 (raise (condition (&derivation-missing-output-error
598 (derivation drv)
599 (output output)))))))
59688fc4
LC
600
601(define (derivation->output-paths drv)
602 "Return the list of name/path pairs of the outputs of DRV."
603 (map (match-lambda
604 ((name . output)
605 (cons name (derivation-output-path output))))
606 (derivation-outputs drv)))
607
aaa848f3
LC
608(define derivation-path->output-path
609 ;; This procedure is called frequently, so memoize it.
55b2d921 610 (let ((memoized (mlambda (path output)
015f17e8 611 (derivation->output-path (read-derivation-from-file path)
55b2d921
LC
612 output))))
613 (lambda* (path #:optional (output "out"))
614 "Read the derivation from PATH (`/gnu/store/xxx.drv'), and return the store
de4c3f26 615path of its output OUTPUT."
55b2d921 616 (memoized path output))))
de4c3f26 617
7244a5f7 618(define (derivation-path->output-paths path)
6f58d582 619 "Read the derivation from PATH (`/gnu/store/xxx.drv'), and return the
7244a5f7 620list of name/path pairs of its outputs."
015f17e8 621 (derivation->output-paths (read-derivation-from-file path)))
7244a5f7 622
de4c3f26
LC
623\f
624;;;
625;;; Derivation primitive.
626;;;
627
1391dcb0 628(define derivation-path->base16-hash
55b2d921
LC
629 (mlambda (file)
630 "Return a string containing the base16 representation of the hash of the
1391dcb0 631derivation at FILE."
015f17e8
LC
632 (bytevector->base16-string
633 (derivation-hash (read-derivation-from-file file)))))
1391dcb0 634
eb1150c2
LC
635(define (derivation/masked-inputs drv)
636 "Assuming DRV is a regular derivation (not fixed-output), replace the file
637name of each input with that input's hash."
638 (match drv
639 (($ <derivation> outputs inputs sources
640 system builder args env-vars)
641 (let ((inputs (map (match-lambda
642 (($ <derivation-input> path sub-drvs)
643 (let ((hash (derivation-path->base16-hash path)))
644 (make-derivation-input hash sub-drvs))))
645 inputs)))
646 (make-derivation outputs
647 (sort (coalesce-duplicate-inputs inputs)
648 derivation-input<?)
649 sources
650 system builder args env-vars
651 #f)))))
652
de4c3f26 653(define derivation-hash ; `hashDerivationModulo' in derivations.cc
55b2d921 654 (mlambda (drv)
de4c3f26
LC
655 "Return the hash of DRV, modulo its fixed-output inputs, as a bytevector."
656 (match drv
657 (($ <derivation> ((_ . ($ <derivation-output> path
55b2d921
LC
658 (? symbol? hash-algo) (? bytevector? hash)
659 (? boolean? recursive?)))))
de4c3f26 660 ;; A fixed-output derivation.
77d3cf08 661 (sha256
de4c3f26 662 (string->utf8
36bbbbd1
LC
663 (string-append "fixed:out:"
664 (if recursive? "r:" "")
665 (symbol->string hash-algo)
749c6567
LC
666 ":" (bytevector->base16-string hash)
667 ":" path))))
eb1150c2
LC
668 (_
669
670 ;; XXX: At this point this remains faster than `port-sha256', because
671 ;; the SHA256 port's `write' method gets called for every single
672 ;; character.
673 (sha256 (derivation->bytevector (derivation/masked-inputs drv)))))))
77d3cf08 674
a987d2c0
LC
675(define* (derivation store name builder args
676 #:key
677 (system (%current-system)) (env-vars '())
678 (inputs '()) (outputs '("out"))
2096ef47 679 hash hash-algo recursive?
35b5ca78
LC
680 references-graphs
681 allowed-references disallowed-references
4a6aeb67
LC
682 leaked-env-vars local-build?
683 (substitutable? #t))
59688fc4 684 "Build a derivation with the given arguments, and return the resulting
2096ef47 685<derivation> object. When HASH and HASH-ALGO are given, a
59688fc4 686fixed-output derivation is created---i.e., one whose result is known in
36bbbbd1
LC
687advance, such as a file download. If, in addition, RECURSIVE? is true, then
688that fixed output may be an executable file or a directory and HASH must be
689the hash of an archive containing this output.
5b0c9d16 690
858e9282 691When REFERENCES-GRAPHS is true, it must be a list of file name/store path
5b0c9d16 692pairs. In that case, the reference graph of each store path is exported in
1909431c
LC
693the build environment in the corresponding file, in a simple text format.
694
b53be755 695When ALLOWED-REFERENCES is true, it must be a list of store items or outputs
35b5ca78
LC
696that the derivation's outputs may refer to. Likewise, DISALLOWED-REFERENCES,
697if true, must be a list of things the outputs may not refer to.
b53be755 698
c0468155
LC
699When LEAKED-ENV-VARS is true, it must be a list of strings denoting
700environment variables that are allowed to \"leak\" from the daemon's
701environment to the build environment. This is only applicable to fixed-output
702derivations--i.e., when HASH is true. The main use is to allow variables such
703as \"http_proxy\" to be passed to derivations that download files.
704
1909431c
LC
705When LOCAL-BUILD? is true, declare that the derivation is not a good candidate
706for offloading and should rather be built locally. This is the case for small
4a6aeb67
LC
707derivations where the costs of data transfers would outweigh the benefits.
708
709When SUBSTITUTABLE? is false, declare that substitutes of the derivation's
710output should not be used."
26bbbb95
LC
711 (define (add-output-paths drv)
712 ;; Return DRV with an actual store path for each of its output and the
713 ;; corresponding environment variable.
714 (match drv
715 (($ <derivation> outputs inputs sources
716 system builder args env-vars)
717 (let* ((drv-hash (derivation-hash drv))
718 (outputs (map (match-lambda
d9085c23 719 ((output-name . ($ <derivation-output>
36bbbbd1 720 _ algo hash rec?))
260bc60f
LC
721 (let ((path
722 (if hash
723 (fixed-output-path name hash
724 #:hash-algo algo
725 #:output output-name
726 #:recursive? rec?)
727 (output-path output-name
728 drv-hash name))))
d9085c23
LC
729 (cons output-name
730 (make-derivation-output path algo
36bbbbd1 731 hash rec?)))))
d9085c23 732 outputs)))
26bbbb95
LC
733 (make-derivation outputs inputs sources system builder args
734 (map (match-lambda
735 ((name . value)
736 (cons name
737 (or (and=> (assoc-ref outputs name)
738 derivation-output-path)
739 value))))
6a446d56
LC
740 env-vars)
741 #f)))))
26bbbb95 742
5b0c9d16
LC
743 (define (user+system-env-vars)
744 ;; Some options are passed to the build daemon via the env. vars of
745 ;; derivations (urgh!). We hide that from our API, but here is the place
746 ;; where we kludgify those options.
b53be755
LC
747 (let ((env-vars `(,@(if local-build?
748 `(("preferLocalBuild" . "1"))
749 '())
4a6aeb67
LC
750 ,@(if (not substitutable?)
751 `(("allowSubstitutes" . "0"))
752 '())
b53be755
LC
753 ,@(if allowed-references
754 `(("allowedReferences"
755 . ,(string-join allowed-references)))
756 '())
35b5ca78
LC
757 ,@(if disallowed-references
758 `(("disallowedReferences"
759 . ,(string-join disallowed-references)))
760 '())
c0468155
LC
761 ,@(if leaked-env-vars
762 `(("impureEnvVars"
763 . ,(string-join leaked-env-vars)))
764 '())
b53be755 765 ,@env-vars)))
1909431c
LC
766 (match references-graphs
767 (((file . path) ...)
768 (let ((value (map (cut string-append <> " " <>)
769 file path)))
770 ;; XXX: This all breaks down if an element of FILE or PATH contains
771 ;; white space.
772 `(("exportReferencesGraph" . ,(string-join value " "))
773 ,@env-vars)))
774 (#f
775 env-vars))))
5b0c9d16
LC
776
777 (define (env-vars-with-empty-outputs env-vars)
26bbbb95 778 ;; Return a variant of ENV-VARS where each OUTPUTS is associated with an
561eaf71 779 ;; empty string, even outputs that do not appear in ENV-VARS.
26bbbb95
LC
780 (let ((e (map (match-lambda
781 ((name . val)
782 (if (member name outputs)
783 (cons name "")
784 (cons name val))))
785 env-vars)))
561eaf71
LC
786 (fold (lambda (output-name env-vars)
787 (if (assoc output-name env-vars)
788 env-vars
789 (append env-vars `((,output-name . "")))))
790 e
791 outputs)))
26bbbb95 792
97507ebe
LC
793 (define input->derivation-input
794 (match-lambda
795 (((? derivation? drv))
796 (make-derivation-input (derivation-file-name drv) '("out")))
797 (((? derivation? drv) sub-drvs ...)
798 (make-derivation-input (derivation-file-name drv) sub-drvs))
799 (((? direct-store-path? input))
800 (make-derivation-input input '("out")))
801 (((? direct-store-path? input) sub-drvs ...)
802 (make-derivation-input input sub-drvs))
803 ((input . _)
804 (let ((path (add-to-store store (basename input)
805 #t "sha256" input)))
806 (make-derivation-input path '())))))
807
808 ;; Note: lists are sorted alphabetically, to conform with the behavior of
809 ;; C++ `std::map' in Nix itself.
810
26bbbb95
LC
811 (let* ((outputs (map (lambda (name)
812 ;; Return outputs with an empty path.
813 (cons name
36bbbbd1
LC
814 (make-derivation-output "" hash-algo
815 hash recursive?)))
97507ebe
LC
816 (sort outputs string<?)))
817 (inputs (sort (coalesce-duplicate-inputs
818 (map input->derivation-input
819 (delete-duplicates inputs)))
820 derivation-input<?))
821 (env-vars (sort (env-vars-with-empty-outputs
822 (user+system-env-vars))
823 (lambda (e1 e2)
824 (string<? (car e1) (car e2)))))
26bbbb95
LC
825 (drv-masked (make-derivation outputs
826 (filter (compose derivation-path?
827 derivation-input-path)
828 inputs)
829 (filter-map (lambda (i)
830 (let ((p (derivation-input-path i)))
831 (and (not (derivation-path? p))
832 p)))
833 inputs)
6a446d56 834 system builder args env-vars #f))
26bbbb95 835 (drv (add-output-paths drv-masked)))
de4c3f26 836
2dce88d5
LC
837 (let* ((file (add-data-to-store store (string-append name ".drv")
838 (derivation->bytevector drv)
76c31074 839 (map derivation-input-path inputs)))
dc673fa1
ML
840 (drv* (set-field drv (derivation-file-name) file)))
841 (hash-set! %derivation-cache file drv*)
842 drv*)))
59688fc4 843
e387ab7c
LC
844(define* (map-derivation store drv mapping
845 #:key (system (%current-system)))
846 "Given MAPPING, a list of pairs of derivations, return a derivation based on
847DRV where all the 'car's of MAPPING have been replaced by its 'cdr's,
848recursively."
849 (define (substitute str initial replacements)
850 (fold (lambda (path replacement result)
851 (string-replace-substring result path
852 replacement))
853 str
854 initial replacements))
855
856 (define (substitute-file file initial replacements)
857 (define contents
858 (with-fluids ((%default-port-encoding #f))
2535635f 859 (call-with-input-file file read-string)))
e387ab7c
LC
860
861 (let ((updated (substitute contents initial replacements)))
862 (if (string=? updated contents)
863 file
864 ;; XXX: permissions aren't preserved.
865 (add-text-to-store store (store-path-package-name file)
866 updated))))
867
868 (define input->output-paths
869 (match-lambda
a716e36d 870 (((? derivation? drv))
e387ab7c 871 (list (derivation->output-path drv)))
a716e36d 872 (((? derivation? drv) sub-drvs ...)
e387ab7c 873 (map (cut derivation->output-path drv <>)
a716e36d
LC
874 sub-drvs))
875 ((file)
876 (list file))))
e387ab7c
LC
877
878 (let ((mapping (fold (lambda (pair result)
879 (match pair
a716e36d 880 (((? derivation? orig) . replacement)
e387ab7c 881 (vhash-cons (derivation-file-name orig)
a716e36d
LC
882 replacement result))
883 ((file . replacement)
884 (vhash-cons file replacement result))))
e387ab7c
LC
885 vlist-null
886 mapping)))
887 (define rewritten-input
888 ;; Rewrite the given input according to MAPPING, and return an input
889 ;; in the format used in 'derivation' calls.
55b2d921
LC
890 (mlambda (input loop)
891 (match input
892 (($ <derivation-input> path (sub-drvs ...))
893 (match (vhash-assoc path mapping)
894 ((_ . (? derivation? replacement))
895 (cons replacement sub-drvs))
896 ((_ . replacement)
897 (list replacement))
898 (#f
015f17e8 899 (let* ((drv (loop (read-derivation-from-file path))))
55b2d921 900 (cons drv sub-drvs))))))))
e387ab7c
LC
901
902 (let loop ((drv drv))
903 (let* ((inputs (map (cut rewritten-input <> loop)
904 (derivation-inputs drv)))
905 (initial (append-map derivation-input-output-paths
906 (derivation-inputs drv)))
907 (replacements (append-map input->output-paths inputs))
908
909 ;; Sources typically refer to the output directories of the
910 ;; original inputs, INITIAL. Rewrite them by substituting
911 ;; REPLACEMENTS.
a716e36d
LC
912 (sources (map (lambda (source)
913 (match (vhash-assoc source mapping)
914 ((_ . replacement)
915 replacement)
916 (#f
917 (substitute-file source
918 initial replacements))))
e387ab7c
LC
919 (derivation-sources drv)))
920
921 ;; Now augment the lists of initials and replacements.
922 (initial (append (derivation-sources drv) initial))
923 (replacements (append sources replacements))
924 (name (store-path-package-name
925 (string-drop-right (derivation-file-name drv)
926 4))))
927 (derivation store name
928 (substitute (derivation-builder drv)
929 initial replacements)
930 (map (cut substitute <> initial replacements)
931 (derivation-builder-arguments drv))
932 #:system system
933 #:env-vars (map (match-lambda
934 ((var . value)
935 `(,var
936 . ,(substitute value initial
937 replacements))))
938 (derivation-builder-environment-vars drv))
939 #:inputs (append (map list sources) inputs)
0b6af195 940 #:outputs (derivation-output-names drv)
e387ab7c
LC
941 #:hash (match (derivation-outputs drv)
942 ((($ <derivation-output> _ algo hash))
943 hash)
944 (_ #f))
945 #:hash-algo (match (derivation-outputs drv)
946 ((($ <derivation-output> _ algo hash))
947 algo)
948 (_ #f)))))))
949
59688fc4
LC
950\f
951;;;
952;;; Store compatibility layer.
953;;;
954
a8d65643
LC
955(define* (build-derivations store derivations
956 #:optional (mode (build-mode normal)))
957 "Build DERIVATIONS, a list of <derivation> objects or .drv file names, using
958the specified MODE."
01d8ac64
LC
959 (build-things store (map (match-lambda
960 ((? string? file) file)
961 ((and drv ($ <derivation>))
962 (derivation-file-name drv)))
a8d65643
LC
963 derivations)
964 mode))
d9085c23
LC
965
966\f
967;;;
968;;; Guile-based builders.
969;;;
970
d9024884
LC
971(define (parent-directories file-name)
972 "Return the list of parent dirs of FILE-NAME, in the order in which an
973`mkdir -p' implementation would make them."
974 (let ((not-slash (char-set-complement (char-set #\/))))
975 (reverse
976 (fold (lambda (dir result)
977 (match result
978 (()
979 (list dir))
980 ((prev _ ...)
981 (cons (string-append prev "/" dir)
982 result))))
983 '()
984 (remove (cut string=? <> ".")
985 (string-tokenize (dirname file-name) not-slash))))))
986
aa72d9af 987(define* (imported-files store files ;deprecated
b272c474
LC
988 #:key (name "file-import")
989 (system (%current-system))
990 (guile (%guile-for-build)))
99634e3f
LC
991 "Return a derivation that imports FILES into STORE. FILES must be a list
992of (FINAL-PATH . FILE-NAME) pairs; each FILE-NAME is read from the file
993system, imported, and appears under FINAL-PATH in the resulting store path."
99634e3f
LC
994 (let* ((files (map (match-lambda
995 ((final-path . file-name)
2acb2cb6 996 (list final-path
a9ebd9ef 997 (add-to-store store (basename final-path) #f
99634e3f
LC
998 "sha256" file-name))))
999 files))
1000 (builder
1001 `(begin
1002 (mkdir %output) (chdir %output)
1003 ,@(append-map (match-lambda
2acb2cb6 1004 ((final-path store-path)
d9024884 1005 (append (match (parent-directories final-path)
99634e3f
LC
1006 (() '())
1007 ((head ... tail)
1008 (append (map (lambda (d)
1009 `(false-if-exception
1010 (mkdir ,d)))
1011 head)
224f7ad6
LC
1012 `((or (file-exists? ,tail)
1013 (mkdir ,tail))))))
99634e3f
LC
1014 `((symlink ,store-path ,final-path)))))
1015 files))))
dd1a5a15
LC
1016 (build-expression->derivation store name builder
1017 #:system system
1018 #:inputs files
6ce206cb
LC
1019 #:guile-for-build guile
1020 #:local-build? #t)))
99634e3f 1021
d26e1967
LC
1022;; The "file not found" error condition.
1023(define-condition-type &file-search-error &error
1024 file-search-error?
1025 (file file-search-error-file-name)
1026 (path file-search-error-search-path))
1027
8601d0dd
LC
1028(define search-path*
1029 ;; A memoizing version of 'search-path' so 'imported-modules' does not end
1030 ;; up looking for the same files over and over again.
55b2d921
LC
1031 (mlambda (path file)
1032 "Search for FILE in PATH and memoize the result. Raise a
d26e1967 1033'&file-search-error' condition if it could not be found."
55b2d921
LC
1034 (or (search-path path file)
1035 (raise (condition
1036 (&file-search-error (file file)
1037 (path path)))))))
8601d0dd 1038
6985335f
LC
1039(define (module->source-file-name module)
1040 "Return the file name corresponding to MODULE, a Guile module name (a list
1041of symbols.)"
1042 (string-append (string-join (map symbol->string module) "/")
1043 ".scm"))
1044
aa72d9af 1045(define* (%imported-modules store modules ;deprecated
e87f0591
LC
1046 #:key (name "module-import")
1047 (system (%current-system))
1048 (guile (%guile-for-build))
1049 (module-path %load-path))
3eb98237 1050 "Return a derivation that contains the source files of MODULES, a list of
8dcb0c55 1051module names such as `(ice-9 q)'. All of MODULES must be in the MODULE-PATH
3eb98237
LC
1052search path."
1053 ;; TODO: Determine the closure of MODULES, build the `.go' files,
1054 ;; canonicalize the source files through read/write, etc.
1055 (let ((files (map (lambda (m)
6985335f 1056 (let ((f (module->source-file-name m)))
8601d0dd 1057 (cons f (search-path* module-path f))))
3eb98237 1058 modules)))
b272c474
LC
1059 (imported-files store files #:name name #:system system
1060 #:guile guile)))
3eb98237 1061
aa72d9af 1062(define* (%compiled-modules store modules ;deprecated
e87f0591
LC
1063 #:key (name "module-import-compiled")
1064 (system (%current-system))
1065 (guile (%guile-for-build))
1066 (module-path %load-path))
d9024884
LC
1067 "Return a derivation that builds a tree containing the `.go' files
1068corresponding to MODULES. All the MODULES are built in a context where
1069they can refer to each other."
e87f0591
LC
1070 (let* ((module-drv (%imported-modules store modules
1071 #:system system
1072 #:guile guile
1073 #:module-path module-path))
59688fc4 1074 (module-dir (derivation->output-path module-drv))
d9024884
LC
1075 (files (map (lambda (m)
1076 (let ((f (string-join (map symbol->string m)
1077 "/")))
1078 (cons (string-append f ".go")
1079 (string-append module-dir "/" f ".scm"))))
1080 modules)))
1081 (define builder
1082 `(begin
1083 (use-modules (system base compile))
1084 (let ((out (assoc-ref %outputs "out")))
1085 (mkdir out)
1086 (chdir out))
1087
1088 (set! %load-path
1089 (cons ,module-dir %load-path))
1090
1091 ,@(map (match-lambda
1092 ((output . input)
1093 (let ((make-parent-dirs (map (lambda (dir)
1094 `(unless (file-exists? ,dir)
1095 (mkdir ,dir)))
1096 (parent-directories output))))
1097 `(begin
1098 ,@make-parent-dirs
1099 (compile-file ,input
1100 #:output-file ,output
1101 #:opts %auto-compilation-options)))))
1102 files)))
1103
dd1a5a15
LC
1104 (build-expression->derivation store name builder
1105 #:inputs `(("modules" ,module-drv))
1106 #:system system
6ce206cb
LC
1107 #:guile-for-build guile
1108 #:local-build? #t)))
3eb98237 1109
aa72d9af 1110(define* (build-expression->derivation store name exp ;deprecated
dd1a5a15
LC
1111 #:key
1112 (system (%current-system))
1113 (inputs '())
1114 (outputs '("out"))
36bbbbd1 1115 hash hash-algo recursive?
4c1eddf7 1116 (env-vars '())
6dd7787c 1117 (modules '())
9c629a27 1118 guile-for-build
1909431c 1119 references-graphs
63a42824 1120 allowed-references
35b5ca78 1121 disallowed-references
4a6aeb67 1122 local-build? (substitutable? #t))
874e6874
LC
1123 "Return a derivation that executes Scheme expression EXP as a builder
1124for derivation NAME. INPUTS must be a list of (NAME DRV-PATH SUB-DRV)
1125tuples; when SUB-DRV is omitted, \"out\" is assumed. MODULES is a list
1126of names of Guile modules from the current search path to be copied in
1127the store, compiled, and made available in the load path during the
1128execution of EXP.
1129
1130EXP is evaluated in an environment where %OUTPUT is bound to the main
1131output path, %OUTPUTS is bound to a list of output/path pairs, and where
1132%BUILD-INPUTS is bound to an alist of string/output-path pairs made from
1133INPUTS. Optionally, ENV-VARS is a list of string pairs specifying the
1134name and value of environment variables visible to the builder. The
1135builder terminates by passing the result of EXP to `exit'; thus, when
1136EXP returns #f, the build is considered to have failed.
6dd7787c
LC
1137
1138EXP is built using GUILE-FOR-BUILD (a derivation). When GUILE-FOR-BUILD is
9c629a27
LC
1139omitted or is #f, the value of the `%guile-for-build' fluid is used instead.
1140
63a42824 1141See the `derivation' procedure for the meaning of REFERENCES-GRAPHS,
35b5ca78 1142ALLOWED-REFERENCES, DISALLOWED-REFERENCES, LOCAL-BUILD?, and SUBSTITUTABLE?."
b272c474
LC
1143 (define guile-drv
1144 (or guile-for-build (%guile-for-build)))
1145
d9085c23 1146 (define guile
59688fc4 1147 (string-append (derivation->output-path guile-drv)
d9085c23
LC
1148 "/bin/guile"))
1149
0d56a551
LC
1150 (define module-form?
1151 (match-lambda
a987d2c0
LC
1152 (((or 'define-module 'use-modules) _ ...) #t)
1153 (_ #f)))
0d56a551 1154
7bdd1f0e
LC
1155 (define source-path
1156 ;; When passed an input that is a source, return its path; otherwise
1157 ;; return #f.
1158 (match-lambda
59688fc4
LC
1159 ((_ (? derivation?) _ ...)
1160 #f)
7bdd1f0e
LC
1161 ((_ path _ ...)
1162 (and (not (derivation-path? path))
1163 path))))
1164
d9085c23 1165 (let* ((prologue `(begin
0d56a551
LC
1166 ,@(match exp
1167 ((_ ...)
1168 ;; Module forms must appear at the top-level so
1169 ;; that any macros they export can be expanded.
1170 (filter module-form? exp))
1171 (_ `(,exp)))
1172
d9085c23 1173 (define %output (getenv "out"))
9bc07f4d
LC
1174 (define %outputs
1175 (map (lambda (o)
1176 (cons o (getenv o)))
1177 ',outputs))
d9085c23
LC
1178 (define %build-inputs
1179 ',(map (match-lambda
2acb2cb6
LC
1180 ((name drv . rest)
1181 (let ((sub (match rest
1182 (() "out")
1183 ((x) x))))
1184 (cons name
59688fc4
LC
1185 (cond
1186 ((derivation? drv)
1187 (derivation->output-path drv sub))
1188 ((derivation-path? drv)
1189 (derivation-path->output-path drv
1190 sub))
1191 (else drv))))))
d44bc84b
LC
1192 inputs))
1193
d9024884
LC
1194 ,@(if (null? modules)
1195 '()
1196 ;; Remove our own settings.
1197 '((unsetenv "GUILE_LOAD_COMPILED_PATH")))
1198
d44bc84b
LC
1199 ;; Guile sets it, but remove it to avoid conflicts when
1200 ;; building Guile-using packages.
1201 (unsetenv "LD_LIBRARY_PATH")))
9231ef12 1202 (builder (add-text-to-store store
d9085c23 1203 (string-append name "-guile-builder")
0bb1aa9e
LC
1204
1205 ;; Explicitly use UTF-8 for determinism,
1206 ;; and also because UTF-8 output is faster.
1207 (with-fluids ((%default-port-encoding
1208 "UTF-8"))
9231ef12
LC
1209 (call-with-output-string
1210 (lambda (port)
2dce88d5
LC
1211 (write prologue port)
1212 (write
1213 `(exit
1214 ,(match exp
1215 ((_ ...)
1216 (remove module-form? exp))
1217 (_ `(,exp))))
9231ef12 1218 port))))
7bdd1f0e
LC
1219
1220 ;; The references don't really matter
1221 ;; since the builder is always used in
1222 ;; conjunction with the drv that needs
1223 ;; it. For clarity, we add references
1224 ;; to the subset of INPUTS that are
1225 ;; sources, avoiding references to other
1226 ;; .drv; otherwise, BUILDER's hash would
1227 ;; depend on those, even if they are
1228 ;; fixed-output.
1229 (filter-map source-path inputs)))
1230
d9024884 1231 (mod-drv (and (pair? modules)
e87f0591
LC
1232 (%imported-modules store modules
1233 #:guile guile-drv
1234 #:system system)))
3eb98237 1235 (mod-dir (and mod-drv
59688fc4 1236 (derivation->output-path mod-drv)))
d9024884 1237 (go-drv (and (pair? modules)
e87f0591
LC
1238 (%compiled-modules store modules
1239 #:guile guile-drv
1240 #:system system)))
d9024884 1241 (go-dir (and go-drv
59688fc4 1242 (derivation->output-path go-drv))))
a987d2c0 1243 (derivation store name guile
3eb98237
LC
1244 `("--no-auto-compile"
1245 ,@(if mod-dir `("-L" ,mod-dir) '())
1246 ,builder)
d9024884 1247
a987d2c0
LC
1248 #:system system
1249
1250 #:inputs `((,(or guile-for-build (%guile-for-build)))
1251 (,builder)
1252 ,@(map cdr inputs)
1253 ,@(if mod-drv `((,mod-drv) (,go-drv)) '()))
1254
d9024884
LC
1255 ;; When MODULES is non-empty, shamelessly clobber
1256 ;; $GUILE_LOAD_COMPILED_PATH.
a987d2c0
LC
1257 #:env-vars (if go-dir
1258 `(("GUILE_LOAD_COMPILED_PATH" . ,go-dir)
1259 ,@(alist-delete "GUILE_LOAD_COMPILED_PATH"
1260 env-vars))
1261 env-vars)
1262
9bc07f4d 1263 #:hash hash #:hash-algo hash-algo
36bbbbd1 1264 #:recursive? recursive?
9c629a27 1265 #:outputs outputs
1909431c 1266 #:references-graphs references-graphs
63a42824 1267 #:allowed-references allowed-references
35b5ca78 1268 #:disallowed-references disallowed-references
4a6aeb67
LC
1269 #:local-build? local-build?
1270 #:substitutable? substitutable?)))
e87f0591
LC
1271
1272\f
1273;;;
1274;;; Monadic interface.
1275;;;
1276
1277(define built-derivations
1278 (store-lift build-derivations))
713335fa
LC
1279
1280(define raw-derivation
1281 (store-lift derivation))