guix: utils: Add fold-tree and fold-tree-leaves.
[jackhill/guix/guix.git] / guix / packages.scm
CommitLineData
233e7676 1;;; GNU Guix --- Functional package management for GNU
9b5b5c17 2;;; Copyright © 2012, 2013, 2014 Ludovic Courtès <ludo@gnu.org>
e3ce5d70 3;;;
233e7676 4;;; This file is part of GNU Guix.
e3ce5d70 5;;;
233e7676 6;;; GNU Guix is free software; you can redistribute it and/or modify it
e3ce5d70
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
e3ce5d70
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/>.
e3ce5d70
LC
18
19(define-module (guix packages)
20 #:use-module (guix utils)
c0cd1b3e 21 #:use-module (guix records)
e3ce5d70 22 #:use-module (guix store)
ddc29a78 23 #:use-module (guix base32)
d510ab46 24 #:use-module (guix derivations)
e3ce5d70
LC
25 #:use-module (guix build-system)
26 #:use-module (ice-9 match)
062c6927 27 #:use-module (srfi srfi-1)
946b72c9 28 #:use-module (srfi srfi-9 gnu)
a63062b5 29 #:use-module (srfi srfi-26)
d36622dc
LC
30 #:use-module (srfi srfi-34)
31 #:use-module (srfi srfi-35)
cd52703a
LC
32 #:re-export (%current-system
33 %current-target-system)
ff352cfb 34 #:export (origin
90c68be8
LC
35 origin?
36 origin-uri
37 origin-method
38 origin-sha256
39 origin-file-name
ac10e0e1
LC
40 origin-patches
41 origin-patch-flags
42 origin-patch-inputs
43 origin-patch-guile
f9cc8971
LC
44 origin-snippet
45 origin-modules
46 origin-imported-modules
e4c245f8 47 base32
e3ce5d70 48
a18eda27
LC
49 <search-path-specification>
50 search-path-specification
51 search-path-specification?
52 search-path-specification->sexp
53
e3ce5d70
LC
54 package
55 package?
56 package-name
57 package-version
2847050a 58 package-full-name
e3ce5d70
LC
59 package-source
60 package-build-system
61 package-arguments
62 package-inputs
63 package-native-inputs
062c6927 64 package-propagated-inputs
e3ce5d70 65 package-outputs
a18eda27 66 package-native-search-paths
e3ce5d70 67 package-search-paths
d45122f5 68 package-synopsis
e3ce5d70 69 package-description
e3ce5d70 70 package-license
52bda18a 71 package-home-page
e3ce5d70
LC
72 package-platforms
73 package-maintainers
062c6927 74 package-properties
35f3c5f5 75 package-location
d66c7096 76 package-field-location
e3ce5d70 77
a3d73f59 78 package-transitive-inputs
9c1edabd
LC
79 package-transitive-target-inputs
80 package-transitive-native-inputs
113aef68 81 package-transitive-propagated-inputs
e3ce5d70
LC
82 package-source-derivation
83 package-derivation
d36622dc 84 package-cross-derivation
d510ab46 85 package-output
d36622dc
LC
86
87 &package-error
07783858 88 package-error?
d36622dc
LC
89 package-error-package
90 &package-input-error
07783858 91 package-input-error?
9b222abe
LC
92 package-error-invalid-input
93 &package-cross-build-system-error
94 package-cross-build-system-error?))
e3ce5d70
LC
95
96;;; Commentary:
97;;;
98;;; This module provides a high-level mechanism to define packages in a
99;;; Guix-based distribution.
100;;;
101;;; Code:
102
90c68be8
LC
103;; The source of a package, such as a tarball URL and fetcher---called
104;; "origin" to avoid name clash with `package-source', `source', etc.
105(define-record-type* <origin>
106 origin make-origin
107 origin?
108 (uri origin-uri) ; string
9b5b5c17 109 (method origin-method) ; procedure
90c68be8 110 (sha256 origin-sha256) ; bytevector
ac10e0e1
LC
111 (file-name origin-file-name (default #f)) ; optional file name
112 (patches origin-patches (default '())) ; list of file names
f9cc8971 113 (snippet origin-snippet (default #f)) ; sexp or #f
ac10e0e1
LC
114 (patch-flags origin-patch-flags ; list of strings
115 (default '("-p1")))
1d9bc459
LC
116
117 ;; Patching requires Guile, GNU Patch, and a few more. These two fields are
118 ;; used to specify these dependencies when needed.
ac10e0e1
LC
119 (patch-inputs origin-patch-inputs ; input list or #f
120 (default #f))
f9cc8971
LC
121 (modules origin-modules ; list of module names
122 (default '()))
123 (imported-modules origin-imported-modules ; list of module names
124 (default '()))
1d9bc459 125 (patch-guile origin-patch-guile ; package or #f
ac10e0e1 126 (default #f)))
e3ce5d70 127
f1096964
LC
128(define (print-origin origin port)
129 "Write a concise representation of ORIGIN to PORT."
130 (match origin
131 (($ <origin> uri method sha256 file-name patches)
132 (simple-format port "#<origin ~s ~a ~s ~a>"
133 uri (bytevector->base32-string sha256)
134 patches
135 (number->string (object-address origin) 16)))))
136
137(set-record-type-printer! <origin> print-origin)
138
e4c245f8
LC
139(define-syntax base32
140 (lambda (s)
141 "Return the bytevector corresponding to the given Nix-base32
142representation."
143 (syntax-case s ()
144 ((_ str)
145 (string? (syntax->datum #'str))
aba326f7 146 ;; A literal string: do the conversion at expansion time.
e4c245f8
LC
147 (with-syntax ((bv (nix-base32-string->bytevector
148 (syntax->datum #'str))))
aba326f7
LC
149 #''bv))
150 ((_ str)
151 #'(nix-base32-string->bytevector str)))))
e4c245f8 152
a18eda27
LC
153;; The specification of a search path.
154(define-record-type* <search-path-specification>
155 search-path-specification make-search-path-specification
156 search-path-specification?
157 (variable search-path-specification-variable)
158 (directories search-path-specification-directories)
159 (separator search-path-specification-separator (default ":")))
160
161(define (search-path-specification->sexp spec)
162 "Return an sexp representing SPEC, a <search-path-specification>. The sexp
163corresponds to the arguments expected by `set-path-environment-variable'."
164 (match spec
165 (($ <search-path-specification> variable directories separator)
166 `(,variable ,directories ,separator))))
d36622dc 167
a18eda27 168;; A package.
e3ce5d70
LC
169(define-record-type* <package>
170 package make-package
171 package?
172 (name package-name) ; string
173 (version package-version) ; string
90c68be8 174 (source package-source) ; <origin> instance
e3ce5d70 175 (build-system package-build-system) ; build system
64fddd74 176 (arguments package-arguments ; arguments for the build method
21c203a5 177 (default '()) (thunked))
062c6927 178
e3ce5d70 179 (inputs package-inputs ; input packages or derivations
dd6b9a37 180 (default '()) (thunked))
062c6927 181 (propagated-inputs package-propagated-inputs ; same, but propagated
9d97a1b3 182 (default '()) (thunked))
e3ce5d70 183 (native-inputs package-native-inputs ; native input packages/derivations
a7dc055b 184 (default '()) (thunked))
c9d01150
LC
185 (self-native-input? package-self-native-input? ; whether to use itself as
186 ; a native input when cross-
187 (default #f)) ; compiling
062c6927 188
e3ce5d70
LC
189 (outputs package-outputs ; list of strings
190 (default '("out")))
a18eda27
LC
191
192 ; lists of
193 ; <search-path-specification>,
194 ; for native and cross
195 ; inputs
196 (native-search-paths package-native-search-paths (default '()))
197 (search-paths package-search-paths (default '()))
e3ce5d70 198
d45122f5
LC
199 (synopsis package-synopsis) ; one-line description
200 (description package-description) ; one or two paragraphs
1fb78cb2 201 (license package-license)
45753b65 202 (home-page package-home-page)
e3ce5d70 203 (platforms package-platforms (default '()))
35f3c5f5 204 (maintainers package-maintainers (default '()))
45753b65 205
062c6927
LC
206 (properties package-properties (default '())) ; alist for anything else
207
35f3c5f5
LC
208 (location package-location
209 (default (and=> (current-source-location)
210 source-properties->location))))
e3ce5d70 211
946b72c9
LC
212(set-record-type-printer! <package>
213 (lambda (package port)
214 (let ((loc (package-location package))
215 (format simple-format))
216 (format port "#<package ~a-~a ~a:~a ~a>"
217 (package-name package)
218 (package-version package)
219 (location-file loc)
220 (location-line loc)
221 (number->string (object-address
222 package)
223 16)))))
224
d66c7096 225(define (package-field-location package field)
f903dc05
LC
226 "Return the source code location of the definition of FIELD for PACKAGE, or
227#f if it could not be determined."
228 (define (goto port line column)
229 (unless (and (= (port-column port) (- column 1))
230 (= (port-line port) (- line 1)))
231 (unless (eof-object? (read-char port))
232 (goto port line column))))
d66c7096
LC
233
234 (match (package-location package)
235 (($ <location> file line column)
236 (catch 'system
237 (lambda ()
0b8749b7
LC
238 ;; In general we want to keep relative file names for modules.
239 (with-fluids ((%file-port-name-canonicalization 'relative))
240 (call-with-input-file (search-path %load-path file)
241 (lambda (port)
242 (goto port line column)
243 (match (read port)
244 (('package inits ...)
245 (let ((field (assoc field inits)))
246 (match field
247 ((_ value)
248 ;; Put the `or' here, and not in the first argument of
249 ;; `and=>', to work around a compiler bug in 2.0.5.
250 (or (and=> (source-properties value)
251 source-properties->location)
252 (and=> (source-properties field)
253 source-properties->location)))
254 (_
255 #f))))
256 (_
257 #f))))))
d66c7096 258 (lambda _
f903dc05 259 #f)))
d66c7096
LC
260 (_ #f)))
261
d36622dc
LC
262
263;; Error conditions.
264
265(define-condition-type &package-error &error
266 package-error?
267 (package package-error-package))
268
269(define-condition-type &package-input-error &package-error
270 package-input-error?
271 (input package-error-invalid-input))
272
9b222abe
LC
273(define-condition-type &package-cross-build-system-error &package-error
274 package-cross-build-system-error?)
275
d36622dc 276
2847050a
LC
277(define (package-full-name package)
278 "Return the full name of PACKAGE--i.e., `NAME-VERSION'."
279 (string-append (package-name package) "-" (package-version package)))
280
ac10e0e1
LC
281(define (%standard-patch-inputs)
282 (let ((ref (lambda (module var)
283 (module-ref (resolve-interface module) var))))
284 `(("tar" ,(ref '(gnu packages base) 'tar))
285 ("xz" ,(ref '(gnu packages compression) 'xz))
286 ("bzip2" ,(ref '(gnu packages compression) 'bzip2))
287 ("gzip" ,(ref '(gnu packages compression) 'gzip))
288 ("lzip" ,(ref '(gnu packages compression) 'lzip))
289 ("patch" ,(ref '(gnu packages base) 'patch)))))
290
1d9bc459
LC
291(define (default-guile)
292 "Return the default Guile package for SYSTEM."
293 (let ((distro (resolve-interface '(gnu packages base))))
294 (module-ref distro 'guile-final)))
ac10e0e1 295
f9cc8971 296(define* (patch-and-repack store source patches
ac10e0e1 297 #:key
f9cc8971
LC
298 (inputs '())
299 (snippet #f)
ac10e0e1 300 (flags '("-p1"))
f9cc8971
LC
301 (modules '())
302 (imported-modules '())
ac10e0e1
LC
303 (guile-for-build (%guile-for-build))
304 (system (%current-system)))
f9cc8971
LC
305 "Unpack SOURCE (a derivation or store path), apply all of PATCHES, and
306repack the tarball using the tools listed in INPUTS. When SNIPPET is true,
307it must be an s-expression that will run from within the directory where
308SOURCE was unpacked, after all of PATCHES have been applied. MODULES and
309IMPORTED-MODULES specify modules to use/import for use by SNIPPET."
310 (define source-file-name
311 ;; SOURCE is usually a derivation, but it could be a store file.
312 (if (derivation? source)
313 (derivation->output-path source)
314 source))
315
ac10e0e1 316 (define decompression-type
f9cc8971
LC
317 (cond ((string-suffix? "gz" source-file-name) "gzip")
318 ((string-suffix? "bz2" source-file-name) "bzip2")
319 ((string-suffix? "lz" source-file-name) "lzip")
320 (else "xz")))
ac10e0e1
LC
321
322 (define original-file-name
f9cc8971
LC
323 ;; Remove the store prefix plus the slash, hash, and hyphen.
324 (let* ((sans (string-drop source-file-name
325 (+ (string-length (%store-prefix)) 1)))
326 (dash (string-index sans #\-)))
327 (string-drop sans (+ 1 dash))))
ac10e0e1 328
3ca00bb5
LC
329 (define (numeric-extension? file-name)
330 ;; Return true if FILE-NAME ends with digits.
857ecb3d
LC
331 (and=> (file-extension file-name)
332 (cut string-every char-set:hex-digit <>)))
3ca00bb5
LC
333
334 (define (tarxz-name file-name)
335 ;; Return a '.tar.xz' file name based on FILE-NAME.
336 (let ((base (if (numeric-extension? file-name)
337 original-file-name
338 (file-sans-extension file-name))))
339 (string-append base
340 (if (equal? (file-extension base) "tar")
341 ".xz"
342 ".tar.xz"))))
343
ac10e0e1
LC
344 (define patch-inputs
345 (map (lambda (number patch)
346 (list (string-append "patch" (number->string number))
347 (add-to-store store (basename patch) #t
348 "sha256" patch)))
349 (iota (length patches))
350
351 patches))
352
353 (define builder
354 `(begin
355 (use-modules (ice-9 ftw)
3ca00bb5
LC
356 (srfi srfi-1)
357 (guix build utils))
ac10e0e1
LC
358
359 (let ((out (assoc-ref %outputs "out"))
360 (xz (assoc-ref %build-inputs "xz"))
361 (decomp (assoc-ref %build-inputs ,decompression-type))
362 (source (assoc-ref %build-inputs "source"))
363 (tar (string-append (assoc-ref %build-inputs "tar")
364 "/bin/tar"))
365 (patch (string-append (assoc-ref %build-inputs "patch")
366 "/bin/patch")))
367 (define (apply-patch input)
368 (let ((patch* (assoc-ref %build-inputs input)))
369 (format (current-error-port) "applying '~a'...~%" patch*)
370 (zero? (system* patch "--batch" ,@flags "--input" patch*))))
371
3ca00bb5
LC
372 (define (first-file directory)
373 ;; Return the name of the first file in DIRECTORY.
374 (car (scandir directory
375 (lambda (name)
376 (not (member name '("." "..")))))))
377
ac10e0e1
LC
378 (setenv "PATH" (string-append xz "/bin" ":"
379 decomp "/bin"))
3ca00bb5
LC
380
381 ;; SOURCE may be either a directory or a tarball.
382 (and (if (file-is-directory? source)
8be3b8a3 383 (let* ((store (or (getenv "NIX_STORE") "/gnu/store"))
3ca00bb5
LC
384 (len (+ 1 (string-length store)))
385 (base (string-drop source len))
386 (dash (string-index base #\-))
387 (directory (string-drop base (+ 1 dash))))
388 (mkdir directory)
389 (copy-recursively source directory)
390 #t)
391 (zero? (system* tar "xvf" source)))
392 (let ((directory (first-file ".")))
ac10e0e1
LC
393 (format (current-error-port)
394 "source is under '~a'~%" directory)
395 (chdir directory)
f9cc8971 396
ac10e0e1 397 (and (every apply-patch ',(map car patch-inputs))
f9cc8971
LC
398
399 ,@(if snippet
400 `((let ((module (make-fresh-user-module)))
401 (module-use-interfaces! module
402 (map resolve-interface
403 ',modules))
404 (module-define! module '%build-inputs
405 %build-inputs)
406 (module-define! module '%outputs %outputs)
407 ((@ (system base compile) compile)
408 ',snippet
409 #:to 'value
410 #:opts %auto-compilation-options
411 #:env module)))
412 '())
413
ac10e0e1
LC
414 (begin (chdir "..") #t)
415 (zero? (system* tar "cvfa" out directory))))))))
416
417
3ca00bb5
LC
418 (let ((name (tarxz-name original-file-name))
419 (inputs (filter-map (match-lambda
420 ((name (? package? p))
421 (and (member name (cons decompression-type
422 '("tar" "xz" "patch")))
423 (list name
424 (package-derivation store p
425 system)))))
426 (or inputs (%standard-patch-inputs))))
427 (modules (delete-duplicates (cons '(guix build utils) modules))))
ac10e0e1 428
3ca00bb5 429 (build-expression->derivation store name builder
dd1a5a15
LC
430 #:inputs `(("source" ,source)
431 ,@inputs
432 ,@patch-inputs)
433 #:system system
3ca00bb5 434 #:modules modules
ac10e0e1
LC
435 #:guile-for-build guile-for-build)))
436
b642e4b8
LC
437(define* (package-source-derivation store source
438 #:optional (system (%current-system)))
439 "Return the derivation path for SOURCE, a package source, for SYSTEM."
e3ce5d70 440 (match source
f9cc8971
LC
441 (($ <origin> uri method sha256 name () #f)
442 ;; No patches, no snippet: this is a fixed-output derivation.
b642e4b8 443 (method store uri 'sha256 sha256 name
7357138b 444 #:system system))
f9cc8971
LC
445 (($ <origin> uri method sha256 name (patches ...) snippet
446 (flags ...) inputs (modules ...) (imported-modules ...)
447 guile-for-build)
448 ;; Patches and/or a snippet.
ac10e0e1 449 (let ((source (method store uri 'sha256 sha256 name
1d9bc459
LC
450 #:system system))
451 (guile (match (or guile-for-build (%guile-for-build)
452 (default-guile))
453 ((? package? p)
454 (package-derivation store p system))
455 ((? derivation? drv)
456 drv))))
f9cc8971
LC
457 (patch-and-repack store source patches
458 #:inputs inputs
459 #:snippet snippet
ac10e0e1
LC
460 #:flags flags
461 #:system system
f9cc8971
LC
462 #:modules modules
463 #:imported-modules modules
1d9bc459 464 #:guile-for-build guile)))
f80594cc 465 ((and (? string?) (? direct-store-path?) file)
7357138b
LC
466 file)
467 ((? string? file)
468 (add-to-store store (basename file) #t "sha256" file))))
e3ce5d70 469
113aef68
LC
470(define (transitive-inputs inputs)
471 (let loop ((inputs inputs)
a3d73f59
LC
472 (result '()))
473 (match inputs
474 (()
475 (delete-duplicates (reverse result))) ; XXX: efficiency
476 (((and i (name (? package? p) sub ...)) rest ...)
477 (let ((t (map (match-lambda
478 ((dep-name derivation ...)
479 (cons (string-append name "/" dep-name)
480 derivation)))
481 (package-propagated-inputs p))))
482 (loop (append t rest)
483 (append t (cons i result)))))
484 ((input rest ...)
485 (loop rest (cons input result))))))
486
113aef68
LC
487(define (package-transitive-inputs package)
488 "Return the transitive inputs of PACKAGE---i.e., its direct inputs along
489with their propagated inputs, recursively."
490 (transitive-inputs (append (package-native-inputs package)
491 (package-inputs package)
492 (package-propagated-inputs package))))
493
9c1edabd
LC
494(define (package-transitive-target-inputs package)
495 "Return the transitive target inputs of PACKAGE---i.e., its direct inputs
496along with their propagated inputs, recursively. This only includes inputs
497for the target system, and not native inputs."
498 (transitive-inputs (append (package-inputs package)
499 (package-propagated-inputs package))))
500
501(define (package-transitive-native-inputs package)
502 "Return the transitive native inputs of PACKAGE---i.e., its direct inputs
503along with their propagated inputs, recursively. This only includes inputs
504for the host system (\"native inputs\"), and not target inputs."
505 (transitive-inputs (package-native-inputs package)))
506
113aef68
LC
507(define (package-transitive-propagated-inputs package)
508 "Return the propagated inputs of PACKAGE, and their propagated inputs,
509recursively."
510 (transitive-inputs (package-propagated-inputs package)))
511
a2ebaddd
LC
512\f
513;;;
514;;; Package derivations.
515;;;
516
517(define %derivation-cache
518 ;; Package to derivation-path mapping.
e4588af9 519 (make-weak-key-hash-table 100))
a2ebaddd 520
e509d152
LC
521(define (cache package system thunk)
522 "Memoize the return values of THUNK as the derivation of PACKAGE on
523SYSTEM."
524 (let ((vals (call-with-values thunk list)))
525 ;; Use `hashq-set!' instead of `hash-set!' because `hash' returns the
526 ;; same value for all structs (as of Guile 2.0.6), and because pointer
527 ;; equality is sufficient in practice.
528 (hashq-set! %derivation-cache package `((,system ,@vals)))
529 (apply values vals)))
530
531(define-syntax-rule (cached package system body ...)
532 "Memoize the result of BODY for the arguments PACKAGE and SYSTEM.
533Return the cached result when available."
534 (let ((thunk (lambda () body ...)))
535 (match (hashq-ref %derivation-cache package)
536 ((alist (... ...))
537 (match (assoc-ref alist system)
538 ((vals (... ...))
539 (apply values vals))
540 (#f
541 (cache package system thunk))))
542 (#f
543 (cache package system thunk)))))
a2ebaddd 544
a63062b5
LC
545(define* (expand-input store package input system #:optional cross-system)
546 "Expand INPUT, an input tuple, such that it contains only references to
547derivation paths or store paths. PACKAGE is only used to provide contextual
548information in exceptions."
592ef6c8
LC
549 (define (intern file)
550 ;; Add FILE to the store. Set the `recursive?' bit to #t, so that
551 ;; file permissions are preserved.
a9ebd9ef 552 (add-to-store store (basename file) #t "sha256" file))
592ef6c8 553
a63062b5
LC
554 (define derivation
555 (if cross-system
556 (cut package-cross-derivation store <> cross-system system)
557 (cut package-derivation store <> system)))
558
559 (match input
560 (((? string? name) (? package? package))
561 (list name (derivation package)))
562 (((? string? name) (? package? package)
563 (? string? sub-drv))
564 (list name (derivation package)
565 sub-drv))
566 (((? string? name)
567 (and (? string?) (? derivation-path?) drv))
568 (list name drv))
569 (((? string? name)
570 (and (? string?) (? file-exists? file)))
571 ;; Add FILE to the store. When FILE is in the sub-directory of a
572 ;; store path, it needs to be added anyway, so it can be used as a
573 ;; source.
574 (list name (intern file)))
575 (((? string? name) (? origin? source))
576 (list name (package-source-derivation store source system)))
577 (x
578 (raise (condition (&package-input-error
579 (package package)
580 (input x)))))))
592ef6c8 581
a63062b5
LC
582(define* (package-derivation store package
583 #:optional (system (%current-system)))
59688fc4
LC
584 "Return the <derivation> object of PACKAGE for SYSTEM."
585
e509d152
LC
586 ;; Compute the derivation and cache the result. Caching is important
587 ;; because some derivations, such as the implicit inputs of the GNU build
588 ;; system, will be queried many, many times in a row.
589 (cached package system
21c203a5
LC
590
591 ;; Bind %CURRENT-SYSTEM so that thunked field values can refer
592 ;; to it.
9c1edabd
LC
593 (parameterize ((%current-system system)
594 (%current-target-system #f))
21c203a5
LC
595 (match package
596 (($ <package> name version source (= build-system-builder builder)
597 args inputs propagated-inputs native-inputs self-native-input?
598 outputs)
a18eda27 599 (let* ((inputs (package-transitive-inputs package))
a63062b5
LC
600 (input-drvs (map (cut expand-input
601 store package <> system)
602 inputs))
a18eda27
LC
603 (paths (delete-duplicates
604 (append-map (match-lambda
605 ((_ (? package? p) _ ...)
606 (package-native-search-paths
607 p))
608 (_ '()))
609 inputs))))
21c203a5
LC
610
611 (apply builder
612 store (package-full-name package)
613 (and source
614 (package-source-derivation store source system))
a18eda27
LC
615 input-drvs
616 #:search-paths paths
21c203a5
LC
617 #:outputs outputs #:system system
618 (args))))))))
e3ce5d70 619
9c1edabd 620(define* (package-cross-derivation store package target
a63062b5 621 #:optional (system (%current-system)))
9c1edabd
LC
622 "Cross-build PACKAGE for TARGET (a GNU triplet) from host SYSTEM (a Guix
623system identifying string)."
624 (cached package (cons system target)
625
626 ;; Bind %CURRENT-SYSTEM so that thunked field values can refer
627 ;; to it.
628 (parameterize ((%current-system system)
629 (%current-target-system target))
630 (match package
631 (($ <package> name version source
632 (= build-system-cross-builder builder)
633 args inputs propagated-inputs native-inputs self-native-input?
634 outputs)
9b222abe
LC
635 (unless builder
636 (raise (condition
637 (&package-cross-build-system-error
638 (package package)))))
639
9c1edabd
LC
640 (let* ((inputs (package-transitive-target-inputs package))
641 (input-drvs (map (cut expand-input
642 store package <>
643 system target)
644 inputs))
645 (host (append (if self-native-input?
646 `(("self" ,package))
647 '())
648 (package-transitive-native-inputs package)))
649 (host-drvs (map (cut expand-input
650 store package <> system)
651 host))
652 (all (append host inputs))
653 (paths (delete-duplicates
654 (append-map (match-lambda
655 ((_ (? package? p) _ ...)
656 (package-search-paths p))
657 (_ '()))
658 all)))
659 (npaths (delete-duplicates
660 (append-map (match-lambda
661 ((_ (? package? p) _ ...)
662 (package-native-search-paths
663 p))
664 (_ '()))
665 all))))
666
667 (apply builder
668 store (package-full-name package) target
669 (and source
670 (package-source-derivation store source system))
671 input-drvs host-drvs
672 #:search-paths paths
673 #:native-search-paths npaths
674 #:outputs outputs #:system system
675 (args))))))))
d510ab46 676
de8bcdae
LC
677(define* (package-output store package
678 #:optional (output "out") (system (%current-system)))
d510ab46
LC
679 "Return the output path of PACKAGE's OUTPUT for SYSTEM---where OUTPUT is the
680symbolic output name, such as \"out\". Note that this procedure calls
681`package-derivation', which is costly."
59688fc4
LC
682 (let ((drv (package-derivation store package system)))
683 (derivation->output-path drv output)))