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