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