store: Add 'store-lower'.
[jackhill/guix/guix.git] / guix / packages.scm
CommitLineData
233e7676 1;;; GNU Guix --- Functional package management for GNU
e87f0591 2;;; Copyright © 2012, 2013, 2014, 2015 Ludovic Courtès <ludo@gnu.org>
a193b824 3;;; Copyright © 2014 Mark H Weaver <mhw@netris.org>
e3ce5d70 4;;;
233e7676 5;;; This file is part of GNU Guix.
e3ce5d70 6;;;
233e7676 7;;; GNU Guix is free software; you can redistribute it and/or modify it
e3ce5d70
LC
8;;; under the terms of the GNU General Public License as published by
9;;; the Free Software Foundation; either version 3 of the License, or (at
10;;; your option) any later version.
11;;;
233e7676 12;;; GNU Guix is distributed in the hope that it will be useful, but
e3ce5d70
LC
13;;; WITHOUT ANY WARRANTY; without even the implied warranty of
14;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15;;; GNU General Public License for more details.
16;;;
17;;; You should have received a copy of the GNU General Public License
233e7676 18;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
e3ce5d70
LC
19
20(define-module (guix packages)
21 #:use-module (guix utils)
c0cd1b3e 22 #:use-module (guix records)
e3ce5d70 23 #:use-module (guix store)
e87f0591 24 #:use-module (guix monads)
ddc29a78 25 #:use-module (guix base32)
d510ab46 26 #:use-module (guix derivations)
e3ce5d70
LC
27 #:use-module (guix build-system)
28 #:use-module (ice-9 match)
c37a74bd 29 #:use-module (ice-9 vlist)
062c6927 30 #:use-module (srfi srfi-1)
946b72c9 31 #:use-module (srfi srfi-9 gnu)
05962f29 32 #:use-module (srfi srfi-11)
a63062b5 33 #:use-module (srfi srfi-26)
d36622dc
LC
34 #:use-module (srfi srfi-34)
35 #:use-module (srfi srfi-35)
cd52703a
LC
36 #:re-export (%current-system
37 %current-target-system)
ff352cfb 38 #:export (origin
90c68be8
LC
39 origin?
40 origin-uri
41 origin-method
42 origin-sha256
43 origin-file-name
ac10e0e1
LC
44 origin-patches
45 origin-patch-flags
46 origin-patch-inputs
47 origin-patch-guile
f9cc8971
LC
48 origin-snippet
49 origin-modules
50 origin-imported-modules
e4c245f8 51 base32
e3ce5d70 52
a18eda27
LC
53 <search-path-specification>
54 search-path-specification
55 search-path-specification?
56 search-path-specification->sexp
57
e3ce5d70
LC
58 package
59 package?
60 package-name
61 package-version
2847050a 62 package-full-name
e3ce5d70
LC
63 package-source
64 package-build-system
65 package-arguments
66 package-inputs
67 package-native-inputs
062c6927 68 package-propagated-inputs
e3ce5d70 69 package-outputs
a18eda27 70 package-native-search-paths
e3ce5d70 71 package-search-paths
05962f29 72 package-replacement
d45122f5 73 package-synopsis
e3ce5d70 74 package-description
e3ce5d70 75 package-license
52bda18a 76 package-home-page
4e097f86 77 package-supported-systems
e3ce5d70 78 package-maintainers
062c6927 79 package-properties
35f3c5f5 80 package-location
d66c7096 81 package-field-location
e3ce5d70 82
7d193ec3 83 package-direct-inputs
a3d73f59 84 package-transitive-inputs
9c1edabd
LC
85 package-transitive-target-inputs
86 package-transitive-native-inputs
113aef68 87 package-transitive-propagated-inputs
7c3c0374 88 package-transitive-supported-systems
e3ce5d70
LC
89 package-source-derivation
90 package-derivation
d36622dc 91 package-cross-derivation
d510ab46 92 package-output
05962f29 93 package-grafts
d36622dc 94
4e097f86
LC
95 %supported-systems
96
d36622dc 97 &package-error
07783858 98 package-error?
d36622dc
LC
99 package-error-package
100 &package-input-error
07783858 101 package-input-error?
9b222abe
LC
102 package-error-invalid-input
103 &package-cross-build-system-error
0d5a559f
LC
104 package-cross-build-system-error?
105
05962f29 106 %graft?
0d5a559f 107 package->bag
d3d337d2 108 bag->derivation
0d5a559f
LC
109 bag-transitive-inputs
110 bag-transitive-host-inputs
111 bag-transitive-build-inputs
e87f0591
LC
112 bag-transitive-target-inputs
113
114 default-guile
115
116 set-guile-for-build
117 package-file
118 package->derivation
119 package->cross-derivation
120 origin->derivation))
e3ce5d70
LC
121
122;;; Commentary:
123;;;
124;;; This module provides a high-level mechanism to define packages in a
125;;; Guix-based distribution.
126;;;
127;;; Code:
128
90c68be8
LC
129;; The source of a package, such as a tarball URL and fetcher---called
130;; "origin" to avoid name clash with `package-source', `source', etc.
131(define-record-type* <origin>
132 origin make-origin
133 origin?
134 (uri origin-uri) ; string
9b5b5c17 135 (method origin-method) ; procedure
90c68be8 136 (sha256 origin-sha256) ; bytevector
ac10e0e1
LC
137 (file-name origin-file-name (default #f)) ; optional file name
138 (patches origin-patches (default '())) ; list of file names
f9cc8971 139 (snippet origin-snippet (default #f)) ; sexp or #f
ac10e0e1
LC
140 (patch-flags origin-patch-flags ; list of strings
141 (default '("-p1")))
1d9bc459
LC
142
143 ;; Patching requires Guile, GNU Patch, and a few more. These two fields are
144 ;; used to specify these dependencies when needed.
ac10e0e1
LC
145 (patch-inputs origin-patch-inputs ; input list or #f
146 (default #f))
f9cc8971
LC
147 (modules origin-modules ; list of module names
148 (default '()))
149 (imported-modules origin-imported-modules ; list of module names
150 (default '()))
1d9bc459 151 (patch-guile origin-patch-guile ; package or #f
ac10e0e1 152 (default #f)))
e3ce5d70 153
f1096964
LC
154(define (print-origin origin port)
155 "Write a concise representation of ORIGIN to PORT."
156 (match origin
157 (($ <origin> uri method sha256 file-name patches)
158 (simple-format port "#<origin ~s ~a ~s ~a>"
159 uri (bytevector->base32-string sha256)
160 patches
161 (number->string (object-address origin) 16)))))
162
163(set-record-type-printer! <origin> print-origin)
164
e4c245f8
LC
165(define-syntax base32
166 (lambda (s)
167 "Return the bytevector corresponding to the given Nix-base32
168representation."
169 (syntax-case s ()
170 ((_ str)
171 (string? (syntax->datum #'str))
aba326f7 172 ;; A literal string: do the conversion at expansion time.
e4c245f8
LC
173 (with-syntax ((bv (nix-base32-string->bytevector
174 (syntax->datum #'str))))
aba326f7
LC
175 #''bv))
176 ((_ str)
177 #'(nix-base32-string->bytevector str)))))
e4c245f8 178
a18eda27
LC
179;; The specification of a search path.
180(define-record-type* <search-path-specification>
181 search-path-specification make-search-path-specification
182 search-path-specification?
183 (variable search-path-specification-variable)
184 (directories search-path-specification-directories)
185 (separator search-path-specification-separator (default ":")))
186
187(define (search-path-specification->sexp spec)
188 "Return an sexp representing SPEC, a <search-path-specification>. The sexp
189corresponds to the arguments expected by `set-path-environment-variable'."
190 (match spec
191 (($ <search-path-specification> variable directories separator)
192 `(,variable ,directories ,separator))))
d36622dc 193
4e097f86
LC
194(define %supported-systems
195 ;; This is the list of system types that are supported. By default, we
196 ;; expect all packages to build successfully here.
197 '("x86_64-linux" "i686-linux" "mips64el-linux"))
198
a18eda27 199;; A package.
e3ce5d70
LC
200(define-record-type* <package>
201 package make-package
202 package?
203 (name package-name) ; string
204 (version package-version) ; string
90c68be8 205 (source package-source) ; <origin> instance
e3ce5d70 206 (build-system package-build-system) ; build system
64fddd74 207 (arguments package-arguments ; arguments for the build method
21c203a5 208 (default '()) (thunked))
062c6927 209
e3ce5d70 210 (inputs package-inputs ; input packages or derivations
dd6b9a37 211 (default '()) (thunked))
062c6927 212 (propagated-inputs package-propagated-inputs ; same, but propagated
9d97a1b3 213 (default '()) (thunked))
e3ce5d70 214 (native-inputs package-native-inputs ; native input packages/derivations
a7dc055b 215 (default '()) (thunked))
c9d01150
LC
216 (self-native-input? package-self-native-input? ; whether to use itself as
217 ; a native input when cross-
218 (default #f)) ; compiling
062c6927 219
e3ce5d70
LC
220 (outputs package-outputs ; list of strings
221 (default '("out")))
a18eda27
LC
222
223 ; lists of
224 ; <search-path-specification>,
225 ; for native and cross
226 ; inputs
227 (native-search-paths package-native-search-paths (default '()))
228 (search-paths package-search-paths (default '()))
05962f29
LC
229 (replacement package-replacement ; package | #f
230 (default #f) (thunked))
e3ce5d70 231
d45122f5
LC
232 (synopsis package-synopsis) ; one-line description
233 (description package-description) ; one or two paragraphs
1fb78cb2 234 (license package-license)
45753b65 235 (home-page package-home-page)
4e097f86
LC
236 (supported-systems package-supported-systems ; list of strings
237 (default %supported-systems))
35f3c5f5 238 (maintainers package-maintainers (default '()))
45753b65 239
062c6927
LC
240 (properties package-properties (default '())) ; alist for anything else
241
35f3c5f5
LC
242 (location package-location
243 (default (and=> (current-source-location)
244 source-properties->location))))
e3ce5d70 245
946b72c9
LC
246(set-record-type-printer! <package>
247 (lambda (package port)
248 (let ((loc (package-location package))
249 (format simple-format))
2e1bafb0 250 (format port "#<package ~a-~a ~a~a>"
946b72c9
LC
251 (package-name package)
252 (package-version package)
2e1bafb0
LC
253 (if loc
254 (format #f "~a:~a "
255 (location-file loc)
256 (location-line loc))
257 "")
946b72c9
LC
258 (number->string (object-address
259 package)
260 16)))))
261
d66c7096 262(define (package-field-location package field)
f903dc05
LC
263 "Return the source code location of the definition of FIELD for PACKAGE, or
264#f if it could not be determined."
265 (define (goto port line column)
266 (unless (and (= (port-column port) (- column 1))
267 (= (port-line port) (- line 1)))
268 (unless (eof-object? (read-char port))
269 (goto port line column))))
d66c7096
LC
270
271 (match (package-location package)
272 (($ <location> file line column)
273 (catch 'system
274 (lambda ()
0b8749b7
LC
275 ;; In general we want to keep relative file names for modules.
276 (with-fluids ((%file-port-name-canonicalization 'relative))
277 (call-with-input-file (search-path %load-path file)
278 (lambda (port)
279 (goto port line column)
280 (match (read port)
281 (('package inits ...)
282 (let ((field (assoc field inits)))
283 (match field
284 ((_ value)
285 ;; Put the `or' here, and not in the first argument of
286 ;; `and=>', to work around a compiler bug in 2.0.5.
287 (or (and=> (source-properties value)
288 source-properties->location)
289 (and=> (source-properties field)
290 source-properties->location)))
291 (_
292 #f))))
293 (_
294 #f))))))
d66c7096 295 (lambda _
f903dc05 296 #f)))
d66c7096
LC
297 (_ #f)))
298
d36622dc
LC
299
300;; Error conditions.
301
302(define-condition-type &package-error &error
303 package-error?
304 (package package-error-package))
305
306(define-condition-type &package-input-error &package-error
307 package-input-error?
308 (input package-error-invalid-input))
309
9b222abe
LC
310(define-condition-type &package-cross-build-system-error &package-error
311 package-cross-build-system-error?)
312
d36622dc 313
2847050a
LC
314(define (package-full-name package)
315 "Return the full name of PACKAGE--i.e., `NAME-VERSION'."
316 (string-append (package-name package) "-" (package-version package)))
317
ac10e0e1
LC
318(define (%standard-patch-inputs)
319 (let ((ref (lambda (module var)
320 (module-ref (resolve-interface module) var))))
321 `(("tar" ,(ref '(gnu packages base) 'tar))
322 ("xz" ,(ref '(gnu packages compression) 'xz))
323 ("bzip2" ,(ref '(gnu packages compression) 'bzip2))
324 ("gzip" ,(ref '(gnu packages compression) 'gzip))
325 ("lzip" ,(ref '(gnu packages compression) 'lzip))
326 ("patch" ,(ref '(gnu packages base) 'patch)))))
327
1d9bc459 328(define (default-guile)
e87f0591
LC
329 "Return the default Guile package used to run the build code of
330derivations."
bdb36958 331 (let ((distro (resolve-interface '(gnu packages commencement))))
1d9bc459 332 (module-ref distro 'guile-final)))
ac10e0e1 333
f9cc8971 334(define* (patch-and-repack store source patches
ac10e0e1 335 #:key
f9cc8971
LC
336 (inputs '())
337 (snippet #f)
ac10e0e1 338 (flags '("-p1"))
f9cc8971
LC
339 (modules '())
340 (imported-modules '())
ac10e0e1
LC
341 (guile-for-build (%guile-for-build))
342 (system (%current-system)))
f9cc8971
LC
343 "Unpack SOURCE (a derivation or store path), apply all of PATCHES, and
344repack the tarball using the tools listed in INPUTS. When SNIPPET is true,
345it must be an s-expression that will run from within the directory where
346SOURCE was unpacked, after all of PATCHES have been applied. MODULES and
347IMPORTED-MODULES specify modules to use/import for use by SNIPPET."
348 (define source-file-name
349 ;; SOURCE is usually a derivation, but it could be a store file.
350 (if (derivation? source)
351 (derivation->output-path source)
352 source))
353
ac10e0e1 354 (define decompression-type
f9cc8971
LC
355 (cond ((string-suffix? "gz" source-file-name) "gzip")
356 ((string-suffix? "bz2" source-file-name) "bzip2")
357 ((string-suffix? "lz" source-file-name) "lzip")
358 (else "xz")))
ac10e0e1
LC
359
360 (define original-file-name
f9cc8971
LC
361 ;; Remove the store prefix plus the slash, hash, and hyphen.
362 (let* ((sans (string-drop source-file-name
363 (+ (string-length (%store-prefix)) 1)))
364 (dash (string-index sans #\-)))
365 (string-drop sans (+ 1 dash))))
ac10e0e1 366
3ca00bb5
LC
367 (define (numeric-extension? file-name)
368 ;; Return true if FILE-NAME ends with digits.
857ecb3d
LC
369 (and=> (file-extension file-name)
370 (cut string-every char-set:hex-digit <>)))
3ca00bb5
LC
371
372 (define (tarxz-name file-name)
373 ;; Return a '.tar.xz' file name based on FILE-NAME.
374 (let ((base (if (numeric-extension? file-name)
375 original-file-name
376 (file-sans-extension file-name))))
377 (string-append base
378 (if (equal? (file-extension base) "tar")
379 ".xz"
380 ".tar.xz"))))
381
ac10e0e1
LC
382 (define patch-inputs
383 (map (lambda (number patch)
384 (list (string-append "patch" (number->string number))
3f6f7b36
LC
385 (match patch
386 ((? string?)
387 (add-to-store store (basename patch) #t
388 "sha256" patch))
389 ((? origin?)
ec38437f 390 (package-source-derivation store patch system)))))
ac10e0e1
LC
391 (iota (length patches))
392
393 patches))
394
395 (define builder
396 `(begin
397 (use-modules (ice-9 ftw)
3ca00bb5
LC
398 (srfi srfi-1)
399 (guix build utils))
ac10e0e1
LC
400
401 (let ((out (assoc-ref %outputs "out"))
402 (xz (assoc-ref %build-inputs "xz"))
403 (decomp (assoc-ref %build-inputs ,decompression-type))
404 (source (assoc-ref %build-inputs "source"))
405 (tar (string-append (assoc-ref %build-inputs "tar")
406 "/bin/tar"))
407 (patch (string-append (assoc-ref %build-inputs "patch")
408 "/bin/patch")))
409 (define (apply-patch input)
410 (let ((patch* (assoc-ref %build-inputs input)))
411 (format (current-error-port) "applying '~a'...~%" patch*)
412 (zero? (system* patch "--batch" ,@flags "--input" patch*))))
413
3ca00bb5
LC
414 (define (first-file directory)
415 ;; Return the name of the first file in DIRECTORY.
416 (car (scandir directory
417 (lambda (name)
418 (not (member name '("." "..")))))))
419
ac10e0e1
LC
420 (setenv "PATH" (string-append xz "/bin" ":"
421 decomp "/bin"))
3ca00bb5
LC
422
423 ;; SOURCE may be either a directory or a tarball.
424 (and (if (file-is-directory? source)
8be3b8a3 425 (let* ((store (or (getenv "NIX_STORE") "/gnu/store"))
3ca00bb5
LC
426 (len (+ 1 (string-length store)))
427 (base (string-drop source len))
428 (dash (string-index base #\-))
429 (directory (string-drop base (+ 1 dash))))
430 (mkdir directory)
431 (copy-recursively source directory)
432 #t)
433 (zero? (system* tar "xvf" source)))
434 (let ((directory (first-file ".")))
ac10e0e1
LC
435 (format (current-error-port)
436 "source is under '~a'~%" directory)
437 (chdir directory)
f9cc8971 438
ac10e0e1 439 (and (every apply-patch ',(map car patch-inputs))
f9cc8971
LC
440
441 ,@(if snippet
442 `((let ((module (make-fresh-user-module)))
443 (module-use-interfaces! module
444 (map resolve-interface
445 ',modules))
446 (module-define! module '%build-inputs
447 %build-inputs)
448 (module-define! module '%outputs %outputs)
449 ((@ (system base compile) compile)
450 ',snippet
451 #:to 'value
452 #:opts %auto-compilation-options
453 #:env module)))
454 '())
455
ac10e0e1
LC
456 (begin (chdir "..") #t)
457 (zero? (system* tar "cvfa" out directory))))))))
458
459
3ca00bb5
LC
460 (let ((name (tarxz-name original-file-name))
461 (inputs (filter-map (match-lambda
462 ((name (? package? p))
463 (and (member name (cons decompression-type
464 '("tar" "xz" "patch")))
465 (list name
05962f29
LC
466 (package-derivation store p system
467 #:graft? #f)))))
3ca00bb5
LC
468 (or inputs (%standard-patch-inputs))))
469 (modules (delete-duplicates (cons '(guix build utils) modules))))
ac10e0e1 470
3ca00bb5 471 (build-expression->derivation store name builder
dd1a5a15
LC
472 #:inputs `(("source" ,source)
473 ,@inputs
474 ,@patch-inputs)
475 #:system system
3ca00bb5 476 #:modules modules
ac10e0e1
LC
477 #:guile-for-build guile-for-build)))
478
b642e4b8
LC
479(define* (package-source-derivation store source
480 #:optional (system (%current-system)))
481 "Return the derivation path for SOURCE, a package source, for SYSTEM."
e3ce5d70 482 (match source
f9cc8971
LC
483 (($ <origin> uri method sha256 name () #f)
484 ;; No patches, no snippet: this is a fixed-output derivation.
b642e4b8 485 (method store uri 'sha256 sha256 name
7357138b 486 #:system system))
f9cc8971
LC
487 (($ <origin> uri method sha256 name (patches ...) snippet
488 (flags ...) inputs (modules ...) (imported-modules ...)
489 guile-for-build)
490 ;; Patches and/or a snippet.
ac10e0e1 491 (let ((source (method store uri 'sha256 sha256 name
1d9bc459 492 #:system system))
05962f29 493 (guile (match (or guile-for-build (default-guile))
1d9bc459 494 ((? package? p)
05962f29
LC
495 (package-derivation store p system
496 #:graft? #f)))))
f9cc8971
LC
497 (patch-and-repack store source patches
498 #:inputs inputs
499 #:snippet snippet
ac10e0e1
LC
500 #:flags flags
501 #:system system
f9cc8971
LC
502 #:modules modules
503 #:imported-modules modules
1d9bc459 504 #:guile-for-build guile)))
f80594cc 505 ((and (? string?) (? direct-store-path?) file)
7357138b
LC
506 file)
507 ((? string? file)
508 (add-to-store store (basename file) #t "sha256" file))))
e3ce5d70 509
113aef68
LC
510(define (transitive-inputs inputs)
511 (let loop ((inputs inputs)
a3d73f59
LC
512 (result '()))
513 (match inputs
514 (()
515 (delete-duplicates (reverse result))) ; XXX: efficiency
516 (((and i (name (? package? p) sub ...)) rest ...)
517 (let ((t (map (match-lambda
518 ((dep-name derivation ...)
519 (cons (string-append name "/" dep-name)
520 derivation)))
521 (package-propagated-inputs p))))
522 (loop (append t rest)
523 (append t (cons i result)))))
524 ((input rest ...)
525 (loop rest (cons input result))))))
526
7d193ec3
EB
527(define (package-direct-inputs package)
528 "Return all the direct inputs of PACKAGE---i.e, its direct inputs along
529with their propagated inputs."
530 (append (package-native-inputs package)
531 (package-inputs package)
532 (package-propagated-inputs package)))
533
113aef68
LC
534(define (package-transitive-inputs package)
535 "Return the transitive inputs of PACKAGE---i.e., its direct inputs along
536with their propagated inputs, recursively."
7d193ec3 537 (transitive-inputs (package-direct-inputs package)))
113aef68 538
9c1edabd
LC
539(define (package-transitive-target-inputs package)
540 "Return the transitive target inputs of PACKAGE---i.e., its direct inputs
541along with their propagated inputs, recursively. This only includes inputs
542for the target system, and not native inputs."
543 (transitive-inputs (append (package-inputs package)
544 (package-propagated-inputs package))))
545
546(define (package-transitive-native-inputs package)
547 "Return the transitive native inputs of PACKAGE---i.e., its direct inputs
548along with their propagated inputs, recursively. This only includes inputs
549for the host system (\"native inputs\"), and not target inputs."
550 (transitive-inputs (package-native-inputs package)))
551
113aef68
LC
552(define (package-transitive-propagated-inputs package)
553 "Return the propagated inputs of PACKAGE, and their propagated inputs,
554recursively."
555 (transitive-inputs (package-propagated-inputs package)))
556
a193b824
MW
557(define-syntax define-memoized/v
558 (lambda (form)
559 "Define a memoized single-valued unary procedure with docstring.
560The procedure argument is compared to cached keys using `eqv?'."
561 (syntax-case form ()
562 ((_ (proc arg) docstring body body* ...)
563 (string? (syntax->datum #'docstring))
564 #'(define proc
565 (let ((cache (make-hash-table)))
566 (define (proc arg)
567 docstring
568 (match (hashv-get-handle cache arg)
569 ((_ . value)
570 value)
571 (_
572 (let ((result (let () body body* ...)))
573 (hashv-set! cache arg result)
574 result))))
575 proc))))))
c37a74bd 576
a193b824 577(define-memoized/v (package-transitive-supported-systems package)
7c3c0374
LC
578 "Return the intersection of the systems supported by PACKAGE and those
579supported by its dependencies."
a193b824
MW
580 (fold (lambda (input systems)
581 (match input
582 ((label (? package? p) . _)
583 (lset-intersection
584 string=? systems (package-transitive-supported-systems p)))
585 (_
586 systems)))
587 (package-supported-systems package)
588 (package-direct-inputs package)))
7c3c0374 589
0d5a559f
LC
590(define (bag-transitive-inputs bag)
591 "Same as 'package-transitive-inputs', but applied to a bag."
592 (transitive-inputs (append (bag-build-inputs bag)
593 (bag-host-inputs bag)
594 (bag-target-inputs bag))))
595
596(define (bag-transitive-build-inputs bag)
597 "Same as 'package-transitive-native-inputs', but applied to a bag."
598 (transitive-inputs (bag-build-inputs bag)))
599
600(define (bag-transitive-host-inputs bag)
601 "Same as 'package-transitive-target-inputs', but applied to a bag."
602 (transitive-inputs (bag-host-inputs bag)))
603
604(define (bag-transitive-target-inputs bag)
605 "Return the \"target inputs\" of BAG, recursively."
606 (transitive-inputs (bag-target-inputs bag)))
607
a2ebaddd
LC
608\f
609;;;
610;;; Package derivations.
611;;;
612
613(define %derivation-cache
614 ;; Package to derivation-path mapping.
e4588af9 615 (make-weak-key-hash-table 100))
a2ebaddd 616
e509d152
LC
617(define (cache package system thunk)
618 "Memoize the return values of THUNK as the derivation of PACKAGE on
619SYSTEM."
bce7526f
LC
620 ;; FIXME: This memoization should be associated with the open store, because
621 ;; otherwise it breaks when switching to a different store.
e509d152
LC
622 (let ((vals (call-with-values thunk list)))
623 ;; Use `hashq-set!' instead of `hash-set!' because `hash' returns the
624 ;; same value for all structs (as of Guile 2.0.6), and because pointer
625 ;; equality is sufficient in practice.
8dcec914
LC
626 (hashq-set! %derivation-cache package
627 `((,system ,@vals)
628 ,@(or (hashq-ref %derivation-cache package)
629 '())))
e509d152
LC
630 (apply values vals)))
631
632(define-syntax-rule (cached package system body ...)
633 "Memoize the result of BODY for the arguments PACKAGE and SYSTEM.
634Return the cached result when available."
8dcec914
LC
635 (let ((thunk (lambda () body ...))
636 (key system))
e509d152
LC
637 (match (hashq-ref %derivation-cache package)
638 ((alist (... ...))
8dcec914 639 (match (assoc-ref alist key)
e509d152
LC
640 ((vals (... ...))
641 (apply values vals))
642 (#f
8dcec914 643 (cache package key thunk))))
e509d152 644 (#f
8dcec914 645 (cache package key thunk)))))
a2ebaddd 646
a63062b5
LC
647(define* (expand-input store package input system #:optional cross-system)
648 "Expand INPUT, an input tuple, such that it contains only references to
649derivation paths or store paths. PACKAGE is only used to provide contextual
650information in exceptions."
592ef6c8
LC
651 (define (intern file)
652 ;; Add FILE to the store. Set the `recursive?' bit to #t, so that
653 ;; file permissions are preserved.
a9ebd9ef 654 (add-to-store store (basename file) #t "sha256" file))
592ef6c8 655
a63062b5
LC
656 (define derivation
657 (if cross-system
05962f29
LC
658 (cut package-cross-derivation store <> cross-system system
659 #:graft? #f)
660 (cut package-derivation store <> system #:graft? #f)))
a63062b5
LC
661
662 (match input
663 (((? string? name) (? package? package))
664 (list name (derivation package)))
665 (((? string? name) (? package? package)
666 (? string? sub-drv))
667 (list name (derivation package)
668 sub-drv))
669 (((? string? name)
670 (and (? string?) (? derivation-path?) drv))
671 (list name drv))
672 (((? string? name)
673 (and (? string?) (? file-exists? file)))
674 ;; Add FILE to the store. When FILE is in the sub-directory of a
675 ;; store path, it needs to be added anyway, so it can be used as a
676 ;; source.
677 (list name (intern file)))
678 (((? string? name) (? origin? source))
679 (list name (package-source-derivation store source system)))
680 (x
681 (raise (condition (&package-input-error
682 (package package)
683 (input x)))))))
592ef6c8 684
05962f29
LC
685(define %graft?
686 ;; Whether to honor package grafts by default.
687 (make-parameter #t))
688
0d5a559f
LC
689(define* (package->bag package #:optional
690 (system (%current-system))
05962f29
LC
691 (target (%current-target-system))
692 #:key (graft? (%graft?)))
0d5a559f
LC
693 "Compile PACKAGE into a bag for SYSTEM, possibly cross-compiled to TARGET,
694and return it."
695 ;; Bind %CURRENT-SYSTEM and %CURRENT-TARGET-SYSTEM so that thunked field
696 ;; values can refer to it.
697 (parameterize ((%current-system system)
698 (%current-target-system target))
05962f29
LC
699 (match (if graft?
700 (or (package-replacement package) package)
701 package)
0d5a559f
LC
702 (($ <package> name version source build-system
703 args inputs propagated-inputs native-inputs self-native-input?
704 outputs)
05962f29 705 (or (make-bag build-system (string-append name "-" version)
d3d337d2 706 #:system system
0d5a559f
LC
707 #:target target
708 #:source source
709 #:inputs (append (inputs)
710 (propagated-inputs))
711 #:outputs outputs
712 #:native-inputs `(,@(if (and target self-native-input?)
713 `(("self" ,package))
714 '())
715 ,@(native-inputs))
716 #:arguments (args))
717 (raise (if target
718 (condition
719 (&package-cross-build-system-error
720 (package package)))
721 (condition
722 (&package-error
723 (package package))))))))))
724
05962f29
LC
725(define (input-graft store system)
726 "Return a procedure that, given an input referring to a package with a
727graft, returns a pair with the original derivation and the graft's derivation,
728and returns #f for other inputs."
729 (match-lambda
730 ((label (? package? package) sub-drv ...)
731 (let ((replacement (package-replacement package)))
732 (and replacement
733 (let ((orig (package-derivation store package system
734 #:graft? #f))
735 (new (package-derivation store replacement system)))
736 (graft
737 (origin orig)
738 (replacement new)
739 (origin-output (match sub-drv
740 (() "out")
741 ((output) output)))
742 (replacement-output origin-output))))))
743 (x
744 #f)))
745
746(define (input-cross-graft store target system)
747 "Same as 'input-graft', but for cross-compilation inputs."
748 (match-lambda
749 ((label (? package? package) sub-drv ...)
750 (let ((replacement (package-replacement package)))
751 (and replacement
752 (let ((orig (package-cross-derivation store package target system
753 #:graft? #f))
754 (new (package-cross-derivation store replacement
755 target system)))
756 (graft
757 (origin orig)
758 (replacement new)
759 (origin-output (match sub-drv
760 (() "out")
761 ((output) output)))
762 (replacement-output origin-output))))))
763 (_
764 #f)))
765
766(define* (bag-grafts store bag)
767 "Return the list of grafts applicable to BAG. Each graft is a <graft>
768record."
769 (let ((target (bag-target bag))
770 (system (bag-system bag)))
771 (define native-grafts
772 (filter-map (input-graft store system)
773 (append (bag-transitive-build-inputs bag)
774 (bag-transitive-target-inputs bag)
775 (if target
776 '()
777 (bag-transitive-host-inputs bag)))))
778
779 (define target-grafts
780 (if target
781 (filter-map (input-cross-graft store target system)
782 (bag-transitive-host-inputs bag))
783 '()))
784
785 (append native-grafts target-grafts)))
786
787(define* (package-grafts store package
788 #:optional (system (%current-system))
789 #:key target)
790 "Return the list of grafts applicable to PACKAGE as built for SYSTEM and
791TARGET."
792 (let* ((package (or (package-replacement package) package))
793 (bag (package->bag package system target)))
794 (bag-grafts store bag)))
795
d3d337d2
LC
796(define* (bag->derivation store bag
797 #:optional context)
798 "Return the derivation to build BAG for SYSTEM. Optionally, CONTEXT can be
799a package object describing the context in which the call occurs, for improved
800error reporting."
801 (if (bag-target bag)
802 (bag->cross-derivation store bag)
803 (let* ((system (bag-system bag))
804 (inputs (bag-transitive-inputs bag))
805 (input-drvs (map (cut expand-input store context <> system)
806 inputs))
807 (paths (delete-duplicates
808 (append-map (match-lambda
809 ((_ (? package? p) _ ...)
810 (package-native-search-paths
811 p))
812 (_ '()))
813 inputs))))
814
815 (apply (bag-build bag)
816 store (bag-name bag) input-drvs
817 #:search-paths paths
818 #:outputs (bag-outputs bag) #:system system
819 (bag-arguments bag)))))
820
821(define* (bag->cross-derivation store bag
822 #:optional context)
823 "Return the derivation to build BAG, which is actually a cross build.
824Optionally, CONTEXT can be a package object denoting the context of the call.
825This is an internal procedure."
826 (let* ((system (bag-system bag))
827 (target (bag-target bag))
828 (host (bag-transitive-host-inputs bag))
829 (host-drvs (map (cut expand-input store context <> system target)
830 host))
831 (target* (bag-transitive-target-inputs bag))
832 (target-drvs (map (cut expand-input store context <> system)
833 target*))
834 (build (bag-transitive-build-inputs bag))
835 (build-drvs (map (cut expand-input store context <> system)
836 build))
837 (all (append build target* host))
838 (paths (delete-duplicates
839 (append-map (match-lambda
840 ((_ (? package? p) _ ...)
841 (package-search-paths p))
842 (_ '()))
843 all)))
844 (npaths (delete-duplicates
845 (append-map (match-lambda
846 ((_ (? package? p) _ ...)
847 (package-native-search-paths
848 p))
849 (_ '()))
850 all))))
851
852 (apply (bag-build bag)
853 store (bag-name bag)
854 #:native-drvs build-drvs
855 #:target-drvs (append host-drvs target-drvs)
856 #:search-paths paths
857 #:native-search-paths npaths
858 #:outputs (bag-outputs bag)
859 #:system system #:target target
860 (bag-arguments bag))))
861
a63062b5 862(define* (package-derivation store package
05962f29
LC
863 #:optional (system (%current-system))
864 #:key (graft? (%graft?)))
59688fc4
LC
865 "Return the <derivation> object of PACKAGE for SYSTEM."
866
e509d152
LC
867 ;; Compute the derivation and cache the result. Caching is important
868 ;; because some derivations, such as the implicit inputs of the GNU build
869 ;; system, will be queried many, many times in a row.
05962f29
LC
870 (cached package (cons system graft?)
871 (let* ((bag (package->bag package system #f #:graft? graft?))
872 (drv (bag->derivation store bag package)))
873 (if graft?
874 (match (bag-grafts store bag)
875 (()
876 drv)
877 (grafts
878 (let ((guile (package-derivation store (default-guile)
879 system #:graft? #f)))
880 (graft-derivation store (bag-name bag) drv grafts
881 #:system system
882 #:guile guile))))
883 drv))))
e3ce5d70 884
9c1edabd 885(define* (package-cross-derivation store package target
05962f29
LC
886 #:optional (system (%current-system))
887 #:key (graft? (%graft?)))
9c1edabd
LC
888 "Cross-build PACKAGE for TARGET (a GNU triplet) from host SYSTEM (a Guix
889system identifying string)."
05962f29
LC
890 (cached package (list system target graft?)
891 (let* ((bag (package->bag package system target #:graft? graft?))
892 (drv (bag->derivation store bag package)))
893 (if graft?
894 (match (bag-grafts store bag)
895 (()
896 drv)
897 (grafts
898 (graft-derivation store (bag-name bag) drv grafts
899 #:system system
900 #:guile
901 (package-derivation store (default-guile)
902 system #:graft? #f))))
903 drv))))
d510ab46 904
de8bcdae
LC
905(define* (package-output store package
906 #:optional (output "out") (system (%current-system)))
d510ab46
LC
907 "Return the output path of PACKAGE's OUTPUT for SYSTEM---where OUTPUT is the
908symbolic output name, such as \"out\". Note that this procedure calls
909`package-derivation', which is costly."
59688fc4
LC
910 (let ((drv (package-derivation store package system)))
911 (derivation->output-path drv output)))
e87f0591
LC
912
913\f
914;;;
915;;; Monadic interface.
916;;;
917
918(define (set-guile-for-build guile)
919 "This monadic procedure changes the Guile currently used to run the build
920code of derivations to GUILE, a package object."
921 (lambda (store)
922 (let ((guile (package-derivation store guile)))
923 (%guile-for-build guile))))
924
925(define* (package-file package
926 #:optional file
927 #:key
928 system (output "out") target)
929 "Return as a monadic value the absolute file name of FILE within the
930OUTPUT directory of PACKAGE. When FILE is omitted, return the name of the
931OUTPUT directory of PACKAGE. When TARGET is true, use it as a
932cross-compilation target triplet."
933 (lambda (store)
934 (define compute-derivation
935 (if target
936 (cut package-cross-derivation <> <> target <>)
937 package-derivation))
938
939 (let* ((system (or system (%current-system)))
940 (drv (compute-derivation store package system))
941 (out (derivation->output-path drv output)))
942 (if file
943 (string-append out "/" file)
944 out))))
945
946(define package->derivation
947 (store-lift package-derivation))
948
949(define package->cross-derivation
950 (store-lift package-cross-derivation))
951
952(define origin->derivation
953 (store-lift package-source-derivation))