build-system: Rewrite using gexps.
[jackhill/guix/guix.git] / guix / packages.scm
CommitLineData
233e7676 1;;; GNU Guix --- Functional package management for GNU
f41ff532 2;;; Copyright © 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Ludovic Courtès <ludo@gnu.org>
57320087 3;;; Copyright © 2014, 2015, 2017, 2018 Mark H Weaver <mhw@netris.org>
a6d0b306 4;;; Copyright © 2015 Eric Bavier <bavier@member.fsf.org>
8d65c71f 5;;; Copyright © 2016 Alex Kost <alezost@gmail.com>
6741f543 6;;; Copyright © 2017, 2019, 2020 Efraim Flashner <efraim@flashner.co.il>
814e12dc 7;;; Copyright © 2019 Marius Bakke <mbakke@fastmail.com>
cfcead2e 8;;; Copyright © 2020, 2021 Maxim Cournoyer <maxim.cournoyer@gmail.com>
a16eb6c5 9;;; Copyright © 2021 Chris Marusich <cmmarusich@gmail.com>
e3ce5d70 10;;;
233e7676 11;;; This file is part of GNU Guix.
e3ce5d70 12;;;
233e7676 13;;; GNU Guix is free software; you can redistribute it and/or modify it
e3ce5d70
LC
14;;; under the terms of the GNU General Public License as published by
15;;; the Free Software Foundation; either version 3 of the License, or (at
16;;; your option) any later version.
17;;;
233e7676 18;;; GNU Guix is distributed in the hope that it will be useful, but
e3ce5d70
LC
19;;; WITHOUT ANY WARRANTY; without even the implied warranty of
20;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21;;; GNU General Public License for more details.
22;;;
23;;; You should have received a copy of the GNU General Public License
233e7676 24;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
e3ce5d70
LC
25
26(define-module (guix packages)
cfcead2e
MC
27 #:use-module ((guix build utils) #:select (compressor tarball?
28 strip-store-file-name))
e3ce5d70 29 #:use-module (guix utils)
c0cd1b3e 30 #:use-module (guix records)
e3ce5d70 31 #:use-module (guix store)
e87f0591 32 #:use-module (guix monads)
ff40e9b7 33 #:use-module (guix gexp)
ddc29a78 34 #:use-module (guix base32)
56f7ca6e 35 #:autoload (guix base64) (base64-decode)
7adf9b84 36 #:use-module (guix grafts)
d510ab46 37 #:use-module (guix derivations)
c9134e82 38 #:use-module (guix memoization)
e3ce5d70 39 #:use-module (guix build-system)
e89431bf 40 #:use-module (guix search-paths)
c22a1324 41 #:use-module (guix sets)
ce0be567
LC
42 #:use-module (guix deprecation)
43 #:use-module (guix i18n)
e3ce5d70 44 #:use-module (ice-9 match)
c37a74bd 45 #:use-module (ice-9 vlist)
c423ae89 46 #:use-module (ice-9 regex)
062c6927 47 #:use-module (srfi srfi-1)
946b72c9 48 #:use-module (srfi srfi-9 gnu)
05962f29 49 #:use-module (srfi srfi-11)
a63062b5 50 #:use-module (srfi srfi-26)
d36622dc
LC
51 #:use-module (srfi srfi-34)
52 #:use-module (srfi srfi-35)
ce0be567 53 #:use-module (rnrs bytevectors)
3b4d0103 54 #:use-module (web uri)
cd52703a 55 #:re-export (%current-system
e89431bf
LC
56 %current-target-system
57 search-path-specification) ;for convenience
ce0be567
LC
58 #:export (content-hash
59 content-hash?
60 content-hash-algorithm
61 content-hash-value
62
63 origin
90c68be8 64 origin?
adb6462c 65 this-origin
90c68be8
LC
66 origin-uri
67 origin-method
ce0be567
LC
68 origin-hash
69 origin-sha256 ;deprecated
90c68be8 70 origin-file-name
3b4d0103 71 origin-actual-file-name
ac10e0e1
LC
72 origin-patches
73 origin-patch-flags
74 origin-patch-inputs
75 origin-patch-guile
f9cc8971
LC
76 origin-snippet
77 origin-modules
e4c245f8 78 base32
56f7ca6e 79 base64
e3ce5d70
LC
80
81 package
82 package?
adb6462c 83 this-package
e3ce5d70 84 package-name
3b0fcc67 85 package-upstream-name
e3ce5d70 86 package-version
2847050a 87 package-full-name
e3ce5d70
LC
88 package-source
89 package-build-system
90 package-arguments
91 package-inputs
92 package-native-inputs
062c6927 93 package-propagated-inputs
e3ce5d70 94 package-outputs
a18eda27 95 package-native-search-paths
e3ce5d70 96 package-search-paths
05962f29 97 package-replacement
d45122f5 98 package-synopsis
e3ce5d70 99 package-description
e3ce5d70 100 package-license
52bda18a 101 package-home-page
4e097f86 102 package-supported-systems
062c6927 103 package-properties
35f3c5f5 104 package-location
6980511b
LC
105 hidden-package
106 hidden-package?
01afdab8
LC
107 package-superseded
108 deprecated-package
d66c7096 109 package-field-location
e3ce5d70 110
f77bcbc3
EB
111 package-direct-sources
112 package-transitive-sources
7d193ec3 113 package-direct-inputs
a3d73f59 114 package-transitive-inputs
9c1edabd
LC
115 package-transitive-target-inputs
116 package-transitive-native-inputs
113aef68 117 package-transitive-propagated-inputs
aa8e0515 118 package-transitive-native-search-paths
7c3c0374 119 package-transitive-supported-systems
f37f2b83 120 package-mapping
2a75b0b6 121 package-input-rewriting
f258d886 122 package-input-rewriting/spec
e3ce5d70
LC
123 package-source-derivation
124 package-derivation
d36622dc 125 package-cross-derivation
d510ab46 126 package-output
05962f29 127 package-grafts
c423ae89 128 package-patched-vulnerabilities
b066c250
CD
129 package-with-patches
130 package-with-extra-patches
46135ce4 131 package-with-c-toolchain
bedba064 132 package/inherit
d36622dc 133
a6d0b306
EB
134 transitive-input-references
135
4e097f86 136 %supported-systems
035b6ff7 137 %hurd-systems
33bb89c9 138 %cuirass-supported-systems
bbceb0ef 139 supported-package?
4e097f86 140
d36622dc 141 &package-error
07783858 142 package-error?
d36622dc
LC
143 package-error-package
144 &package-input-error
07783858 145 package-input-error?
9b222abe
LC
146 package-error-invalid-input
147 &package-cross-build-system-error
0d5a559f
LC
148 package-cross-build-system-error?
149
150 package->bag
d3d337d2 151 bag->derivation
cceab875 152 bag-direct-inputs
0d5a559f
LC
153 bag-transitive-inputs
154 bag-transitive-host-inputs
155 bag-transitive-build-inputs
e87f0591 156 bag-transitive-target-inputs
3e223a22 157 package-closure
e87f0591
LC
158
159 default-guile
ff40e9b7 160 default-guile-derivation
e87f0591
LC
161 set-guile-for-build
162 package-file
163 package->derivation
164 package->cross-derivation
165 origin->derivation))
e3ce5d70
LC
166
167;;; Commentary:
168;;;
169;;; This module provides a high-level mechanism to define packages in a
170;;; Guix-based distribution.
171;;;
172;;; Code:
173
31ebecf7
MC
174(define-syntax-rule (define-compile-time-decoder name string->bytevector)
175 "Define NAME as a macro that runs STRING->BYTEVECTOR at macro expansion time
176if possible."
177 (define-syntax name
178 (lambda (s)
179 "Return the bytevector corresponding to the given textual
180representation."
181 (syntax-case s ()
182 ((_ str)
183 (string? (syntax->datum #'str))
184 ;; A literal string: do the conversion at expansion time.
185 (with-syntax ((bv (string->bytevector (syntax->datum #'str))))
186 #''bv))
187 ((_ str)
188 #'(string->bytevector str))))))
189
190(define-compile-time-decoder base32 nix-base32-string->bytevector)
191(define-compile-time-decoder base64 base64-decode)
192
ce0be567
LC
193;; Crytographic content hash.
194(define-immutable-record-type <content-hash>
195 (%content-hash algorithm value)
196 content-hash?
197 (algorithm content-hash-algorithm) ;symbol
198 (value content-hash-value)) ;bytevector
199
200(define-syntax-rule (define-content-hash-constructor name
201 (algorithm size) ...)
202 "Define NAME as a <content-hash> constructor that ensures that (1) its
203second argument is among the listed ALGORITHM, and (2), when possible, that
204its first argument has the right size for the chosen algorithm."
205 (define-syntax name
206 (lambda (s)
207 (syntax-case s (algorithm ...)
208 ((_ bv algorithm)
209 (let ((bv* (syntax->datum #'bv)))
210 (when (and (bytevector? bv*)
211 (not (= size (bytevector-length bv*))))
212 (syntax-violation 'content-hash "invalid content hash length" s))
213 #'(%content-hash 'algorithm bv)))
214 ...))))
215
216(define-content-hash-constructor build-content-hash
217 (sha256 32)
0505eda9
LC
218 (sha512 64)
219 (sha3-256 32)
220 (sha3-512 64)
221 (blake2s-256 64))
ce0be567
LC
222
223(define-syntax content-hash
224 (lambda (s)
225 "Return a content hash with the given parameters. The default hash
226algorithm is sha256. If the first argument is a literal string, it is decoded
227as base32. Otherwise, it must be a bytevector."
228 ;; What we'd really want here is something like C++ 'constexpr'.
229 (syntax-case s ()
230 ((_ str)
231 (string? (syntax->datum #'str))
232 #'(content-hash str sha256))
233 ((_ str algorithm)
234 (string? (syntax->datum #'str))
235 (with-syntax ((bv (base32 (syntax->datum #'str))))
236 #'(content-hash bv algorithm)))
237 ((_ (id str) algorithm)
238 (and (string? (syntax->datum #'str))
239 (free-identifier=? #'id #'base32))
240 (with-syntax ((bv (nix-base32-string->bytevector (syntax->datum #'str))))
241 #'(content-hash bv algorithm)))
242 ((_ (id str) algorithm)
243 (and (string? (syntax->datum #'str))
244 (free-identifier=? #'id #'base64))
245 (with-syntax ((bv (base64-decode (syntax->datum #'str))))
246 #'(content-hash bv algorithm)))
247 ((_ bv)
248 #'(content-hash bv sha256))
249 ((_ bv hash)
250 #'(build-content-hash bv hash)))))
251
252(define (print-content-hash hash port)
253 (format port "#<content-hash ~a:~a>"
254 (content-hash-algorithm hash)
83ec969c
LC
255 (and=> (content-hash-value hash)
256 bytevector->nix-base32-string)))
ce0be567
LC
257
258(set-record-type-printer! <content-hash> print-content-hash)
259
260\f
90c68be8
LC
261;; The source of a package, such as a tarball URL and fetcher---called
262;; "origin" to avoid name clash with `package-source', `source', etc.
263(define-record-type* <origin>
ce0be567 264 %origin make-origin
90c68be8 265 origin?
adb6462c 266 this-origin
90c68be8 267 (uri origin-uri) ; string
9b5b5c17 268 (method origin-method) ; procedure
ce0be567 269 (hash origin-hash) ; <content-hash>
ac10e0e1 270 (file-name origin-file-name (default #f)) ; optional file name
6b1f9721
LC
271
272 ;; Patches are delayed so that the 'search-patch' calls are made lazily,
273 ;; which reduces I/O on startup and allows patch-not-found errors to be
274 ;; gracefully handled at run time.
275 (patches origin-patches ; list of file names
276 (default '()) (delayed))
277
f9cc8971 278 (snippet origin-snippet (default #f)) ; sexp or #f
ac10e0e1
LC
279 (patch-flags origin-patch-flags ; list of strings
280 (default '("-p1")))
1d9bc459
LC
281
282 ;; Patching requires Guile, GNU Patch, and a few more. These two fields are
283 ;; used to specify these dependencies when needed.
ac10e0e1
LC
284 (patch-inputs origin-patch-inputs ; input list or #f
285 (default #f))
f9cc8971
LC
286 (modules origin-modules ; list of module names
287 (default '()))
1929fdba 288
1d9bc459 289 (patch-guile origin-patch-guile ; package or #f
ac10e0e1 290 (default #f)))
e3ce5d70 291
ce0be567
LC
292(define-syntax origin-compatibility-helper
293 (syntax-rules (sha256)
294 ((_ () (fields ...))
295 (%origin fields ...))
296 ((_ ((sha256 exp) rest ...) (others ...))
297 (%origin others ...
298 (hash (content-hash exp sha256))
299 rest ...))
300 ((_ (field rest ...) (others ...))
301 (origin-compatibility-helper (rest ...)
302 (others ... field)))))
303
304(define-syntax-rule (origin fields ...)
305 "Build an <origin> record, automatically converting 'sha256' field
306specifications to 'hash'."
307 (origin-compatibility-helper (fields ...) ()))
308
309(define-deprecated (origin-sha256 origin)
310 origin-hash
311 (let ((hash (origin-hash origin)))
312 (unless (eq? (content-hash-algorithm hash) 'sha256)
313 (raise (condition (&message
314 (message (G_ "no SHA256 hash for origin"))))))
315 (content-hash-value hash)))
316
f1096964
LC
317(define (print-origin origin port)
318 "Write a concise representation of ORIGIN to PORT."
319 (match origin
ce0be567 320 (($ <origin> uri method hash file-name patches)
f1096964 321 (simple-format port "#<origin ~s ~a ~s ~a>"
ce0be567 322 uri hash
6b1f9721 323 (force patches)
f1096964
LC
324 (number->string (object-address origin) 16)))))
325
326(set-record-type-printer! <origin> print-origin)
327
3b4d0103
EB
328(define (origin-actual-file-name origin)
329 "Return the file name of ORIGIN, either its 'file-name' field or the file
330name of its URI."
331 (define (uri->file-name uri)
332 ;; Return the 'base name' of URI or URI itself, where URI is a string.
333 (let ((path (and=> (string->uri uri) uri-path)))
334 (if path
335 (basename path)
336 uri)))
337
338 (or (origin-file-name origin)
339 (match (origin-uri origin)
340 ((head . tail)
341 (uri->file-name head))
342 ((? string? uri)
343 (uri->file-name uri))
344 (else
345 ;; git, svn, cvs, etc. reference
346 #f))))
347
ce0be567 348\f
4e097f86
LC
349(define %supported-systems
350 ;; This is the list of system types that are supported. By default, we
351 ;; expect all packages to build successfully here.
a16eb6c5
CM
352 '("x86_64-linux" "i686-linux" "armhf-linux" "aarch64-linux" "mips64el-linux" "i586-gnu"
353 "powerpc64le-linux"))
4e097f86 354
035b6ff7
LC
355(define %hurd-systems
356 ;; The GNU/Hurd systems for which support is being developed.
003fcf23 357 '("i586-gnu" "i686-gnu"))
035b6ff7 358
33bb89c9 359(define %cuirass-supported-systems
cdb3f734
LC
360 ;; This is the list of system types for which build machines are available.
361 ;;
d0428564 362 ;; XXX: MIPS is unavailable in CI:
cdb3f734 363 ;; <https://lists.gnu.org/archive/html/guix-devel/2017-03/msg00790.html>.
d0428564 364 (fold delete %supported-systems '("mips64el-linux")))
abcbda48
LC
365
366
a18eda27 367;; A package.
e3ce5d70
LC
368(define-record-type* <package>
369 package make-package
370 package?
adb6462c 371 this-package
e3ce5d70
LC
372 (name package-name) ; string
373 (version package-version) ; string
90c68be8 374 (source package-source) ; <origin> instance
e3ce5d70 375 (build-system package-build-system) ; build system
64fddd74 376 (arguments package-arguments ; arguments for the build method
21c203a5 377 (default '()) (thunked))
062c6927 378
e3ce5d70 379 (inputs package-inputs ; input packages or derivations
dd6b9a37 380 (default '()) (thunked))
062c6927 381 (propagated-inputs package-propagated-inputs ; same, but propagated
9d97a1b3 382 (default '()) (thunked))
e3ce5d70 383 (native-inputs package-native-inputs ; native input packages/derivations
a7dc055b 384 (default '()) (thunked))
062c6927 385
e3ce5d70
LC
386 (outputs package-outputs ; list of strings
387 (default '("out")))
a18eda27
LC
388
389 ; lists of
390 ; <search-path-specification>,
391 ; for native and cross
392 ; inputs
393 (native-search-paths package-native-search-paths (default '()))
394 (search-paths package-search-paths (default '()))
d5ec5ed7
LC
395
396 ;; The 'replacement' field is marked as "innate" because it never makes
397 ;; sense to inherit a replacement as is. See the 'package/inherit' macro.
05962f29 398 (replacement package-replacement ; package | #f
d5ec5ed7 399 (default #f) (thunked) (innate))
e3ce5d70 400
d45122f5
LC
401 (synopsis package-synopsis) ; one-line description
402 (description package-description) ; one or two paragraphs
1fb78cb2 403 (license package-license)
45753b65 404 (home-page package-home-page)
4e097f86
LC
405 (supported-systems package-supported-systems ; list of strings
406 (default %supported-systems))
45753b65 407
062c6927
LC
408 (properties package-properties (default '())) ; alist for anything else
409
35f3c5f5
LC
410 (location package-location
411 (default (and=> (current-source-location)
0004c590
LC
412 source-properties->location))
413 (innate)))
e3ce5d70 414
946b72c9
LC
415(set-record-type-printer! <package>
416 (lambda (package port)
417 (let ((loc (package-location package))
418 (format simple-format))
74e667d1 419 (format port "#<package ~a@~a ~a~a>"
946b72c9
LC
420 (package-name package)
421 (package-version package)
2e1bafb0
LC
422 (if loc
423 (format #f "~a:~a "
424 (location-file loc)
425 (location-line loc))
426 "")
946b72c9
LC
427 (number->string (object-address
428 package)
429 16)))))
430
2bf6f962
LC
431(define-syntax-rule (package/inherit p overrides ...)
432 "Like (package (inherit P) OVERRIDES ...), except that the same
56733080 433transformation is done to the package P's replacement, if any. P must be a bare
2bf6f962
LC
434identifier, and will be bound to either P or its replacement when evaluating
435OVERRIDES."
436 (let loop ((p p))
437 (package (inherit p)
438 overrides ...
439 (replacement (and=> (package-replacement p) loop)))))
440
3b0fcc67
LC
441(define (package-upstream-name package)
442 "Return the upstream name of PACKAGE, which could be different from the name
443it has in Guix."
444 (or (assq-ref (package-properties package) 'upstream-name)
445 (package-name package)))
446
6980511b
LC
447(define (hidden-package p)
448 "Return a \"hidden\" version of P--i.e., one that 'fold-packages' and thus,
449user interfaces, ignores."
450 (package
451 (inherit p)
452 (properties `((hidden? . #t)
453 ,@(package-properties p)))))
454
455(define (hidden-package? p)
456 "Return true if P is \"hidden\"--i.e., must not be visible to user
457interfaces."
458 (assoc-ref (package-properties p) 'hidden?))
459
01afdab8
LC
460(define (package-superseded p)
461 "Return the package the supersedes P, or #f if P is still current."
462 (assoc-ref (package-properties p) 'superseded))
463
464(define (deprecated-package old-name p)
465 "Return a package called OLD-NAME and marked as superseded by P, a package
466object."
467 (package
468 (inherit p)
469 (name old-name)
470 (properties `((superseded . ,p)))))
471
d66c7096 472(define (package-field-location package field)
f903dc05
LC
473 "Return the source code location of the definition of FIELD for PACKAGE, or
474#f if it could not be determined."
475 (define (goto port line column)
476 (unless (and (= (port-column port) (- column 1))
477 (= (port-line port) (- line 1)))
478 (unless (eof-object? (read-char port))
479 (goto port line column))))
d66c7096
LC
480
481 (match (package-location package)
482 (($ <location> file line column)
9a38bed2 483 (match (search-path %load-path file)
66c9bc35 484 ((? string? file-found)
9a38bed2
LC
485 (catch 'system-error
486 (lambda ()
487 ;; In general we want to keep relative file names for modules.
66c9bc35 488 (call-with-input-file file-found
9a38bed2
LC
489 (lambda (port)
490 (goto port line column)
491 (match (read port)
492 (('package inits ...)
493 (let ((field (assoc field inits)))
494 (match field
495 ((_ value)
496 (let ((loc (and=> (source-properties value)
497 source-properties->location)))
498 (and loc
499 ;; Preserve the original file name, which may be a
500 ;; relative file name.
501 (set-field loc (location-file) file))))
502 (_
503 #f))))
504 (_
505 #f)))))
506 (lambda _
507 #f)))
508 (#f
509 ;; FILE could not be found in %LOAD-PATH.
510 #f)))
d66c7096
LC
511 (_ #f)))
512
d36622dc
LC
513
514;; Error conditions.
515
516(define-condition-type &package-error &error
517 package-error?
518 (package package-error-package))
519
520(define-condition-type &package-input-error &package-error
521 package-input-error?
522 (input package-error-invalid-input))
523
9b222abe
LC
524(define-condition-type &package-cross-build-system-error &package-error
525 package-cross-build-system-error?)
526
ede121de
CM
527(define* (package-full-name package #:optional (delimiter "@"))
528 "Return the full name of PACKAGE--i.e., `NAME@VERSION'. By specifying
529DELIMITER (a string), you can customize what will appear between the name and
530the version. By default, DELIMITER is \"@\"."
531 (string-append (package-name package) delimiter (package-version package)))
2847050a 532
c423ae89
LC
533(define (patch-file-name patch)
534 "Return the basename of PATCH's file name, or #f if the file name could not
535be determined."
536 (match patch
537 ((? string?)
538 (basename patch))
539 ((? origin?)
540 (and=> (origin-actual-file-name patch) basename))))
541
542(define %vulnerability-regexp
543 ;; Regexp matching a CVE identifier in patch file names.
544 (make-regexp "CVE-[0-9]{4}-[0-9]+"))
545
546(define (package-patched-vulnerabilities package)
547 "Return the list of patched vulnerabilities of PACKAGE as a list of CVE
548identifiers. The result is inferred from the file names of patches."
549 (define (patch-vulnerabilities patch)
550 (map (cut match:substring <> 0)
551 (list-matches %vulnerability-regexp patch)))
552
553 (let ((patches (filter-map patch-file-name
554 (or (and=> (package-source package)
555 origin-patches)
556 '()))))
557 (append-map patch-vulnerabilities patches)))
558
ac10e0e1 559(define (%standard-patch-inputs)
5ae4169c
LC
560 (let* ((canonical (module-ref (resolve-interface '(gnu packages base))
561 'canonical-package))
562 (ref (lambda (module var)
563 (canonical
564 (module-ref (resolve-interface module) var)))))
ac10e0e1
LC
565 `(("tar" ,(ref '(gnu packages base) 'tar))
566 ("xz" ,(ref '(gnu packages compression) 'xz))
567 ("bzip2" ,(ref '(gnu packages compression) 'bzip2))
568 ("gzip" ,(ref '(gnu packages compression) 'gzip))
569 ("lzip" ,(ref '(gnu packages compression) 'lzip))
148585c2 570 ("unzip" ,(ref '(gnu packages compression) 'unzip))
9cca706c 571 ("patch" ,(ref '(gnu packages base) 'patch))
5ae4169c 572 ("locales" ,(ref '(gnu packages base) 'glibc-utf8-locales)))))
ac10e0e1 573
1d9bc459 574(define (default-guile)
e87f0591
LC
575 "Return the default Guile package used to run the build code of
576derivations."
bdb36958 577 (let ((distro (resolve-interface '(gnu packages commencement))))
1d9bc459 578 (module-ref distro 'guile-final)))
ac10e0e1 579
2b6fe605
LC
580(define (guile-for-grafts)
581 "Return the Guile package used to build grafting derivations."
582 ;; Guile 2.2 would not work due to <https://bugs.gnu.org/28211> when
e4925e00
LC
583 ;; grafting packages.
584 (let ((distro (resolve-interface '(gnu packages guile))))
585 (module-ref distro 'guile-2.0)))
586
ff40e9b7
LC
587(define* (default-guile-derivation #:optional (system (%current-system)))
588 "Return the derivation for SYSTEM of the default Guile package used to run
589the build code of derivation."
590 (package->derivation (default-guile) system
591 #:graft? #f))
592
cf87cc89 593(define* (patch-and-repack source patches
ac10e0e1 594 #:key
a158484d 595 inputs
f9cc8971 596 (snippet #f)
ac10e0e1 597 (flags '("-p1"))
f9cc8971 598 (modules '())
ac10e0e1
LC
599 (guile-for-build (%guile-for-build))
600 (system (%current-system)))
f9cc8971
LC
601 "Unpack SOURCE (a derivation or store path), apply all of PATCHES, and
602repack the tarball using the tools listed in INPUTS. When SNIPPET is true,
603it must be an s-expression that will run from within the directory where
1929fdba
LC
604SOURCE was unpacked, after all of PATCHES have been applied. MODULES
605specifies modules in scope when evaluating SNIPPET."
f9cc8971
LC
606 (define source-file-name
607 ;; SOURCE is usually a derivation, but it could be a store file.
608 (if (derivation? source)
609 (derivation->output-path source)
610 source))
611
a158484d
LC
612 (define lookup-input
613 ;; The default value of the 'patch-inputs' field, and thus INPUTS is #f,
614 ;; so deal with that.
615 (let ((inputs (or inputs (%standard-patch-inputs))))
616 (lambda (name)
617 (match (assoc-ref inputs name)
618 ((package) package)
619 (#f #f)))))
cf87cc89 620
cfcead2e 621 (define original-file-name (strip-store-file-name source-file-name))
ac10e0e1 622
3ca00bb5
LC
623 (define (numeric-extension? file-name)
624 ;; Return true if FILE-NAME ends with digits.
857ecb3d
LC
625 (and=> (file-extension file-name)
626 (cut string-every char-set:hex-digit <>)))
3ca00bb5 627
814e12dc
MB
628 (define (checkout? directory)
629 ;; Return true if DIRECTORY is a checkout (git, svn, etc).
630 (string-suffix? "-checkout" directory))
631
3ca00bb5
LC
632 (define (tarxz-name file-name)
633 ;; Return a '.tar.xz' file name based on FILE-NAME.
f41ff532
LC
634 (let ((base (if (numeric-extension? file-name)
635 original-file-name
636 (file-sans-extension file-name))))
3ca00bb5
LC
637 (string-append base
638 (if (equal? (file-extension base) "tar")
639 ".xz"
640 ".tar.xz"))))
641
cf87cc89
LC
642 (define instantiate-patch
643 (match-lambda
7ebc6cf8 644 ((? string? patch) ;deprecated
cf87cc89 645 (interned-file patch #:recursive? #t))
7ebc6cf8
LC
646 ((? struct? patch) ;origin, local-file, etc.
647 (lower-object patch system))))
cf87cc89
LC
648
649 (mlet %store-monad ((tar -> (lookup-input "tar"))
cfcead2e
MC
650 (gzip -> (lookup-input "gzip"))
651 (bzip2 -> (lookup-input "bzip2"))
652 (lzip -> (lookup-input "lzip"))
cf87cc89
LC
653 (xz -> (lookup-input "xz"))
654 (patch -> (lookup-input "patch"))
655 (locales -> (lookup-input "locales"))
cfcead2e
MC
656 (comp -> (and=> (compressor source-file-name)
657 lookup-input))
cf87cc89
LC
658 (patches (sequence %store-monad
659 (map instantiate-patch patches))))
660 (define build
1929fdba
LC
661 (with-imported-modules '((guix build utils))
662 #~(begin
663 (use-modules (ice-9 ftw)
cfcead2e
MC
664 (ice-9 match)
665 (ice-9 regex)
1929fdba 666 (srfi srfi-1)
cfcead2e 667 (srfi srfi-26)
1929fdba
LC
668 (guix build utils))
669
670 ;; The --sort option was added to GNU tar in version 1.28, released
671 ;; 2014-07-28. During bootstrap we must cope with older versions.
672 (define tar-supports-sort?
673 (zero? (system* (string-append #+tar "/bin/tar")
674 "cf" "/dev/null" "--files-from=/dev/null"
675 "--sort=name")))
676
677 (define (apply-patch patch)
678 (format (current-error-port) "applying '~a'...~%" patch)
679
680 ;; Use '--force' so that patches that do not apply perfectly are
8d65c71f
AK
681 ;; rejected. Use '--no-backup-if-mismatch' to prevent making
682 ;; "*.orig" file if a patch is applied with offset.
7ac1b408
MW
683 (invoke (string-append #+patch "/bin/patch")
684 "--force" "--no-backup-if-mismatch"
685 #+@flags "--input" patch))
1929fdba
LC
686
687 (define (first-file directory)
688 ;; Return the name of the first file in DIRECTORY.
689 (car (scandir directory
690 (lambda (name)
691 (not (member name '("." "..")))))))
692
f41ff532
LC
693 (define (repack directory output)
694 ;; Write to OUTPUT a compressed tarball containing DIRECTORY.
695 (unless tar-supports-sort?
696 (call-with-output-file ".file_list"
697 (lambda (port)
698 (for-each (lambda (name)
699 (format port "~a~%" name))
700 (find-files directory
701 #:directories? #t
702 #:fail-on-error? #t)))))
703
704 (apply invoke #+(file-append tar "/bin/tar")
705 "cvfa" output
706 ;; Avoid non-determinism in the archive. Set the mtime
707 ;; to 1 as is the case in the store (software like gzip
708 ;; behaves differently when it stumbles upon mtime = 0).
709 "--mtime=@1"
710 "--owner=root:0" "--group=root:0"
711 (if tar-supports-sort?
712 `("--sort=name" ,directory)
713 '("--no-recursion"
714 "--files-from=.file_list"))))
715
1929fdba
LC
716 ;; Encoding/decoding errors shouldn't be silent.
717 (fluid-set! %default-port-conversion-strategy 'error)
718
719 (when #+locales
720 ;; First of all, install a UTF-8 locale so that UTF-8 file names
721 ;; are correctly interpreted. During bootstrap, LOCALES is #f.
722 (setenv "LOCPATH"
723 (string-append #+locales "/lib/locale/"
724 #+(and locales
c6bc8e22
MB
725 (version-major+minor
726 (package-version locales)))))
1929fdba
LC
727 (setlocale LC_ALL "en_US.utf8"))
728
cfcead2e
MC
729 (setenv "PATH"
730 (string-append #+xz "/bin"
731 (if #+comp
732 (string-append ":" #+comp "/bin")
733 "")))
1929fdba 734
5a0997ef
MC
735 (setenv "XZ_DEFAULTS" (string-join (%xz-parallel-args)))
736
cfcead2e
MC
737 ;; SOURCE may be either a directory, a tarball or a simple file.
738 (let ((name (strip-store-file-name #+source))
739 (command (and=> #+comp (cut string-append <> "/bin/"
740 (compressor #+source)))))
741 (if (file-is-directory? #+source)
742 (copy-recursively #+source name)
743 (cond
744 ((tarball? #+source)
745 (invoke (string-append #+tar "/bin/tar") "xvf" #+source))
746 ((and=> (compressor #+source) (cut string= "unzip" <>))
747 ;; Note: Referring to the store unzip here (#+unzip)
748 ;; would introduce a cycle.
749 ("unzip" (invoke "unzip" #+source)))
750 (else
751 (copy-file #+source name)
752 (when command
753 (invoke command "--decompress" name))))))
754
755 (let* ((file (first-file "."))
756 (directory (if (file-is-directory? file)
757 file
758 ".")))
759 (format (current-error-port) "source is at '~a'~%" file)
760
761 (with-directory-excursion directory
762
763 (for-each apply-patch '#+patches)
764
765 #+(if snippet
766 #~(let ((module (make-fresh-user-module)))
767 (module-use-interfaces!
768 module
769 (map resolve-interface '#+modules))
770 ((@ (system base compile) compile)
771 '#+snippet
772 #:to 'value
773 #:opts %auto-compilation-options
774 #:env module))
775 #~#t))
7ac1b408 776
f41ff532
LC
777 ;; If SOURCE is a directory (such as a checkout), return a
778 ;; directory. Otherwise create a tarball.
cfcead2e
MC
779 (cond
780 ((file-is-directory? #+source)
781 (copy-recursively directory #$output
782 #:log (%make-void-port "w")))
783 ((not #+comp)
784 (copy-file file #$output))
785 (else
786 (repack directory #$output)))))))
787
788 (let ((name (if (or (checkout? original-file-name)
789 (not (compressor original-file-name)))
f41ff532
LC
790 original-file-name
791 (tarxz-name original-file-name))))
cf87cc89
LC
792 (gexp->derivation name build
793 #:graft? #f
794 #:system system
ea89b62a
LC
795 #:guile-for-build guile-for-build
796 #:properties `((type . origin)
797 (patches . ,(length patches)))))))
ac10e0e1 798
b066c250
CD
799(define (package-with-patches original patches)
800 "Return package ORIGINAL with PATCHES applied."
801 (package (inherit original)
802 (source (origin (inherit (package-source original))
803 (patches patches)))))
804
805(define (package-with-extra-patches original patches)
806 "Return package ORIGINAL with all PATCHES appended to its list of patches."
807 (package-with-patches original
808 (append (origin-patches (package-source original))
809 patches)))
810
46135ce4
LC
811(define (package-with-c-toolchain package toolchain)
812 "Return a variant of PACKAGE that uses TOOLCHAIN instead of the default GNU
813C/C++ toolchain. TOOLCHAIN must be a list of inputs (label/package tuples)
814providing equivalent functionality, such as the 'gcc-toolchain' package."
815 (let ((bs (package-build-system package)))
816 (package/inherit package
817 (build-system (build-system-with-c-toolchain bs toolchain)))))
818
113aef68 819(define (transitive-inputs inputs)
161094c8
LC
820 "Return the closure of INPUTS when considering the 'propagated-inputs'
821edges. Omit duplicate inputs, except for those already present in INPUTS
822itself.
823
824This is implemented as a breadth-first traversal such that INPUTS is
825preserved, and only duplicate propagated inputs are removed."
826 (define (seen? seen item outputs)
8102cf0b
LC
827 ;; FIXME: We're using pointer identity here, which is extremely sensitive
828 ;; to memoization in package-producing procedures; see
829 ;; <https://bugs.gnu.org/30155>.
161094c8
LC
830 (match (vhash-assq item seen)
831 ((_ . o) (equal? o outputs))
832 (_ #f)))
833
834 (let loop ((inputs inputs)
835 (result '())
836 (propagated '())
837 (first? #t)
838 (seen vlist-null))
a3d73f59
LC
839 (match inputs
840 (()
161094c8
LC
841 (if (null? propagated)
842 (reverse result)
843 (loop (reverse (concatenate propagated)) result '() #f seen)))
844 (((and input (label (? package? package) outputs ...)) rest ...)
845 (if (and (not first?) (seen? seen package outputs))
846 (loop rest result propagated first? seen)
847 (loop rest
848 (cons input result)
849 (cons (package-propagated-inputs package) propagated)
850 first?
851 (vhash-consq package outputs seen))))
a3d73f59 852 ((input rest ...)
161094c8 853 (loop rest (cons input result) propagated first? seen)))))
a3d73f59 854
f77bcbc3
EB
855(define (package-direct-sources package)
856 "Return all source origins associated with PACKAGE; including origins in
857PACKAGE's inputs."
858 `(,@(or (and=> (package-source package) list) '())
859 ,@(filter-map (match-lambda
860 ((_ (? origin? orig) _ ...)
861 orig)
862 (_ #f))
863 (package-direct-inputs package))))
864
865(define (package-transitive-sources package)
866 "Return PACKAGE's direct sources, and their direct sources, recursively."
867 (delete-duplicates
868 (concatenate (filter-map (match-lambda
869 ((_ (? origin? orig) _ ...)
870 (list orig))
871 ((_ (? package? p) _ ...)
872 (package-direct-sources p))
873 (_ #f))
874 (bag-transitive-inputs
875 (package->bag package))))))
876
7d193ec3
EB
877(define (package-direct-inputs package)
878 "Return all the direct inputs of PACKAGE---i.e, its direct inputs along
879with their propagated inputs."
880 (append (package-native-inputs package)
881 (package-inputs package)
882 (package-propagated-inputs package)))
883
113aef68
LC
884(define (package-transitive-inputs package)
885 "Return the transitive inputs of PACKAGE---i.e., its direct inputs along
886with their propagated inputs, recursively."
7d193ec3 887 (transitive-inputs (package-direct-inputs package)))
113aef68 888
9c1edabd
LC
889(define (package-transitive-target-inputs package)
890 "Return the transitive target inputs of PACKAGE---i.e., its direct inputs
891along with their propagated inputs, recursively. This only includes inputs
892for the target system, and not native inputs."
893 (transitive-inputs (append (package-inputs package)
894 (package-propagated-inputs package))))
895
896(define (package-transitive-native-inputs package)
897 "Return the transitive native inputs of PACKAGE---i.e., its direct inputs
898along with their propagated inputs, recursively. This only includes inputs
899for the host system (\"native inputs\"), and not target inputs."
900 (transitive-inputs (package-native-inputs package)))
901
113aef68
LC
902(define (package-transitive-propagated-inputs package)
903 "Return the propagated inputs of PACKAGE, and their propagated inputs,
904recursively."
905 (transitive-inputs (package-propagated-inputs package)))
906
aa8e0515
LC
907(define (package-transitive-native-search-paths package)
908 "Return the list of search paths for PACKAGE and its propagated inputs,
909recursively."
910 (append (package-native-search-paths package)
911 (append-map (match-lambda
912 ((label (? package? p) _ ...)
913 (package-native-search-paths p))
914 (_
915 '()))
916 (package-transitive-propagated-inputs package))))
917
a6d0b306
EB
918(define (transitive-input-references alist inputs)
919 "Return a list of (assoc-ref ALIST <label>) for each (<label> <package> . _)
920in INPUTS and their transitive propagated inputs."
921 (define label
922 (match-lambda
923 ((label . _)
924 label)))
925
926 (map (lambda (input)
927 `(assoc-ref ,alist ,(label input)))
928 (transitive-inputs inputs)))
929
c9134e82 930(define package-transitive-supported-systems
bc60349b
LC
931 (let ()
932 (define supported-systems
933 (mlambda (package system)
934 (parameterize ((%current-system system))
935 (fold (lambda (input systems)
936 (match input
937 ((label (? package? package) . _)
938 (lset-intersection string=? systems
939 (supported-systems package system)))
940 (_
941 systems)))
942 (package-supported-systems package)
943 (bag-direct-inputs (package->bag package))))))
944
945 (lambda* (package #:optional (system (%current-system)))
946 "Return the intersection of the systems supported by PACKAGE and those
7c3c0374 947supported by its dependencies."
bc60349b 948 (supported-systems package system))))
7c3c0374 949
bbceb0ef
LC
950(define* (supported-package? package #:optional (system (%current-system)))
951 "Return true if PACKAGE is supported on SYSTEM--i.e., if PACKAGE and all its
952dependencies are known to build on SYSTEM."
bc60349b 953 (member system (package-transitive-supported-systems package system)))
bbceb0ef 954
cceab875
LC
955(define (bag-direct-inputs bag)
956 "Same as 'package-direct-inputs', but applied to a bag."
957 (append (bag-build-inputs bag)
958 (bag-host-inputs bag)
959 (bag-target-inputs bag)))
960
0d5a559f
LC
961(define (bag-transitive-inputs bag)
962 "Same as 'package-transitive-inputs', but applied to a bag."
efb10f17
LC
963 (parameterize ((%current-target-system #f)
964 (%current-system (bag-system bag)))
f52fbf70 965 (transitive-inputs (bag-direct-inputs bag))))
0d5a559f
LC
966
967(define (bag-transitive-build-inputs bag)
968 "Same as 'package-transitive-native-inputs', but applied to a bag."
efb10f17
LC
969 (parameterize ((%current-target-system #f)
970 (%current-system (bag-system bag)))
f52fbf70 971 (transitive-inputs (bag-build-inputs bag))))
0d5a559f
LC
972
973(define (bag-transitive-host-inputs bag)
974 "Same as 'package-transitive-target-inputs', but applied to a bag."
efb10f17
LC
975 (parameterize ((%current-target-system (bag-target bag))
976 (%current-system (bag-system bag)))
6cef554b 977 (transitive-inputs (bag-host-inputs bag))))
0d5a559f
LC
978
979(define (bag-transitive-target-inputs bag)
980 "Return the \"target inputs\" of BAG, recursively."
efb10f17
LC
981 (parameterize ((%current-target-system (bag-target bag))
982 (%current-system (bag-system bag)))
f52fbf70 983 (transitive-inputs (bag-target-inputs bag))))
0d5a559f 984
3e223a22
LC
985(define* (package-closure packages #:key (system (%current-system)))
986 "Return the closure of PACKAGES on SYSTEM--i.e., PACKAGES and the list of
987packages they depend on, recursively."
988 (let loop ((packages packages)
989 (visited vlist-null)
990 (closure (list->setq packages)))
991 (match packages
992 (()
993 (set->list closure))
994 ((package . rest)
995 (if (vhash-assq package visited)
996 (loop rest visited closure)
997 (let* ((bag (package->bag package system))
998 (dependencies (filter-map (match-lambda
999 ((label (? package? package) . _)
1000 package)
1001 (_ #f))
1002 (bag-direct-inputs bag))))
1003 (loop (append dependencies rest)
1004 (vhash-consq package #t visited)
1005 (fold set-insert closure dependencies))))))))
1006
ff39361c
LC
1007(define (build-system-with-package-mapping bs rewrite)
1008 "Return a variant of BS, a build system, that rewrites a bag's inputs by
1009passing them through REWRITE, a procedure that takes an input tuplet and
1010returns a \"rewritten\" input tuplet."
1011 (define lower
1012 (build-system-lower bs))
1013
1014 (define (lower* . args)
1015 (let ((lowered (apply lower args)))
1016 (bag
1017 (inherit lowered)
1018 (build-inputs (map rewrite (bag-build-inputs lowered)))
1019 (host-inputs (map rewrite (bag-host-inputs lowered)))
1020 (target-inputs (map rewrite (bag-target-inputs lowered))))))
1021
1022 (build-system
1023 (inherit bs)
1024 (lower lower*)))
1025
1026(define* (package-mapping proc #:optional (cut? (const #f))
1027 #:key deep?)
f37f2b83
LC
1028 "Return a procedure that, given a package, applies PROC to all the packages
1029depended on and returns the resulting package. The procedure stops recursion
ff39361c
LC
1030when CUT? returns true for a given package. When DEEP? is true, PROC is
1031applied to implicit inputs as well."
2a75b0b6
LC
1032 (define (rewrite input)
1033 (match input
1034 ((label (? package? package) outputs ...)
8db4ebb0 1035 (cons* label (replace package) outputs))
2a75b0b6
LC
1036 (_
1037 input)))
1038
ff39361c
LC
1039 (define mapping-property
1040 ;; Property indicating whether the package has already been processed.
1041 (gensym " package-mapping-done"))
1042
c9134e82
LC
1043 (define replace
1044 (mlambdaq (p)
ff39361c 1045 ;; If P is the result of a previous call, return it.
8db4ebb0
LC
1046 (cond ((assq-ref (package-properties p) mapping-property)
1047 p)
1048
1049 ((cut? p)
1050 ;; Since P's propagated inputs are really inputs of its dependents,
1051 ;; rewrite them as well, unless we're doing a "shallow" rewrite.
1052 (let ((p (proc p)))
1053 (if (or (not deep?)
1054 (null? (package-propagated-inputs p)))
1055 p
1056 (package
1057 (inherit p)
1058 (location (package-location p))
1059 (replacement (package-replacement p))
1060 (propagated-inputs (map rewrite (package-propagated-inputs p)))
1061 (properties `((,mapping-property . #t)
1062 ,@(package-properties p)))))))
1063
1064 (else
1065 ;; Return a variant of P with PROC applied to P and its explicit
1066 ;; dependencies, recursively. Memoize the transformations. Failing
1067 ;; to do that, we would build a huge object graph with lots of
1068 ;; duplicates, which in turns prevents us from benefiting from
1069 ;; memoization in 'package-derivation'.
1070 (let ((p (proc p)))
1071 (package
1072 (inherit p)
1073 (location (package-location p))
1074 (build-system (if deep?
1075 (build-system-with-package-mapping
1076 (package-build-system p) rewrite)
1077 (package-build-system p)))
1078 (inputs (map rewrite (package-inputs p)))
1079 (native-inputs (map rewrite (package-native-inputs p)))
1080 (propagated-inputs (map rewrite (package-propagated-inputs p)))
1081 (replacement (and=> (package-replacement p) replace))
1082 (properties `((,mapping-property . #t)
1083 ,@(package-properties p)))))))))
2a75b0b6
LC
1084
1085 replace)
1086
f37f2b83 1087(define* (package-input-rewriting replacements
8819551c
LC
1088 #:optional (rewrite-name identity)
1089 #:key (deep? #t))
f37f2b83 1090 "Return a procedure that, when passed a package, replaces its direct and
8819551c
LC
1091indirect dependencies, including implicit inputs when DEEP? is true, according
1092to REPLACEMENTS. REPLACEMENTS is a list of package pairs; the first element
1093of each pair is the package to replace, and the second one is the replacement.
f37f2b83
LC
1094
1095Optionally, REWRITE-NAME is a one-argument procedure that takes the name of a
1096package and returns its new name after rewrite."
8819551c
LC
1097 (define replacement-property
1098 ;; Property to tag right-hand sides in REPLACEMENTS.
1099 (gensym " package-replacement"))
f37f2b83 1100
8819551c
LC
1101 (define (rewrite p)
1102 (if (assq-ref (package-properties p) replacement-property)
1103 p
1104 (match (assq-ref replacements p)
1105 (#f (package/inherit p
1106 (name (rewrite-name (package-name p)))))
1107 (new (if deep?
1108 (package/inherit new
1109 (properties `((,replacement-property . #t)
1110 ,@(package-properties new))))
1111 new)))))
1112
1113 (define (cut? p)
1114 (or (assq-ref (package-properties p) replacement-property)
1115 (assq-ref replacements p)))
1116
1117 (package-mapping rewrite cut?
1118 #:deep? deep?))
f37f2b83 1119
2bf6f962 1120(define* (package-input-rewriting/spec replacements #:key (deep? #t))
f258d886 1121 "Return a procedure that, given a package, applies the given REPLACEMENTS to
2bf6f962
LC
1122all the package graph, including implicit inputs unless DEEP? is false.
1123REPLACEMENTS is a list of spec/procedures pair; each spec is a package
1124specification such as \"gcc\" or \"guile@2\", and each procedure takes a
1125matching package and returns a replacement for that package."
f258d886
LC
1126 (define table
1127 (fold (lambda (replacement table)
1128 (match replacement
1129 ((spec . proc)
1130 (let-values (((name version)
1131 (package-name->name+version spec)))
1132 (vhash-cons name (list version proc) table)))))
1133 vlist-null
1134 replacements))
1135
1136 (define (find-replacement package)
1137 (vhash-fold* (lambda (item proc)
1138 (or proc
1139 (match item
1140 ((#f proc)
1141 proc)
1142 ((version proc)
1143 (and (version-prefix? version
1144 (package-version package))
1145 proc)))))
1146 #f
1147 (package-name package)
1148 table))
1149
2bf6f962
LC
1150 (define replacement-property
1151 (gensym " package-replacement"))
f258d886 1152
2bf6f962
LC
1153 (define (rewrite p)
1154 (if (assq-ref (package-properties p) replacement-property)
1155 p
1156 (match (find-replacement p)
1157 (#f p)
1158 (proc
1159 (let ((new (proc p)))
1160 ;; Mark NEW as already processed.
1161 (package/inherit new
1162 (properties `((,replacement-property . #t)
1163 ,@(package-properties new)))))))))
1164
1165 (define (cut? p)
1166 (or (assq-ref (package-properties p) replacement-property)
1167 (find-replacement p)))
1168
1169 (package-mapping rewrite cut?
1170 #:deep? deep?))
bedba064 1171
a2ebaddd
LC
1172\f
1173;;;
1174;;; Package derivations.
1175;;;
1176
198d84b7
LC
1177(define (cache! cache package system thunk)
1178 "Memoize in CACHE the return values of THUNK as the derivation of PACKAGE on
e509d152 1179SYSTEM."
bce7526f
LC
1180 ;; FIXME: This memoization should be associated with the open store, because
1181 ;; otherwise it breaks when switching to a different store.
0b1be8fd 1182 (let ((result (thunk)))
e509d152
LC
1183 ;; Use `hashq-set!' instead of `hash-set!' because `hash' returns the
1184 ;; same value for all structs (as of Guile 2.0.6), and because pointer
1185 ;; equality is sufficient in practice.
198d84b7 1186 (hashq-set! cache package
0b1be8fd 1187 `((,system . ,result)
198d84b7 1188 ,@(or (hashq-ref cache package) '())))
0b1be8fd 1189 result))
e509d152 1190
198d84b7
LC
1191(define-syntax cached
1192 (syntax-rules (=>)
1193 "Memoize the result of BODY for the arguments PACKAGE and SYSTEM.
e509d152 1194Return the cached result when available."
198d84b7
LC
1195 ((_ (=> cache) package system body ...)
1196 (let ((thunk (lambda () body ...))
1197 (key system))
1198 (match (hashq-ref cache package)
1199 ((alist (... ...))
1200 (match (assoc-ref alist key)
0b1be8fd
LC
1201 (#f (cache! cache package key thunk))
1202 (value value)))
e509d152 1203 (#f
198d84b7
LC
1204 (cache! cache package key thunk)))))
1205 ((_ package system body ...)
1206 (cached (=> %derivation-cache) package system body ...))))
a2ebaddd 1207
7d873f19
LC
1208(define* (expand-input package input #:key native?)
1209 "Expand INPUT, an input tuple, to a name/<gexp-input> tuple. PACKAGE is
1210only used to provide contextual information in exceptions."
1211 (define (valid? x)
1212 (or (package? x) (origin? x) (derivation? x)))
a63062b5
LC
1213
1214 (match input
7d873f19
LC
1215 (((? string? name) (? valid? thing))
1216 (list name (gexp-input thing #:native? native?)))
1217 (((? string? name) (? valid? thing) (? string? output))
1218 (list name (gexp-input thing output #:native? native?)))
a63062b5
LC
1219 (((? string? name)
1220 (and (? string?) (? file-exists? file)))
1221 ;; Add FILE to the store. When FILE is in the sub-directory of a
1222 ;; store path, it needs to be added anyway, so it can be used as a
1223 ;; source.
7d873f19
LC
1224 (list name (gexp-input (local-file file #:recursive? #t)
1225 #:native? native?)))
da675305 1226 (((? string? name) (? struct? source))
76c48619
LC
1227 ;; 'package-source-derivation' calls 'lower-object', which can throw
1228 ;; '&gexp-input-error'. However '&gexp-input-error' lacks source
7d873f19
LC
1229 ;; location info, so we used to catch and rethrow here (FIXME!).
1230 (list name (gexp-input source)))
a63062b5
LC
1231 (x
1232 (raise (condition (&package-input-error
1233 (package package)
1234 (input x)))))))
592ef6c8 1235
9775412e
LC
1236(define %bag-cache
1237 ;; 'eq?' cache mapping packages to system+target+graft?-dependent bags.
1238 ;; It significantly speeds things up when doing repeated calls to
1239 ;; 'package->bag' as is the case when building a profile.
1240 (make-weak-key-hash-table 200))
1241
0d5a559f
LC
1242(define* (package->bag package #:optional
1243 (system (%current-system))
05962f29
LC
1244 (target (%current-target-system))
1245 #:key (graft? (%graft?)))
0d5a559f
LC
1246 "Compile PACKAGE into a bag for SYSTEM, possibly cross-compiled to TARGET,
1247and return it."
9f785529
LC
1248 (let ((package (or (and graft? (package-replacement package))
1249 package)))
1250 (cached (=> %bag-cache)
1251 package (list system target)
1252 ;; Bind %CURRENT-SYSTEM and %CURRENT-TARGET-SYSTEM so that thunked
1253 ;; field values can refer to it.
1254 (parameterize ((%current-system system)
1255 (%current-target-system target))
1256 (match package
1257 ((and self
1258 ($ <package> name version source build-system
1259 args inputs propagated-inputs native-inputs
1260 outputs))
1261 ;; Even though we prefer to use "@" to separate the package
1262 ;; name from the package version in various user-facing parts
1263 ;; of Guix, checkStoreName (in nix/libstore/store-api.cc)
1264 ;; prohibits the use of "@", so use "-" instead.
1265 (or (make-bag build-system (string-append name "-" version)
1266 #:system system
1267 #:target target
1268 #:source source
1269 #:inputs (append (inputs self)
1270 (propagated-inputs self))
1271 #:outputs outputs
1272 #:native-inputs (native-inputs self)
1273 #:arguments (args self))
1274 (raise (if target
1275 (condition
1276 (&package-cross-build-system-error
1277 (package package)))
1278 (condition
1279 (&package-error
1280 (package package))))))))))))
0d5a559f 1281
ced71ac7
LC
1282(define %graft-cache
1283 ;; 'eq?' cache mapping package objects to a graft corresponding to their
1284 ;; replacement package.
1285 (make-weak-key-hash-table 200))
1286
05962f29 1287(define (input-graft store system)
03a70e4c
LC
1288 "Return a procedure that, given a package with a replacement and an output name,
1289returns a graft, and #f otherwise."
1290 (match-lambda*
1291 (((? package? package) output)
c22a1324
LC
1292 (let ((replacement (package-replacement package)))
1293 (and replacement
03a70e4c 1294 (cached (=> %graft-cache) package (cons output system)
ced71ac7
LC
1295 (let ((orig (package-derivation store package system
1296 #:graft? #f))
d0025d01
LC
1297 (new (package-derivation store replacement system
1298 #:graft? #t)))
ced71ac7
LC
1299 (graft
1300 (origin orig)
03a70e4c
LC
1301 (origin-output output)
1302 (replacement new)
1303 (replacement-output output)))))))))
05962f29
LC
1304
1305(define (input-cross-graft store target system)
1306 "Same as 'input-graft', but for cross-compilation inputs."
03a70e4c
LC
1307 (match-lambda*
1308 (((? package? package) output)
1309 (let ((replacement (package-replacement package)))
1310 (and replacement
1311 (let ((orig (package-cross-derivation store package target system
1312 #:graft? #f))
1313 (new (package-cross-derivation store replacement
1314 target system
1315 #:graft? #t)))
1316 (graft
1317 (origin orig)
1318 (origin-output output)
1319 (replacement new)
1320 (replacement-output output))))))))
05962f29 1321
c22a1324
LC
1322(define* (fold-bag-dependencies proc seed bag
1323 #:key (native? #t))
1324 "Fold PROC over the packages BAG depends on. Each package is visited only
1325once, in depth-first order. If NATIVE? is true, restrict to native
1326dependencies; otherwise, restrict to target dependencies."
ff0e0041
LC
1327 (define bag-direct-inputs*
1328 (if native?
1329 (lambda (bag)
1330 (append (bag-build-inputs bag)
1331 (bag-target-inputs bag)
1332 (if (bag-target bag)
1333 '()
1334 (bag-host-inputs bag))))
609d126e 1335 bag-host-inputs))
ff0e0041 1336
03a70e4c 1337 (let loop ((inputs (bag-direct-inputs* bag))
c22a1324 1338 (result seed)
03a70e4c
LC
1339 (visited vlist-null))
1340 (match inputs
c22a1324
LC
1341 (()
1342 result)
03a70e4c
LC
1343 (((label (? package? head) . rest) . tail)
1344 (let ((output (match rest (() "out") ((output) output)))
1345 (outputs (vhash-foldq* cons '() head visited)))
1346 (if (member output outputs)
1347 (loop tail result visited)
1348 (let ((inputs (bag-direct-inputs* (package->bag head))))
1349 (loop (append inputs tail)
1350 (proc head output result)
1351 (vhash-consq head output visited))))))
c22a1324
LC
1352 ((head . tail)
1353 (loop tail result visited)))))
1354
05962f29 1355(define* (bag-grafts store bag)
c22a1324
LC
1356 "Return the list of grafts potentially applicable to BAG. Potentially
1357applicable grafts are collected by looking at direct or indirect dependencies
1358of BAG that have a 'replacement'. Whether a graft is actually applicable
1359depends on whether the outputs of BAG depend on the items the grafts refer
1360to (see 'graft-derivation'.)"
1361 (define system (bag-system bag))
1362 (define target (bag-target bag))
1363
1364 (define native-grafts
1365 (let ((->graft (input-graft store system)))
b49caaa2
LC
1366 (parameterize ((%current-system system)
1367 (%current-target-system #f))
03a70e4c
LC
1368 (fold-bag-dependencies (lambda (package output grafts)
1369 (match (->graft package output)
b49caaa2
LC
1370 (#f grafts)
1371 (graft (cons graft grafts))))
1372 '()
1373 bag))))
c22a1324
LC
1374
1375 (define target-grafts
1376 (if target
1377 (let ((->graft (input-cross-graft store target system)))
b49caaa2
LC
1378 (parameterize ((%current-system system)
1379 (%current-target-system target))
03a70e4c
LC
1380 (fold-bag-dependencies (lambda (package output grafts)
1381 (match (->graft package output)
b49caaa2
LC
1382 (#f grafts)
1383 (graft (cons graft grafts))))
1384 '()
1385 bag
1386 #:native? #f)))
c22a1324
LC
1387 '()))
1388
fcadd9ff
LC
1389 ;; We can end up with several identical grafts if we stumble upon packages
1390 ;; that are not 'eq?' but map to the same derivation (this can happen when
1391 ;; using things like 'package-with-explicit-inputs'.) Hence the
1392 ;; 'delete-duplicates' call.
1393 (delete-duplicates
1394 (append native-grafts target-grafts)))
05962f29
LC
1395
1396(define* (package-grafts store package
1397 #:optional (system (%current-system))
1398 #:key target)
1399 "Return the list of grafts applicable to PACKAGE as built for SYSTEM and
1400TARGET."
1401 (let* ((package (or (package-replacement package) package))
1402 (bag (package->bag package system target)))
1403 (bag-grafts store bag)))
1404
6b466336
LC
1405(define-inlinable (derivation=? drv1 drv2)
1406 "Return true if DRV1 and DRV2 are equal."
1407 (or (eq? drv1 drv2)
1408 (string=? (derivation-file-name drv1)
1409 (derivation-file-name drv2))))
1410
1411(define (input=? input1 input2)
1412 "Return true if INPUT1 and INPUT2 are equivalent."
1413 (match input1
7d873f19 1414 ((label1 obj1 . outputs1)
6b466336 1415 (match input2
7d873f19 1416 ((label2 obj2 . outputs2)
6b466336
LC
1417 (and (string=? label1 label2)
1418 (equal? outputs1 outputs2)
7d873f19
LC
1419 (or (and (derivation? obj1) (derivation? obj2)
1420 (derivation=? obj1 obj2))
1421 (equal? obj1 obj2))))))))
6b466336 1422
d3d337d2
LC
1423(define* (bag->derivation store bag
1424 #:optional context)
1425 "Return the derivation to build BAG for SYSTEM. Optionally, CONTEXT can be
1426a package object describing the context in which the call occurs, for improved
1427error reporting."
1428 (if (bag-target bag)
1429 (bag->cross-derivation store bag)
1430 (let* ((system (bag-system bag))
1431 (inputs (bag-transitive-inputs bag))
7d873f19 1432 (input-drvs (map (cut expand-input context <> #:native? #t)
d3d337d2
LC
1433 inputs))
1434 (paths (delete-duplicates
1435 (append-map (match-lambda
1436 ((_ (? package? p) _ ...)
1437 (package-native-search-paths
1438 p))
1439 (_ '()))
1440 inputs))))
6b466336
LC
1441 ;; It's possible that INPUTS contains packages that are not 'eq?' but
1442 ;; that lead to the same derivation. Delete those duplicates to avoid
1443 ;; issues down the road, such as duplicate entries in '%build-inputs'.
7d873f19
LC
1444 ;; TODO: Change to monadic style.
1445 (apply (store-lower (bag-build bag))
6b466336
LC
1446 store (bag-name bag)
1447 (delete-duplicates input-drvs input=?)
d3d337d2
LC
1448 #:search-paths paths
1449 #:outputs (bag-outputs bag) #:system system
1450 (bag-arguments bag)))))
1451
1452(define* (bag->cross-derivation store bag
1453 #:optional context)
1454 "Return the derivation to build BAG, which is actually a cross build.
1455Optionally, CONTEXT can be a package object denoting the context of the call.
1456This is an internal procedure."
1457 (let* ((system (bag-system bag))
1458 (target (bag-target bag))
1459 (host (bag-transitive-host-inputs bag))
7d873f19 1460 (host-drvs (map (cut expand-input context <> #:native? #f)
d3d337d2
LC
1461 host))
1462 (target* (bag-transitive-target-inputs bag))
7d873f19 1463 (target-drvs (map (cut expand-input context <> #:native? #t)
d3d337d2
LC
1464 target*))
1465 (build (bag-transitive-build-inputs bag))
7d873f19 1466 (build-drvs (map (cut expand-input context <> #:native? #t)
d3d337d2
LC
1467 build))
1468 (all (append build target* host))
1469 (paths (delete-duplicates
1470 (append-map (match-lambda
1471 ((_ (? package? p) _ ...)
1472 (package-search-paths p))
1473 (_ '()))
1474 all)))
1475 (npaths (delete-duplicates
1476 (append-map (match-lambda
1477 ((_ (? package? p) _ ...)
1478 (package-native-search-paths
1479 p))
1480 (_ '()))
1481 all))))
1482
7d873f19
LC
1483 ;; TODO: Change to monadic style.
1484 (apply (store-lower (bag-build bag))
d3d337d2 1485 store (bag-name bag)
7d873f19
LC
1486 #:build-inputs (delete-duplicates build-drvs input=?)
1487 #:host-inputs (delete-duplicates host-drvs input=?)
1488 #:target-inputs (delete-duplicates target-drvs input=?)
d3d337d2
LC
1489 #:search-paths paths
1490 #:native-search-paths npaths
1491 #:outputs (bag-outputs bag)
1492 #:system system #:target target
1493 (bag-arguments bag))))
1494
a63062b5 1495(define* (package-derivation store package
05962f29
LC
1496 #:optional (system (%current-system))
1497 #:key (graft? (%graft?)))
59688fc4
LC
1498 "Return the <derivation> object of PACKAGE for SYSTEM."
1499
e509d152
LC
1500 ;; Compute the derivation and cache the result. Caching is important
1501 ;; because some derivations, such as the implicit inputs of the GNU build
1502 ;; system, will be queried many, many times in a row.
05962f29
LC
1503 (cached package (cons system graft?)
1504 (let* ((bag (package->bag package system #f #:graft? graft?))
1505 (drv (bag->derivation store bag package)))
1506 (if graft?
1507 (match (bag-grafts store bag)
1508 (()
1509 drv)
1510 (grafts
2b6fe605 1511 (let ((guile (package-derivation store (guile-for-grafts)
05962f29 1512 system #:graft? #f)))
c22a1324
LC
1513 ;; TODO: As an optimization, we can simply graft the tip
1514 ;; of the derivation graph since 'graft-derivation'
1515 ;; recurses anyway.
b0fef4d6 1516 (graft-derivation store drv grafts
05962f29
LC
1517 #:system system
1518 #:guile guile))))
1519 drv))))
e3ce5d70 1520
9c1edabd 1521(define* (package-cross-derivation store package target
05962f29
LC
1522 #:optional (system (%current-system))
1523 #:key (graft? (%graft?)))
9c1edabd
LC
1524 "Cross-build PACKAGE for TARGET (a GNU triplet) from host SYSTEM (a Guix
1525system identifying string)."
05962f29
LC
1526 (cached package (list system target graft?)
1527 (let* ((bag (package->bag package system target #:graft? graft?))
1528 (drv (bag->derivation store bag package)))
1529 (if graft?
1530 (match (bag-grafts store bag)
1531 (()
1532 drv)
1533 (grafts
b0fef4d6 1534 (graft-derivation store drv grafts
05962f29
LC
1535 #:system system
1536 #:guile
2b6fe605 1537 (package-derivation store (guile-for-grafts)
05962f29
LC
1538 system #:graft? #f))))
1539 drv))))
d510ab46 1540
de8bcdae
LC
1541(define* (package-output store package
1542 #:optional (output "out") (system (%current-system)))
d510ab46
LC
1543 "Return the output path of PACKAGE's OUTPUT for SYSTEM---where OUTPUT is the
1544symbolic output name, such as \"out\". Note that this procedure calls
1545`package-derivation', which is costly."
59688fc4
LC
1546 (let ((drv (package-derivation store package system)))
1547 (derivation->output-path drv output)))
e87f0591
LC
1548
1549\f
1550;;;
1551;;; Monadic interface.
1552;;;
1553
1554(define (set-guile-for-build guile)
1555 "This monadic procedure changes the Guile currently used to run the build
1556code of derivations to GUILE, a package object."
1557 (lambda (store)
1558 (let ((guile (package-derivation store guile)))
4e190c28 1559 (values (%guile-for-build guile) store))))
e87f0591
LC
1560
1561(define* (package-file package
1562 #:optional file
1563 #:key
1564 system (output "out") target)
1565 "Return as a monadic value the absolute file name of FILE within the
1566OUTPUT directory of PACKAGE. When FILE is omitted, return the name of the
1567OUTPUT directory of PACKAGE. When TARGET is true, use it as a
c8d8f616
LC
1568cross-compilation target triplet.
1569
1570Note that this procedure does _not_ build PACKAGE. Thus, the result might or
1571might not designate an existing file. We recommend not using this procedure
1572unless you know what you are doing."
e87f0591
LC
1573 (lambda (store)
1574 (define compute-derivation
1575 (if target
1576 (cut package-cross-derivation <> <> target <>)
1577 package-derivation))
1578
1579 (let* ((system (or system (%current-system)))
1580 (drv (compute-derivation store package system))
1581 (out (derivation->output-path drv output)))
4e190c28
LC
1582 (values (if file
1583 (string-append out "/" file)
1584 out)
1585 store))))
e87f0591
LC
1586
1587(define package->derivation
1588 (store-lift package-derivation))
1589
1590(define package->cross-derivation
1591 (store-lift package-cross-derivation))
1592
1cdecf24 1593(define-gexp-compiler (package-compiler (package <package>) system target)
ff40e9b7
LC
1594 ;; Compile PACKAGE to a derivation for SYSTEM, optionally cross-compiled for
1595 ;; TARGET. This is used when referring to a package from within a gexp.
1596 (if target
1597 (package->cross-derivation package target system)
1598 (package->derivation package system)))
1599
78951064 1600(define* (origin->derivation origin
f220a838 1601 #:optional (system (%current-system)))
78951064
LC
1602 "Return the derivation corresponding to ORIGIN."
1603 (match origin
ce0be567 1604 (($ <origin> uri method hash name (= force ()) #f)
f220a838 1605 ;; No patches, no snippet: this is a fixed-output derivation.
ce0be567
LC
1606 (method uri
1607 (content-hash-algorithm hash)
1608 (content-hash-value hash)
1609 name #:system system))
1610 (($ <origin> uri method hash name (= force (patches ...)) snippet
1929fdba 1611 (flags ...) inputs (modules ...) guile-for-build)
f220a838 1612 ;; Patches and/or a snippet.
ce0be567
LC
1613 (mlet %store-monad ((source (method uri
1614 (content-hash-algorithm hash)
1615 (content-hash-value hash)
1616 name #:system system))
f220a838
LC
1617 (guile (package->derivation (or guile-for-build
1618 (default-guile))
1619 system
1620 #:graft? #f)))
cf87cc89
LC
1621 (patch-and-repack source patches
1622 #:inputs inputs
1623 #:snippet snippet
1624 #:flags flags
1625 #:system system
1626 #:modules modules
78951064 1627 #:guile-for-build guile)))))
f220a838 1628
1cdecf24 1629(define-gexp-compiler (origin-compiler (origin <origin>) system target)
ff40e9b7
LC
1630 ;; Compile ORIGIN to a derivation for SYSTEM. This is used when referring
1631 ;; to an origin from within a gexp.
1632 (origin->derivation origin system))
1633
78951064 1634(define package-source-derivation ;somewhat deprecated
da675305 1635 (let ((lower (store-lower lower-object)))
78951064
LC
1636 (lambda* (store source #:optional (system (%current-system)))
1637 "Return the derivation or file corresponding to SOURCE, which can be an
da675305
LC
1638a file name or any object handled by 'lower-object', such as an <origin>.
1639When SOURCE is a file name, return either the interned file name (if SOURCE is
1640outside of the store) or SOURCE itself (if SOURCE is already a store item.)"
78951064
LC
1641 (match source
1642 ((and (? string?) (? direct-store-path?) file)
1643 file)
1644 ((? string? file)
1645 (add-to-store store (basename file) #t "sha256" file))
1646 (_
1647 (lower store source system))))))