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