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