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