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