tests: Hide quoted (define-module ...) form from Geiser.
[jackhill/guix/guix.git] / guix / gexp.scm
CommitLineData
21b679f6 1;;; GNU Guix --- Functional package management for GNU
52207b39 2;;; Copyright © 2014, 2015, 2016, 2017, 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org>
bdcf0e6f 3;;; Copyright © 2018 Clément Lassieur <clement@lassieur.org>
e8e1f295 4;;; Copyright © 2018 Jan Nieuwenhuizen <janneke@gnu.org>
a6bf7a97 5;;; Copyright © 2019, 2020 Mathieu Othacehe <m.othacehe@gmail.com>
21b679f6
LC
6;;;
7;;; This file is part of GNU Guix.
8;;;
9;;; GNU Guix is free software; you can redistribute it and/or modify it
10;;; under the terms of the GNU General Public License as published by
11;;; the Free Software Foundation; either version 3 of the License, or (at
12;;; your option) any later version.
13;;;
14;;; GNU Guix is distributed in the hope that it will be useful, but
15;;; WITHOUT ANY WARRANTY; without even the implied warranty of
16;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17;;; GNU General Public License for more details.
18;;;
19;;; You should have received a copy of the GNU General Public License
20;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
21
22(define-module (guix gexp)
e87f0591 23 #:use-module (guix store)
21b679f6 24 #:use-module (guix monads)
e87f0591 25 #:use-module (guix derivations)
7adf9b84 26 #:use-module (guix grafts)
aa72d9af 27 #:use-module (guix utils)
e8e1f295 28 #:use-module (rnrs bytevectors)
21b679f6
LC
29 #:use-module (srfi srfi-1)
30 #:use-module (srfi srfi-9)
7560b00b 31 #:use-module (srfi srfi-9 gnu)
21b679f6 32 #:use-module (srfi srfi-26)
3e43166f
LC
33 #:use-module (srfi srfi-34)
34 #:use-module (srfi srfi-35)
21b679f6
LC
35 #:use-module (ice-9 match)
36 #:export (gexp
37 gexp?
0bb9929e 38 with-imported-modules
838e17d8 39 with-extensions
644cb40c 40 let-system
0dbea56b
LC
41
42 gexp-input
43 gexp-input?
2ca41030
LC
44 gexp-input-thing
45 gexp-input-output
46 gexp-input-native?
558e8b11 47
d9ae938f
LC
48 local-file
49 local-file?
74d441ab 50 local-file-file
9d3994f7 51 local-file-absolute-file-name
74d441ab
LC
52 local-file-name
53 local-file-recursive?
0dbea56b 54
558e8b11
LC
55 plain-file
56 plain-file?
57 plain-file-name
58 plain-file-content
59
91937029
LC
60 computed-file
61 computed-file?
62 computed-file-name
63 computed-file-gexp
91937029
LC
64 computed-file-options
65
15a01c72
LC
66 program-file
67 program-file?
68 program-file-name
69 program-file-gexp
15a01c72 70 program-file-guile
427ec19e 71 program-file-module-path
15a01c72 72
e1c153e0
LC
73 scheme-file
74 scheme-file?
75 scheme-file-name
76 scheme-file-gexp
77
a9e5e92f
LC
78 file-append
79 file-append?
80 file-append-base
81 file-append-suffix
82
d63ee94d
LC
83 raw-derivation-file
84 raw-derivation-file?
85
cf2ac04f
LC
86 with-parameters
87 parameterized?
88
64fc9f65
RJ
89 load-path-expression
90 gexp-modules
91
2ca41030
LC
92 lower-gexp
93 lowered-gexp?
94 lowered-gexp-sexp
95 lowered-gexp-inputs
38685774 96 lowered-gexp-sources
2ca41030
LC
97 lowered-gexp-guile
98 lowered-gexp-load-path
99 lowered-gexp-load-compiled-path
100
21b679f6
LC
101 gexp->derivation
102 gexp->file
462a3fa3 103 gexp->script
aa72d9af 104 text-file*
b751cde3 105 mixed-text-file
dedb512f 106 file-union
d298c815 107 directory-union
aa72d9af
LC
108 imported-files
109 imported-modules
ff40e9b7
LC
110 compiled-modules
111
112 define-gexp-compiler
6b6298ae 113 gexp-compiler?
bdcf0e6f 114 file-like?
c2b84676 115 lower-object
6b6298ae 116
3e43166f
LC
117 lower-inputs
118
119 &gexp-error
120 gexp-error?
121 &gexp-input-error
122 gexp-input-error?
123 gexp-error-invalid-input))
21b679f6
LC
124
125;;; Commentary:
126;;;
127;;; This module implements "G-expressions", or "gexps". Gexps are like
128;;; S-expressions (sexps), with two differences:
129;;;
130;;; 1. References (un-quotations) to derivations or packages in a gexp are
667b2508
LC
131;;; replaced by the corresponding output file name; in addition, the
132;;; 'ungexp-native' unquote-like form allows code to explicitly refer to
133;;; the native code of a given package, in case of cross-compilation;
21b679f6
LC
134;;;
135;;; 2. Gexps embed information about the derivations they refer to.
136;;;
137;;; Gexps make it easy to write to files Scheme code that refers to store
138;;; items, or to write Scheme code to build derivations.
139;;;
140;;; Code:
141
142;; "G expressions".
143(define-record-type <gexp>
838e17d8 144 (make-gexp references modules extensions proc)
21b679f6 145 gexp?
affd7761 146 (references gexp-references) ;list of <gexp-input>
0bb9929e 147 (modules gexp-self-modules) ;list of module names
838e17d8 148 (extensions gexp-self-extensions) ;list of lowerable things
affd7761 149 (proc gexp-proc)) ;procedure
21b679f6 150
7560b00b
LC
151(define (write-gexp gexp port)
152 "Write GEXP on PORT."
153 (display "#<gexp " port)
2cf0ea0d
LC
154
155 ;; Try to write the underlying sexp. Now, this trick doesn't work when
156 ;; doing things like (ungexp-splicing (gexp ())) because GEXP's procedure
157 ;; tries to use 'append' on that, which fails with wrong-type-arg.
158 (false-if-exception
667b2508 159 (write (apply (gexp-proc gexp)
affd7761 160 (gexp-references gexp))
667b2508 161 port))
7560b00b
LC
162 (format port " ~a>"
163 (number->string (object-address gexp) 16)))
164
165(set-record-type-printer! <gexp> write-gexp)
166
bcb13287
LC
167\f
168;;;
169;;; Methods.
170;;;
171
172;; Compiler for a type of objects that may be introduced in a gexp.
173(define-record-type <gexp-compiler>
1cdecf24 174 (gexp-compiler type lower expand)
bcb13287 175 gexp-compiler?
1cdecf24 176 (type gexp-compiler-type) ;record type descriptor
ebdfd776 177 (lower gexp-compiler-lower)
1cdecf24 178 (expand gexp-compiler-expand)) ;#f | DRV -> sexp
bcb13287 179
3e43166f
LC
180(define-condition-type &gexp-error &error
181 gexp-error?)
182
183(define-condition-type &gexp-input-error &gexp-error
184 gexp-input-error?
185 (input gexp-error-invalid-input))
186
187
bcb13287 188(define %gexp-compilers
1cdecf24
LC
189 ;; 'eq?' mapping of record type descriptor to <gexp-compiler>.
190 (make-hash-table 20))
bcb13287 191
ebdfd776
LC
192(define (default-expander thing obj output)
193 "This is the default expander for \"things\" that appear in gexps. It
194returns its output file name of OBJ's OUTPUT."
195 (match obj
196 ((? derivation? drv)
197 (derivation->output-path drv output))
198 ((? string? file)
644cb40c
LC
199 file)
200 ((? self-quoting? obj)
201 obj)))
ebdfd776 202
bcb13287
LC
203(define (register-compiler! compiler)
204 "Register COMPILER as a gexp compiler."
1cdecf24
LC
205 (hashq-set! %gexp-compilers
206 (gexp-compiler-type compiler) compiler))
bcb13287
LC
207
208(define (lookup-compiler object)
ebdfd776 209 "Search for a compiler for OBJECT. Upon success, return the three argument
bcb13287 210procedure to lower it; otherwise return #f."
1cdecf24
LC
211 (and=> (hashq-ref %gexp-compilers (struct-vtable object))
212 gexp-compiler-lower))
bcb13287 213
bdcf0e6f
CL
214(define (file-like? object)
215 "Return #t if OBJECT leads to a file in the store once unquoted in a
216G-expression; otherwise return #f."
217 (and (struct? object) (->bool (lookup-compiler object))))
218
ebdfd776
LC
219(define (lookup-expander object)
220 "Search for an expander for OBJECT. Upon success, return the three argument
221procedure to expand it; otherwise return #f."
1cdecf24
LC
222 (and=> (hashq-ref %gexp-compilers (struct-vtable object))
223 gexp-compiler-expand))
ebdfd776 224
c2b84676
LC
225(define* (lower-object obj
226 #:optional (system (%current-system))
a6bf7a97 227 #:key (target 'current))
c2b84676
LC
228 "Return as a value in %STORE-MONAD the derivation or store item
229corresponding to OBJ for SYSTEM, cross-compiling for TARGET if TARGET is true.
230OBJ must be an object that has an associated gexp compiler, such as a
231<package>."
d03001a3
LC
232 (mlet %store-monad ((target (if (eq? target 'current)
233 (current-target-system)
234 (return target)))
235 (graft? (grafting?)))
236 (let loop ((obj obj))
237 (match (lookup-compiler obj)
238 (#f
239 (raise (condition (&gexp-input-error (input obj)))))
240 (lower
241 ;; Cache in STORE the result of lowering OBJ.
242 (mcached (mlet %store-monad ((lowered (lower obj system target)))
243 (if (and (struct? lowered)
244 (not (derivation? lowered)))
245 (loop lowered)
246 (return lowered)))
247 obj
248 system target graft?))))))
249
250(define* (lower+expand-object obj
251 #:optional (system (%current-system))
252 #:key target (output "out"))
253 "Return as a value in %STORE-MONAD the output of object OBJ expands to for
254SYSTEM and TARGET. Object such as <package>, <file-append>, or <plain-file>
255expand to file names, but it's possible to expand to a plain data type."
256 (let loop ((obj obj)
257 (expand (and (struct? obj) (lookup-expander obj))))
258 (match (lookup-compiler obj)
259 (#f
260 (raise (condition (&gexp-input-error (input obj)))))
261 (lower
262 (mlet* %store-monad ((graft? (grafting?))
263 (lowered (mcached (lower obj system target)
264 obj
265 system target graft?)))
266 ;; LOWER might return something that needs to be further
267 ;; lowered.
268 (if (struct? lowered)
269 ;; If we lack an expander, delegate to that of LOWERED.
270 (if (not expand)
271 (loop lowered (lookup-expander lowered))
272 (return (expand obj lowered output)))
273 (return lowered))))))) ;self-quoting
c2b84676 274
ebdfd776
LC
275(define-syntax define-gexp-compiler
276 (syntax-rules (=> compiler expander)
277 "Define NAME as a compiler for objects matching PREDICATE encountered in
278gexps.
279
d03001a3
LC
280In the simplest form of the macro, BODY must return (1) a derivation for
281a record of the specified type, for SYSTEM and TARGET (the latter of which is
282#f except when cross-compiling), (2) another record that can itself be
283compiled down to a derivation, or (3) an object of a primitive data type.
ebdfd776
LC
284
285The more elaborate form allows you to specify an expander:
286
d03001a3 287 (define-gexp-compiler something-compiler <something>
ebdfd776
LC
288 compiler => (lambda (param system target) ...)
289 expander => (lambda (param drv output) ...))
290
291The expander specifies how an object is converted to its sexp representation."
1cdecf24
LC
292 ((_ (name (param record-type) system target) body ...)
293 (define-gexp-compiler name record-type
ebdfd776
LC
294 compiler => (lambda (param system target) body ...)
295 expander => default-expander))
1cdecf24 296 ((_ name record-type
ebdfd776
LC
297 compiler => compile
298 expander => expand)
299 (begin
300 (define name
1cdecf24 301 (gexp-compiler record-type compile expand))
ebdfd776 302 (register-compiler! name)))))
bcb13287 303
1cdecf24 304(define-gexp-compiler (derivation-compiler (drv <derivation>) system target)
2924f0d6
LC
305 ;; Derivations are the lowest-level representation, so this is the identity
306 ;; compiler.
307 (with-monad %store-monad
308 (return drv)))
309
d63ee94d
LC
310;; Expand to a raw ".drv" file for the lowerable object it wraps. In other
311;; words, this gives the raw ".drv" file instead of its build result.
312(define-record-type <raw-derivation-file>
313 (raw-derivation-file obj)
314 raw-derivation-file?
315 (obj raw-derivation-file-object)) ;lowerable object
316
317(define-gexp-compiler raw-derivation-file-compiler <raw-derivation-file>
318 compiler => (lambda (obj system target)
319 (mlet %store-monad ((obj (lower-object
320 (raw-derivation-file-object obj)
321 system #:target target)))
322 ;; Returning the .drv file name instead of the <derivation>
323 ;; record ensures that 'lower-gexp' will classify it as a
324 ;; "source" and not as an "input".
325 (return (if (derivation? obj)
326 (derivation-file-name obj)
327 obj))))
328 expander => (lambda (obj lowered output)
329 (if (derivation? lowered)
330 (derivation-file-name lowered)
331 lowered)))
332
bcb13287 333\f
644cb40c
LC
334;;;
335;;; System dependencies.
336;;;
337
338;; Binding form for the current system and cross-compilation target.
339(define-record-type <system-binding>
340 (system-binding proc)
341 system-binding?
342 (proc system-binding-proc))
343
344(define-syntax let-system
345 (syntax-rules ()
346 "Introduce a system binding in a gexp. The simplest form is:
347
348 (let-system system
349 (cond ((string=? system \"x86_64-linux\") ...)
350 (else ...)))
351
352which binds SYSTEM to the currently targeted system. The second form is
353similar, but it also shows the cross-compilation target:
354
355 (let-system (system target)
356 ...)
357
358Here TARGET is bound to the cross-compilation triplet or #f."
359 ((_ (system target) exp0 exp ...)
360 (system-binding (lambda (system target)
361 exp0 exp ...)))
362 ((_ system exp0 exp ...)
363 (system-binding (lambda (system target)
364 exp0 exp ...)))))
365
366(define-gexp-compiler system-binding-compiler <system-binding>
367 compiler => (lambda (binding system target)
368 (match binding
369 (($ <system-binding> proc)
370 (with-monad %store-monad
371 ;; PROC is expected to return a lowerable object.
372 ;; 'lower-object' takes care of residualizing it to a
373 ;; derivation or similar.
374 (return (proc system target))))))
375
376 ;; Delegate to the expander of the object returned by PROC.
377 expander => #f)
378
379\f
d9ae938f 380;;;
558e8b11 381;;; File declarations.
d9ae938f
LC
382;;;
383
9d3994f7
LC
384;; A local file name. FILE is the file name the user entered, which can be a
385;; relative file name, and ABSOLUTE is a promise that computes its canonical
386;; absolute file name. We keep it in a promise to compute it lazily and avoid
387;; repeated 'stat' calls.
d9ae938f 388(define-record-type <local-file>
0687fc9c 389 (%%local-file file absolute name recursive? select?)
d9ae938f
LC
390 local-file?
391 (file local-file-file) ;string
9d3994f7 392 (absolute %local-file-absolute-file-name) ;promise string
d9ae938f 393 (name local-file-name) ;string
0687fc9c
LC
394 (recursive? local-file-recursive?) ;Boolean
395 (select? local-file-select?)) ;string stat -> Boolean
396
397(define (true file stat) #t)
d9ae938f 398
9d3994f7 399(define* (%local-file file promise #:optional (name (basename file))
0687fc9c 400 #:key recursive? (select? true))
9d3994f7
LC
401 ;; This intermediate procedure is part of our ABI, but the underlying
402 ;; %%LOCAL-FILE is not.
0687fc9c 403 (%%local-file file promise name recursive? select?))
9d3994f7 404
9d3994f7
LC
405(define (absolute-file-name file directory)
406 "Return the canonical absolute file name for FILE, which lives in the
407vicinity of DIRECTORY."
408 (canonicalize-path
409 (cond ((string-prefix? "/" file) file)
410 ((not directory) file)
411 ((string-prefix? "/" directory)
412 (string-append directory "/" file))
413 (else file))))
414
302d46e6
LC
415(define-syntax local-file
416 (lambda (s)
417 "Return an object representing local file FILE to add to the store; this
9d3994f7
LC
418object can be used in a gexp. If FILE is a relative file name, it is looked
419up relative to the source file where this form appears. FILE will be added to
420the store under NAME--by default the base name of FILE.
d9ae938f
LC
421
422When RECURSIVE? is true, the contents of FILE are added recursively; if FILE
423designates a flat file and RECURSIVE? is true, its contents are added, and its
424permission bits are kept.
425
0687fc9c
LC
426When RECURSIVE? is true, call (SELECT? FILE STAT) for each directory entry,
427where FILE is the entry's absolute file name and STAT is the result of
428'lstat'; exclude entries for which SELECT? does not return true.
429
302d46e6
LC
430This is the declarative counterpart of the 'interned-file' monadic procedure.
431It is implemented as a macro to capture the current source directory where it
432appears."
433 (syntax-case s ()
434 ((_ file rest ...)
99c45877
LC
435 (string? (syntax->datum #'file))
436 ;; FILE is a literal, so resolve it relative to the source directory.
302d46e6
LC
437 #'(%local-file file
438 (delay (absolute-file-name file (current-source-directory)))
439 rest ...))
99c45877
LC
440 ((_ file rest ...)
441 ;; Resolve FILE relative to the current directory.
442 #'(%local-file file
443 (delay (absolute-file-name file (getcwd)))
444 rest ...))
302d46e6
LC
445 ((_)
446 #'(syntax-error "missing file name"))
447 (id
448 (identifier? #'id)
449 ;; XXX: We could return #'(lambda (file . rest) ...). However,
450 ;; (syntax-source #'id) is #f so (current-source-directory) would not
451 ;; work. Thus, simply forbid this form.
452 #'(syntax-error
453 "'local-file' is a macro and cannot be used like this")))))
9d3994f7
LC
454
455(define (local-file-absolute-file-name file)
456 "Return the absolute file name for FILE, a <local-file> instance. A
457'system-error' exception is raised if FILE could not be found."
458 (force (%local-file-absolute-file-name file)))
d9ae938f 459
1cdecf24 460(define-gexp-compiler (local-file-compiler (file <local-file>) system target)
d9ae938f
LC
461 ;; "Compile" FILE by adding it to the store.
462 (match file
0687fc9c 463 (($ <local-file> file (= force absolute) name recursive? select?)
9d3994f7
LC
464 ;; Canonicalize FILE so that if it's a symlink, it is resolved. Failing
465 ;; to do that, when RECURSIVE? is #t, we could end up creating a dangling
466 ;; symlink in the store, and when RECURSIVE? is #f 'add-to-store' would
467 ;; just throw an error, both of which are inconvenient.
0687fc9c
LC
468 (interned-file absolute name
469 #:recursive? recursive? #:select? select?))))
d9ae938f 470
558e8b11
LC
471(define-record-type <plain-file>
472 (%plain-file name content references)
473 plain-file?
474 (name plain-file-name) ;string
e8e1f295 475 (content plain-file-content) ;string or bytevector
558e8b11
LC
476 (references plain-file-references)) ;list (currently unused)
477
478(define (plain-file name content)
479 "Return an object representing a text file called NAME with the given
480CONTENT (a string) to be added to the store.
481
482This is the declarative counterpart of 'text-file'."
483 ;; XXX: For now just ignore 'references' because it's not clear how to use
484 ;; them in a declarative context.
485 (%plain-file name content '()))
486
1cdecf24 487(define-gexp-compiler (plain-file-compiler (file <plain-file>) system target)
558e8b11
LC
488 ;; "Compile" FILE by adding it to the store.
489 (match file
e8e1f295
JN
490 (($ <plain-file> name (and (? string?) content) references)
491 (text-file name content references))
492 (($ <plain-file> name (and (? bytevector?) content) references)
493 (binary-file name content references))))
558e8b11 494
91937029 495(define-record-type <computed-file>
ab25eb7c 496 (%computed-file name gexp guile options)
91937029
LC
497 computed-file?
498 (name computed-file-name) ;string
499 (gexp computed-file-gexp) ;gexp
ab25eb7c 500 (guile computed-file-guile) ;<package>
91937029
LC
501 (options computed-file-options)) ;list of arguments
502
503(define* (computed-file name gexp
ab25eb7c 504 #:key guile (options '(#:local-build? #t)))
91937029 505 "Return an object representing the store item NAME, a file or directory
a769bffb 506computed by GEXP. OPTIONS is a list of additional arguments to pass
91937029
LC
507to 'gexp->derivation'.
508
509This is the declarative counterpart of 'gexp->derivation'."
ab25eb7c 510 (%computed-file name gexp guile options))
91937029 511
1cdecf24 512(define-gexp-compiler (computed-file-compiler (file <computed-file>)
91937029
LC
513 system target)
514 ;; Compile FILE by returning a derivation whose build expression is its
515 ;; gexp.
516 (match file
ab25eb7c
LC
517 (($ <computed-file> name gexp guile options)
518 (if guile
519 (mlet %store-monad ((guile (lower-object guile system
520 #:target target)))
521 (apply gexp->derivation name gexp #:guile-for-build guile
9ec154f5
LC
522 #:system system #:target target options))
523 (apply gexp->derivation name gexp
524 #:system system #:target target options)))))
91937029 525
15a01c72 526(define-record-type <program-file>
427ec19e 527 (%program-file name gexp guile path)
15a01c72
LC
528 program-file?
529 (name program-file-name) ;string
530 (gexp program-file-gexp) ;gexp
427ec19e
LC
531 (guile program-file-guile) ;package
532 (path program-file-module-path)) ;list of strings
15a01c72 533
427ec19e 534(define* (program-file name gexp #:key (guile #f) (module-path %load-path))
15a01c72 535 "Return an object representing the executable store item NAME that runs
427ec19e
LC
536GEXP. GUILE is the Guile package used to execute that script. Imported
537modules of GEXP are looked up in MODULE-PATH.
15a01c72
LC
538
539This is the declarative counterpart of 'gexp->script'."
427ec19e 540 (%program-file name gexp guile module-path))
15a01c72 541
1cdecf24 542(define-gexp-compiler (program-file-compiler (file <program-file>)
15a01c72
LC
543 system target)
544 ;; Compile FILE by returning a derivation that builds the script.
545 (match file
427ec19e 546 (($ <program-file> name gexp guile module-path)
15a01c72 547 (gexp->script name gexp
427ec19e 548 #:module-path module-path
2e8cabb8
LC
549 #:guile (or guile (default-guile))
550 #:system system
551 #:target target))))
15a01c72 552
e1c153e0 553(define-record-type <scheme-file>
34faf63e 554 (%scheme-file name gexp splice? load-path?)
e1c153e0
LC
555 scheme-file?
556 (name scheme-file-name) ;string
4fbd1a2b 557 (gexp scheme-file-gexp) ;gexp
34faf63e
LC
558 (splice? scheme-file-splice?) ;Boolean
559 (load-path? scheme-file-set-load-path?)) ;Boolean
e1c153e0 560
34faf63e 561(define* (scheme-file name gexp #:key splice? (set-load-path? #t))
e1c153e0
LC
562 "Return an object representing the Scheme file NAME that contains GEXP.
563
564This is the declarative counterpart of 'gexp->file'."
34faf63e 565 (%scheme-file name gexp splice? set-load-path?))
e1c153e0 566
1cdecf24 567(define-gexp-compiler (scheme-file-compiler (file <scheme-file>)
e1c153e0
LC
568 system target)
569 ;; Compile FILE by returning a derivation that builds the file.
570 (match file
34faf63e 571 (($ <scheme-file> name gexp splice? set-load-path?)
3cd1444d 572 (gexp->file name gexp
34faf63e 573 #:set-load-path? set-load-path?
3cd1444d
MO
574 #:splice? splice?
575 #:system system
576 #:target target))))
e1c153e0 577
a9e5e92f
LC
578;; Appending SUFFIX to BASE's output file name.
579(define-record-type <file-append>
580 (%file-append base suffix)
581 file-append?
582 (base file-append-base) ;<package> | <derivation> | ...
583 (suffix file-append-suffix)) ;list of strings
584
39d7fdce
LC
585(define (write-file-append file port)
586 (match file
587 (($ <file-append> base suffix)
588 (format port "#<file-append ~s ~s>" base
589 (string-join suffix)))))
590
591(set-record-type-printer! <file-append> write-file-append)
592
a9e5e92f
LC
593(define (file-append base . suffix)
594 "Return a <file-append> object that expands to the concatenation of BASE and
595SUFFIX."
596 (%file-append base suffix))
597
1cdecf24 598(define-gexp-compiler file-append-compiler <file-append>
a9e5e92f
LC
599 compiler => (lambda (obj system target)
600 (match obj
601 (($ <file-append> base _)
602 (lower-object base system #:target target))))
603 expander => (lambda (obj lowered output)
604 (match obj
605 (($ <file-append> base suffix)
606 (let* ((expand (lookup-expander base))
607 (base (expand base lowered output)))
608 (string-append base (string-concatenate suffix)))))))
609
cf2ac04f
LC
610;; Representation of SRFI-39 parameter settings in the dynamic scope of an
611;; object lowering.
612(define-record-type <parameterized>
613 (parameterized bindings thunk)
614 parameterized?
615 (bindings parameterized-bindings) ;list of parameter/value pairs
616 (thunk parameterized-thunk)) ;thunk
617
618(define-syntax-rule (with-parameters ((param value) ...) body ...)
619 "Bind each PARAM to the corresponding VALUE for the extent during which BODY
620is lowered. Consider this example:
621
622 (with-parameters ((%current-system \"x86_64-linux\"))
623 coreutils)
624
625It returns a <parameterized> object that ensures %CURRENT-SYSTEM is set to
626x86_64-linux when COREUTILS is lowered."
627 (parameterized (list (list param (lambda () value)) ...)
628 (lambda ()
629 body ...)))
630
631(define-gexp-compiler compile-parameterized <parameterized>
632 compiler =>
633 (lambda (parameterized system target)
634 (match (parameterized-bindings parameterized)
635 (((parameters values) ...)
636 (let ((fluids (map parameter-fluid parameters))
637 (thunk (parameterized-thunk parameterized)))
638 ;; Install the PARAMETERS for the dynamic extent of THUNK.
639 (with-fluids* fluids
640 (map (lambda (thunk) (thunk)) values)
641 (lambda ()
642 ;; Special-case '%current-system' and '%current-target-system' to
643 ;; make sure we get the desired effect.
644 (let ((system (if (memq %current-system parameters)
645 (%current-system)
646 system))
647 (target (if (memq %current-target-system parameters)
648 (%current-target-system)
649 target)))
650 (lower-object (thunk) system #:target target))))))))
651
652 expander => (lambda (parameterized lowered output)
653 (match (parameterized-bindings parameterized)
654 (((parameters values) ...)
655 (let ((fluids (map parameter-fluid parameters))
656 (thunk (parameterized-thunk parameterized)))
657 ;; Install the PARAMETERS for the dynamic extent of THUNK.
658 (with-fluids* fluids
659 (map (lambda (thunk) (thunk)) values)
660 (lambda ()
661 ;; Delegate to the expander of the wrapped object.
662 (let* ((base (thunk))
663 (expand (lookup-expander base)))
664 (expand base lowered output)))))))))
a9e5e92f 665
d9ae938f 666\f
bcb13287
LC
667;;;
668;;; Inputs & outputs.
669;;;
670
e39d1461
LC
671;; The input of a gexp.
672(define-record-type <gexp-input>
0dbea56b 673 (%gexp-input thing output native?)
e39d1461
LC
674 gexp-input?
675 (thing gexp-input-thing) ;<package> | <origin> | <derivation> | ...
676 (output gexp-input-output) ;string
677 (native? gexp-input-native?)) ;Boolean
678
f7328634
LC
679(define (write-gexp-input input port)
680 (match input
681 (($ <gexp-input> thing output #f)
682 (format port "#<gexp-input ~s:~a>" thing output))
683 (($ <gexp-input> thing output #t)
684 (format port "#<gexp-input native ~s:~a>" thing output))))
685
686(set-record-type-printer! <gexp-input> write-gexp-input)
687
0dbea56b
LC
688(define* (gexp-input thing ;convenience procedure
689 #:optional (output "out")
690 #:key native?)
691 "Return a new <gexp-input> for the OUTPUT of THING; NATIVE? determines
692whether this should be considered a \"native\" input or not."
693 (%gexp-input thing output native?))
694
21b679f6
LC
695;; Reference to one of the derivation's outputs, for gexps used in
696;; derivations.
1e87da58
LC
697(define-record-type <gexp-output>
698 (gexp-output name)
699 gexp-output?
700 (name gexp-output-name))
21b679f6 701
f7328634
LC
702(define (write-gexp-output output port)
703 (match output
704 (($ <gexp-output> name)
705 (format port "#<gexp-output ~a>" name))))
706
707(set-record-type-printer! <gexp-output> write-gexp-output)
708
932d1600 709(define* (gexp-attribute gexp self-attribute #:optional (equal? equal?))
838e17d8 710 "Recurse on GEXP and the expressions it refers to, summing the items
932d1600
LC
711returned by SELF-ATTRIBUTE, a procedure that takes a gexp. Use EQUAL? as the
712second argument to 'delete-duplicates'."
2363bdd7
LC
713 (if (gexp? gexp)
714 (delete-duplicates
838e17d8 715 (append (self-attribute gexp)
2363bdd7
LC
716 (append-map (match-lambda
717 (($ <gexp-input> (? gexp? exp))
838e17d8 718 (gexp-attribute exp self-attribute))
2363bdd7
LC
719 (($ <gexp-input> (lst ...))
720 (append-map (lambda (item)
721 (if (gexp? item)
838e17d8
LC
722 (gexp-attribute item
723 self-attribute)
2363bdd7
LC
724 '()))
725 lst))
726 (_
727 '()))
932d1600
LC
728 (gexp-references gexp)))
729 equal?)
2363bdd7 730 '())) ;plain Scheme data type
0bb9929e 731
838e17d8
LC
732(define (gexp-modules gexp)
733 "Return the list of Guile module names GEXP relies on. If (gexp? GEXP) is
734false, meaning that GEXP is a plain Scheme object, return the empty list."
932d1600
LC
735 (define (module=? m1 m2)
736 ;; Return #t when M1 equals M2. Special-case '=>' specs because their
737 ;; right-hand side may not be comparable with 'equal?': it's typically a
738 ;; file-like object that embeds a gexp, which in turn embeds closure;
739 ;; those closures may be 'eq?' when running compiled code but are unlikely
740 ;; to be 'eq?' when running on 'eval'. Ignore the right-hand side to
741 ;; avoid this discrepancy.
742 (match m1
743 (((name1 ...) '=> _)
744 (match m2
745 (((name2 ...) '=> _) (equal? name1 name2))
746 (_ #f)))
747 (_
748 (equal? m1 m2))))
749
750 (gexp-attribute gexp gexp-self-modules module=?))
838e17d8
LC
751
752(define (gexp-extensions gexp)
753 "Return the list of Guile extensions (packages) GEXP relies on. If (gexp?
754GEXP) is false, meaning that GEXP is a plain Scheme object, return the empty
755list."
756 (gexp-attribute gexp gexp-self-extensions))
757
644cb40c
LC
758(define (self-quoting? x)
759 (letrec-syntax ((one-of (syntax-rules ()
760 ((_) #f)
761 ((_ pred rest ...)
762 (or (pred x)
763 (one-of rest ...))))))
764 (one-of symbol? string? keyword? pair? null? array?
765 number? boolean? char?)))
766
68a61e9f
LC
767(define* (lower-inputs inputs
768 #:key system target)
38685774
LC
769 "Turn any object from INPUTS into a derivation input for SYSTEM or a store
770item (a \"source\"); return the corresponding input list as a monadic value.
771When TARGET is true, use it as the cross-compilation target triplet."
2ca41030
LC
772 (define (store-item? obj)
773 (and (string? obj) (store-path? obj)))
774
644cb40c
LC
775 (define filterm
776 (lift1 (cut filter ->bool <>) %store-monad))
777
21b679f6 778 (with-monad %store-monad
644cb40c
LC
779 (>>= (mapm/accumulate-builds
780 (match-lambda
781 (((? struct? thing) sub-drv ...)
782 (mlet %store-monad ((obj (lower-object
783 thing system #:target target)))
784 (return (match obj
785 ((? derivation? drv)
786 (let ((outputs (if (null? sub-drv)
787 '("out")
788 sub-drv)))
789 (derivation-input drv outputs)))
790 ((? store-item? item)
791 item)
792 ((? self-quoting?)
793 ;; Some inputs such as <system-binding> can lower to
794 ;; a self-quoting object that FILTERM will filter
795 ;; out.
796 #f)))))
797 (((? store-item? item))
798 (return item)))
799 inputs)
800 filterm)))
21b679f6 801
b53833b2
LC
802(define* (lower-reference-graphs graphs #:key system target)
803 "Given GRAPHS, a list of (FILE-NAME INPUT ...) lists for use as a
804#:reference-graphs argument, lower it such that each INPUT is replaced by the
38685774 805corresponding <derivation-input> or store item."
b53833b2
LC
806 (match graphs
807 (((file-names . inputs) ...)
808 (mlet %store-monad ((inputs (lower-inputs inputs
809 #:system system
810 #:target target)))
38685774 811 (return (map cons file-names inputs))))))
b53833b2 812
c8351d9a
LC
813(define* (lower-references lst #:key system target)
814 "Based on LST, a list of output names and packages, return a list of output
815names and file names suitable for the #:allowed-references argument to
816'derivation'."
c8351d9a
LC
817 (with-monad %store-monad
818 (define lower
819 (match-lambda
820 ((? string? output)
821 (return output))
accb682c 822 (($ <gexp-input> thing output native?)
c2b84676
LC
823 (mlet %store-monad ((drv (lower-object thing system
824 #:target (if native?
825 #f target))))
accb682c 826 (return (derivation->output-path drv output))))
bcb13287 827 (thing
c2b84676
LC
828 (mlet %store-monad ((drv (lower-object thing system
829 #:target target)))
c8351d9a
LC
830 (return (derivation->output-path drv))))))
831
b34ead48 832 (mapm/accumulate-builds lower lst)))
c8351d9a 833
ff40e9b7
LC
834(define default-guile-derivation
835 ;; Here we break the abstraction by talking to the higher-level layer.
836 ;; Thus, do the resolution lazily to hide the circular dependency.
837 (let ((proc (delay
838 (let ((iface (resolve-interface '(guix packages))))
839 (module-ref iface 'default-guile-derivation)))))
840 (lambda (system)
841 ((force proc) system))))
842
2ca41030 843;; Representation of a gexp instantiated for a given target and system.
38685774 844;; It's an intermediate representation between <gexp> and <derivation>.
2ca41030 845(define-record-type <lowered-gexp>
38685774 846 (lowered-gexp sexp inputs sources guile load-path load-compiled-path)
2ca41030
LC
847 lowered-gexp?
848 (sexp lowered-gexp-sexp) ;sexp
38685774
LC
849 (inputs lowered-gexp-inputs) ;list of <derivation-input>
850 (sources lowered-gexp-sources) ;list of store items
b9373e26 851 (guile lowered-gexp-guile) ;<derivation-input> | #f
2ca41030
LC
852 (load-path lowered-gexp-load-path) ;list of store items
853 (load-compiled-path lowered-gexp-load-compiled-path)) ;list of store items
854
f58b4535
LC
855(define* (imported+compiled-modules modules system
856 #:key (extensions '())
857 deprecation-warnings guile
858 (module-path %load-path))
859 "Return a pair where the first element is the imported MODULES and the
860second element is the derivation to compile them."
f5fca9a8
LC
861 (mcached equal?
862 (mlet %store-monad ((modules (if (pair? modules)
863 (imported-modules modules
864 #:system system
865 #:module-path module-path)
866 (return #f)))
867 (compiled (if (pair? modules)
868 (compiled-modules modules
869 #:system system
870 #:module-path module-path
871 #:extensions extensions
872 #:guile guile
873 #:deprecation-warnings
874 deprecation-warnings)
875 (return #f))))
876 (return (cons modules compiled)))
877 modules
878 system extensions guile deprecation-warnings module-path))
f58b4535 879
2ca41030
LC
880(define* (lower-gexp exp
881 #:key
882 (module-path %load-path)
883 (system (%current-system))
884 (target 'current)
885 (graft? (%graft?))
886 (guile-for-build (%guile-for-build))
2bc1a400 887 (effective-version "3.0")
2ca41030 888
fb9a23a3 889 deprecation-warnings)
2ca41030
LC
890 "*Note: This API is subject to change; use at your own risk!*
891
892Lower EXP, a gexp, instantiating it for SYSTEM and TARGET. Return a
893<lowered-gexp> ready to be used.
894
895Lowered gexps are an intermediate representation that's useful for
896applications that deal with gexps outside in a way that is disconnected from
897derivations--e.g., code evaluated for its side effects."
898 (define %modules
899 (delete-duplicates (gexp-modules exp)))
900
901 (define (search-path modules extensions suffix)
902 (append (match modules
903 ((? derivation? drv)
904 (list (derivation->output-path drv)))
905 (#f
906 '())
907 ((? store-path? item)
908 (list item)))
909 (map (lambda (extension)
910 (string-append (match extension
911 ((? derivation? drv)
912 (derivation->output-path drv))
913 ((? store-path? item)
914 item))
915 suffix))
916 extensions)))
917
918 (mlet* %store-monad ( ;; The following binding forces '%current-system' and
919 ;; '%current-target-system' to be looked up at >>=
920 ;; time.
921 (graft? (set-grafting graft?))
922
923 (system -> (or system (%current-system)))
924 (target -> (if (eq? target 'current)
925 (%current-target-system)
926 target))
927 (guile (if guile-for-build
928 (return guile-for-build)
929 (default-guile-derivation system)))
930 (normals (lower-inputs (gexp-inputs exp)
931 #:system system
932 #:target target))
933 (natives (lower-inputs (gexp-native-inputs exp)
934 #:system system
935 #:target #f))
936 (inputs -> (append normals natives))
937 (sexp (gexp->sexp exp
938 #:system system
939 #:target target))
940 (extensions -> (gexp-extensions exp))
941 (exts (mapm %store-monad
942 (lambda (obj)
a6bf7a97
MO
943 (lower-object obj system
944 #:target #f))
2ca41030 945 extensions))
f58b4535
LC
946 (modules+compiled (imported+compiled-modules
947 %modules system
948 #:extensions extensions
949 #:deprecation-warnings
950 deprecation-warnings
951 #:guile guile
952 #:module-path module-path))
953 (modules -> (car modules+compiled))
954 (compiled -> (cdr modules+compiled)))
2ca41030
LC
955 (define load-path
956 (search-path modules exts
957 (string-append "/share/guile/site/" effective-version)))
958
959 (define load-compiled-path
960 (search-path compiled exts
961 (string-append "/lib/guile/" effective-version
962 "/site-ccache")))
963
964 (mbegin %store-monad
965 (set-grafting graft?) ;restore the initial setting
966 (return (lowered-gexp sexp
38685774
LC
967 `(,@(if (derivation? modules)
968 (list (derivation-input modules))
2ca41030
LC
969 '())
970 ,@(if compiled
38685774 971 (list (derivation-input compiled))
2ca41030 972 '())
38685774
LC
973 ,@(map derivation-input exts)
974 ,@(filter derivation-input? inputs))
975 (filter string? (cons modules inputs))
b9373e26 976 (derivation-input guile '("out"))
2ca41030
LC
977 load-path
978 load-compiled-path)))))
979
21b679f6
LC
980(define* (gexp->derivation name exp
981 #:key
68a61e9f 982 system (target 'current)
21b679f6
LC
983 hash hash-algo recursive?
984 (env-vars '())
985 (modules '())
4684f301 986 (module-path %load-path)
21b679f6 987 (guile-for-build (%guile-for-build))
2bc1a400 988 (effective-version "3.0")
ce45eb4c 989 (graft? (%graft?))
21b679f6 990 references-graphs
3f4ecf32 991 allowed-references disallowed-references
c0468155 992 leaked-env-vars
0309e1b0 993 local-build? (substitutable? #t)
8856f409 994 (properties '())
a912c723 995 deprecation-warnings
0309e1b0 996 (script-name (string-append name "-builder")))
21b679f6 997 "Return a derivation NAME that runs EXP (a gexp) with GUILE-FOR-BUILD (a
0309e1b0
LC
998derivation) on SYSTEM; EXP is stored in a file called SCRIPT-NAME. When
999TARGET is true, it is used as the cross-compilation target triplet for
1000packages referred to by EXP.
21b679f6 1001
0bb9929e
LC
1002MODULES is deprecated in favor of 'with-imported-modules'. Its meaning is to
1003make MODULES available in the evaluation context of EXP; MODULES is a list of
4684f301 1004names of Guile modules searched in MODULE-PATH to be copied in the store,
21b679f6
LC
1005compiled, and made available in the load path during the execution of
1006EXP---e.g., '((guix build utils) (guix build gnu-build-system)).
1007
838e17d8
LC
1008EFFECTIVE-VERSION determines the string to use when adding extensions of
1009EXP (see 'with-extensions') to the search path---e.g., \"2.2\".
1010
ce45eb4c
LC
1011GRAFT? determines whether packages referred to by EXP should be grafted when
1012applicable.
1013
b53833b2
LC
1014When REFERENCES-GRAPHS is true, it must be a list of tuples of one of the
1015following forms:
1016
1017 (FILE-NAME PACKAGE)
1018 (FILE-NAME PACKAGE OUTPUT)
1019 (FILE-NAME DERIVATION)
1020 (FILE-NAME DERIVATION OUTPUT)
1021 (FILE-NAME STORE-ITEM)
1022
1023The right-hand-side of each element of REFERENCES-GRAPHS is automatically made
1024an input of the build process of EXP. In the build environment, each
1025FILE-NAME contains the reference graph of the corresponding item, in a simple
1026text format.
1027
c8351d9a
LC
1028ALLOWED-REFERENCES must be either #f or a list of output names and packages.
1029In the latter case, the list denotes store items that the result is allowed to
1030refer to. Any reference to another store item will lead to a build error.
3f4ecf32
LC
1031Similarly for DISALLOWED-REFERENCES, which can list items that must not be
1032referenced by the outputs.
b53833b2 1033
a912c723
LC
1034DEPRECATION-WARNINGS determines whether to show deprecation warnings while
1035compiling modules. It can be #f, #t, or 'detailed.
1036
21b679f6 1037The other arguments are as for 'derivation'."
21b679f6 1038 (define outputs (gexp-outputs exp))
2ca41030 1039 (define requested-graft? graft?)
21b679f6 1040
b53833b2
LC
1041 (define (graphs-file-names graphs)
1042 ;; Return a list of (FILE-NAME . STORE-PATH) pairs made from GRAPHS.
1043 (map (match-lambda
38685774
LC
1044 ((file-name . (? derivation-input? input))
1045 (cons file-name (first (derivation-input-output-paths input))))
1046 ((file-name . (? string? item))
1047 (cons file-name item)))
b53833b2
LC
1048 graphs))
1049
2ca41030
LC
1050 (define (add-modules exp modules)
1051 (if (null? modules)
1052 exp
1053 (make-gexp (gexp-references exp)
1054 (append modules (gexp-self-modules exp))
1055 (gexp-self-extensions exp)
1056 (gexp-proc exp))))
838e17d8
LC
1057
1058 (mlet* %store-monad ( ;; The following binding forces '%current-system' and
ce45eb4c
LC
1059 ;; '%current-target-system' to be looked up at >>=
1060 ;; time.
1061 (graft? (set-grafting graft?))
68a61e9f 1062
5d098459 1063 (system -> (or system (%current-system)))
68a61e9f
LC
1064 (target -> (if (eq? target 'current)
1065 (%current-target-system)
1066 target))
2ca41030
LC
1067 (exp -> (add-modules exp modules))
1068 (lowered (lower-gexp exp
1069 #:module-path module-path
1070 #:system system
1071 #:target target
1072 #:graft? requested-graft?
1073 #:guile-for-build
1074 guile-for-build
1075 #:effective-version
1076 effective-version
1077 #:deprecation-warnings
fb9a23a3 1078 deprecation-warnings))
2ca41030 1079
b53833b2
LC
1080 (graphs (if references-graphs
1081 (lower-reference-graphs references-graphs
1082 #:system system
1083 #:target target)
1084 (return #f)))
c8351d9a
LC
1085 (allowed (if allowed-references
1086 (lower-references allowed-references
1087 #:system system
1088 #:target target)
1089 (return #f)))
3f4ecf32
LC
1090 (disallowed (if disallowed-references
1091 (lower-references disallowed-references
1092 #:system system
1093 #:target target)
1094 (return #f)))
2ca41030
LC
1095 (guile -> (lowered-gexp-guile lowered))
1096 (builder (text-file script-name
1097 (object->string
1098 (lowered-gexp-sexp lowered)))))
ce45eb4c
LC
1099 (mbegin %store-monad
1100 (set-grafting graft?) ;restore the initial setting
1101 (raw-derivation name
b9373e26 1102 (string-append (derivation-input-output-path guile)
ce45eb4c
LC
1103 "/bin/guile")
1104 `("--no-auto-compile"
2ca41030
LC
1105 ,@(append-map (lambda (directory)
1106 `("-L" ,directory))
1107 (lowered-gexp-load-path lowered))
1108 ,@(append-map (lambda (directory)
1109 `("-C" ,directory))
1110 (lowered-gexp-load-compiled-path lowered))
ce45eb4c
LC
1111 ,builder)
1112 #:outputs outputs
1113 #:env-vars env-vars
1114 #:system system
b9373e26 1115 #:inputs `(,guile
38685774 1116 ,@(lowered-gexp-inputs lowered)
ce45eb4c 1117 ,@(match graphs
38685774
LC
1118 (((_ . inputs) ...)
1119 (filter derivation-input? inputs))
1120 (#f '())))
1121 #:sources `(,builder
1122 ,@(if (and (string? modules)
1123 (store-path? modules))
1124 (list modules)
1125 '())
1126 ,@(lowered-gexp-sources lowered)
1127 ,@(match graphs
1128 (((_ . inputs) ...)
1129 (filter string? inputs))
1130 (#f '())))
1131
ce45eb4c
LC
1132 #:hash hash #:hash-algo hash-algo #:recursive? recursive?
1133 #:references-graphs (and=> graphs graphs-file-names)
1134 #:allowed-references allowed
3f4ecf32 1135 #:disallowed-references disallowed
c0468155 1136 #:leaked-env-vars leaked-env-vars
4a6aeb67 1137 #:local-build? local-build?
8856f409
LC
1138 #:substitutable? substitutable?
1139 #:properties properties))))
21b679f6 1140
1123759b
LC
1141(define* (gexp-inputs exp #:key native?)
1142 "Return the input list for EXP. When NATIVE? is true, return only native
1143references; otherwise, return only non-native references."
2ca41030 1144 ;; TODO: Return <gexp-input> records instead of tuples.
21b679f6
LC
1145 (define (add-reference-inputs ref result)
1146 (match ref
1123759b
LC
1147 (($ <gexp-input> (? gexp? exp) _ #t)
1148 (if native?
1149 (append (gexp-inputs exp)
1150 (gexp-inputs exp #:native? #t)
1151 result)
1152 result))
1153 (($ <gexp-input> (? gexp? exp) _ #f)
d343a60f
LC
1154 (append (gexp-inputs exp #:native? native?)
1155 result))
e39d1461
LC
1156 (($ <gexp-input> (? string? str))
1157 (if (direct-store-path? str)
1158 (cons `(,str) result)
21b679f6 1159 result))
5b14a790
LC
1160 (($ <gexp-input> (? struct? thing) output n?)
1161 (if (and (eqv? n? native?) (lookup-compiler thing))
bcb13287
LC
1162 ;; THING is a derivation, or a package, or an origin, etc.
1163 (cons `(,thing ,output) result)
1164 result))
1123759b 1165 (($ <gexp-input> (lst ...) output n?)
578dfbe0
LC
1166 (fold-right add-reference-inputs result
1167 ;; XXX: For now, automatically convert LST to a list of
1168 ;; gexp-inputs. Inherit N?.
1169 (map (match-lambda
1170 ((? gexp-input? x)
1171 (%gexp-input (gexp-input-thing x)
1172 (gexp-input-output x)
1173 n?))
1174 (x
1175 (%gexp-input x "out" n?)))
1176 lst)))
21b679f6
LC
1177 (_
1178 ;; Ignore references to other kinds of objects.
1179 result)))
1180
1181 (fold-right add-reference-inputs
1182 '()
5b14a790 1183 (gexp-references exp)))
667b2508
LC
1184
1185(define gexp-native-inputs
1123759b 1186 (cut gexp-inputs <> #:native? #t))
21b679f6
LC
1187
1188(define (gexp-outputs exp)
1189 "Return the outputs referred to by EXP as a list of strings."
1190 (define (add-reference-output ref result)
1191 (match ref
1e87da58 1192 (($ <gexp-output> name)
21b679f6 1193 (cons name result))
e39d1461 1194 (($ <gexp-input> (? gexp? exp))
21b679f6 1195 (append (gexp-outputs exp) result))
e39d1461
LC
1196 (($ <gexp-input> (lst ...) output native?)
1197 ;; XXX: Automatically convert LST.
0dbea56b
LC
1198 (add-reference-output (map (match-lambda
1199 ((? gexp-input? x) x)
1200 (x (%gexp-input x "out" native?)))
1201 lst)
e39d1461 1202 result))
f9efe568
LC
1203 ((lst ...)
1204 (fold-right add-reference-output result lst))
21b679f6
LC
1205 (_
1206 result)))
1207
7e75a673
LC
1208 (delete-duplicates
1209 (add-reference-output (gexp-references exp) '())))
21b679f6 1210
68a61e9f
LC
1211(define* (gexp->sexp exp #:key
1212 (system (%current-system))
1213 (target (%current-target-system)))
21b679f6
LC
1214 "Return (monadically) the sexp corresponding to EXP for the given OUTPUT,
1215and in the current monad setting (system type, etc.)"
667b2508 1216 (define* (reference->sexp ref #:optional native?)
21b679f6
LC
1217 (with-monad %store-monad
1218 (match ref
1e87da58 1219 (($ <gexp-output> output)
bfd9eed9
LC
1220 ;; Output file names are not known in advance but the daemon defines
1221 ;; an environment variable for each of them at build time, so use
1222 ;; that trick.
1223 (return `((@ (guile) getenv) ,output)))
e39d1461 1224 (($ <gexp-input> (? gexp? exp) output n?)
667b2508
LC
1225 (gexp->sexp exp
1226 #:system system
e39d1461
LC
1227 #:target (if (or n? native?) #f target)))
1228 (($ <gexp-input> (refs ...) output n?)
b334674f
LC
1229 (mapm %store-monad
1230 (lambda (ref)
1231 ;; XXX: Automatically convert REF to an gexp-input.
1232 (reference->sexp
1233 (if (gexp-input? ref)
1234 ref
1235 (%gexp-input ref "out" n?))
1236 (or n? native?)))
1237 refs))
bcb13287 1238 (($ <gexp-input> (? struct? thing) output n?)
d03001a3
LC
1239 (let ((target (if (or n? native?) #f target)))
1240 (lower+expand-object thing system
1241 #:target target
1242 #:output output)))
24ab804c 1243 (($ <gexp-input> (? self-quoting? x))
e39d1461 1244 (return x))
24ab804c
LC
1245 (($ <gexp-input> x)
1246 (raise (condition (&gexp-input-error (input x)))))
21b679f6
LC
1247 (x
1248 (return x)))))
1249
1250 (mlet %store-monad
b334674f
LC
1251 ((args (mapm %store-monad
1252 reference->sexp (gexp-references exp))))
21b679f6
LC
1253 (return (apply (gexp-proc exp) args))))
1254
8245bb74
LC
1255(define-syntax-rule (define-syntax-parameter-once name proc)
1256 ;; Like 'define-syntax-parameter' but ensure the top-level binding for NAME
1257 ;; does not get redefined. This works around a race condition in a
1258 ;; multi-threaded context with Guile <= 2.2.4: <https://bugs.gnu.org/27476>.
1259 (eval-when (load eval expand compile)
1260 (define name
1261 (if (module-locally-bound? (current-module) 'name)
1262 (module-ref (current-module) 'name)
1263 (make-syntax-transformer 'name 'syntax-parameter
1264 (list proc))))))
1265
1266(define-syntax-parameter-once current-imported-modules
0bb9929e
LC
1267 ;; Current list of imported modules.
1268 (identifier-syntax '()))
1269
1270(define-syntax-rule (with-imported-modules modules body ...)
1271 "Mark the gexps defined in BODY... as requiring MODULES in their execution
1272environment."
1273 (syntax-parameterize ((current-imported-modules
1274 (identifier-syntax modules)))
1275 body ...))
1276
8245bb74 1277(define-syntax-parameter-once current-imported-extensions
838e17d8
LC
1278 ;; Current list of extensions.
1279 (identifier-syntax '()))
1280
1281(define-syntax-rule (with-extensions extensions body ...)
1282 "Mark the gexps defined in BODY... as requiring EXTENSIONS in their
1283execution environment."
1284 (syntax-parameterize ((current-imported-extensions
1285 (identifier-syntax extensions)))
1286 body ...))
1287
21b679f6
LC
1288(define-syntax gexp
1289 (lambda (s)
1290 (define (collect-escapes exp)
1291 ;; Return all the 'ungexp' present in EXP.
1292 (let loop ((exp exp)
1293 (result '()))
607e1b51
LC
1294 (syntax-case exp (ungexp
1295 ungexp-splicing
1296 ungexp-native
1297 ungexp-native-splicing)
21b679f6
LC
1298 ((ungexp _)
1299 (cons exp result))
1300 ((ungexp _ _)
1301 (cons exp result))
1302 ((ungexp-splicing _ ...)
1303 (cons exp result))
607e1b51 1304 ((ungexp-native _ ...)
667b2508
LC
1305 (cons exp result))
1306 ((ungexp-native-splicing _ ...)
1307 (cons exp result))
5e2e4a51 1308 ((exp0 . exp)
667b2508 1309 (let ((result (loop #'exp0 result)))
5e2e4a51 1310 (loop #'exp result)))
667b2508
LC
1311 (_
1312 result))))
1313
21b679f6
LC
1314 (define (escape->ref exp)
1315 ;; Turn 'ungexp' form EXP into a "reference".
667b2508
LC
1316 (syntax-case exp (ungexp ungexp-splicing
1317 ungexp-native ungexp-native-splicing
1318 output)
21b679f6 1319 ((ungexp output)
1e87da58 1320 #'(gexp-output "out"))
21b679f6 1321 ((ungexp output name)
1e87da58 1322 #'(gexp-output name))
21b679f6 1323 ((ungexp thing)
0dbea56b 1324 #'(%gexp-input thing "out" #f))
21b679f6 1325 ((ungexp drv-or-pkg out)
0dbea56b 1326 #'(%gexp-input drv-or-pkg out #f))
21b679f6 1327 ((ungexp-splicing lst)
0dbea56b 1328 #'(%gexp-input lst "out" #f))
667b2508 1329 ((ungexp-native thing)
0dbea56b 1330 #'(%gexp-input thing "out" #t))
667b2508 1331 ((ungexp-native drv-or-pkg out)
0dbea56b 1332 #'(%gexp-input drv-or-pkg out #t))
667b2508 1333 ((ungexp-native-splicing lst)
0dbea56b 1334 #'(%gexp-input lst "out" #t))))
21b679f6 1335
667b2508
LC
1336 (define (substitute-ungexp exp substs)
1337 ;; Given EXP, an 'ungexp' or 'ungexp-native' form, substitute it with
1338 ;; the corresponding form in SUBSTS.
1339 (match (assoc exp substs)
1340 ((_ id)
1341 id)
4a6e889f
LC
1342 (_ ;internal error
1343 (with-syntax ((exp exp))
1344 #'(syntax-error "error: no 'ungexp' substitution" exp)))))
667b2508
LC
1345
1346 (define (substitute-ungexp-splicing exp substs)
1347 (syntax-case exp ()
1348 ((exp rest ...)
1349 (match (assoc #'exp substs)
1350 ((_ id)
1351 (with-syntax ((id id))
1352 #`(append id
1353 #,(substitute-references #'(rest ...) substs))))
1354 (_
1355 #'(syntax-error "error: no 'ungexp-splicing' substitution"
4a6e889f 1356 exp))))))
667b2508 1357
21b679f6
LC
1358 (define (substitute-references exp substs)
1359 ;; Return a variant of EXP where all the cars of SUBSTS have been
1360 ;; replaced by the corresponding cdr.
667b2508
LC
1361 (syntax-case exp (ungexp ungexp-native
1362 ungexp-splicing ungexp-native-splicing)
21b679f6 1363 ((ungexp _ ...)
667b2508
LC
1364 (substitute-ungexp exp substs))
1365 ((ungexp-native _ ...)
1366 (substitute-ungexp exp substs))
21b679f6 1367 (((ungexp-splicing _ ...) rest ...)
667b2508
LC
1368 (substitute-ungexp-splicing exp substs))
1369 (((ungexp-native-splicing _ ...) rest ...)
1370 (substitute-ungexp-splicing exp substs))
5e2e4a51 1371 ((exp0 . exp)
21b679f6 1372 #`(cons #,(substitute-references #'exp0 substs)
5e2e4a51 1373 #,(substitute-references #'exp substs)))
21b679f6
LC
1374 (x #''x)))
1375
1376 (syntax-case s (ungexp output)
1377 ((_ exp)
affd7761 1378 (let* ((escapes (delete-duplicates (collect-escapes #'exp)))
21b679f6
LC
1379 (formals (generate-temporaries escapes))
1380 (sexp (substitute-references #'exp (zip escapes formals)))
affd7761
LC
1381 (refs (map escape->ref escapes)))
1382 #`(make-gexp (list #,@refs)
0bb9929e 1383 current-imported-modules
838e17d8 1384 current-imported-extensions
21b679f6
LC
1385 (lambda #,formals
1386 #,sexp)))))))
1387
1388\f
aa72d9af
LC
1389;;;
1390;;; Module handling.
1391;;;
1392
df2d51f0
LC
1393(define %utils-module
1394 ;; This file provides 'mkdir-p', needed to implement 'imported-files' and
a9601e23
LC
1395 ;; other primitives below. Note: We give the file name relative to this
1396 ;; file you are currently reading; 'search-path' could return a file name
1397 ;; relative to the current working directory.
1398 (local-file "build/utils.scm"
df2d51f0 1399 "build-utils.scm"))
aa72d9af 1400
8df2eca6
LC
1401(define* (imported-files/derivation files
1402 #:key (name "file-import")
e529d468 1403 (symlink? #f)
8df2eca6 1404 (system (%current-system))
8afa18d6 1405 (guile (%guile-for-build)))
aa72d9af 1406 "Return a derivation that imports FILES into STORE. FILES must be a list
d938a58b
LC
1407of (FINAL-PATH . FILE) pairs. Each FILE is mapped to FINAL-PATH in the
1408resulting store path. FILE can be either a file name, or a file-like object,
e529d468
LC
1409as returned by 'local-file' for example. If SYMLINK? is true, create symlinks
1410to the source files instead of copying them."
aa72d9af
LC
1411 (define file-pair
1412 (match-lambda
d938a58b 1413 ((final-path . (? string? file-name))
aa72d9af
LC
1414 (mlet %store-monad ((file (interned-file file-name
1415 (basename final-path))))
d938a58b
LC
1416 (return (list final-path file))))
1417 ((final-path . file-like)
1418 (mlet %store-monad ((file (lower-object file-like system)))
aa72d9af
LC
1419 (return (list final-path file))))))
1420
b334674f 1421 (mlet %store-monad ((files (mapm %store-monad file-pair files)))
aa72d9af
LC
1422 (define build
1423 (gexp
1424 (begin
df2d51f0 1425 (primitive-load (ungexp %utils-module)) ;for 'mkdir-p'
aa72d9af
LC
1426 (use-modules (ice-9 match))
1427
aa72d9af
LC
1428 (mkdir (ungexp output)) (chdir (ungexp output))
1429 (for-each (match-lambda
1430 ((final-path store-path)
1431 (mkdir-p (dirname final-path))
e529d468
LC
1432 ((ungexp (if symlink? 'symlink 'copy-file))
1433 store-path final-path)))
aa72d9af
LC
1434 '(ungexp files)))))
1435
1436 ;; TODO: Pass FILES as an environment variable so that BUILD remains
1437 ;; exactly the same regardless of FILES: less disk space, and fewer
1438 ;; 'add-to-store' RPCs.
1439 (gexp->derivation name build
1440 #:system system
1441 #:guile-for-build guile
30d722c3
LC
1442 #:local-build? #t
1443
8afa18d6
LC
1444 ;; Avoid deprecation warnings about the use of the _IO*
1445 ;; constants in (guix build utils).
30d722c3 1446 #:env-vars
8afa18d6 1447 '(("GUILE_WARN_DEPRECATED" . "no")))))
aa72d9af 1448
8df2eca6
LC
1449(define* (imported-files files
1450 #:key (name "file-import")
8df2eca6
LC
1451 ;; The following parameters make sense when creating
1452 ;; an actual derivation.
1453 (system (%current-system))
8afa18d6 1454 (guile (%guile-for-build)))
8df2eca6
LC
1455 "Import FILES into the store and return the resulting derivation or store
1456file name (a derivation is created if and only if some elements of FILES are
1457file-like objects and not local file names.) FILES must be a list
1458of (FINAL-PATH . FILE) pairs. Each FILE is mapped to FINAL-PATH in the
1459resulting store path. FILE can be either a file name, or a file-like object,
1460as returned by 'local-file' for example."
8c7bebd6
LC
1461 (if (any (match-lambda
1462 ((_ . (? struct? source)) #t)
1463 (_ #f))
1464 files)
8df2eca6 1465 (imported-files/derivation files #:name name
e529d468 1466 #:symlink? derivation?
8afa18d6 1467 #:system system #:guile guile)
8df2eca6
LC
1468 (interned-file-tree `(,name directory
1469 ,@(file-mapping->tree files)))))
1470
aa72d9af
LC
1471(define* (imported-modules modules
1472 #:key (name "module-import")
1473 (system (%current-system))
1474 (guile (%guile-for-build))
8afa18d6 1475 (module-path %load-path))
aa72d9af 1476 "Return a derivation that contains the source files of MODULES, a list of
d938a58b
LC
1477module names such as `(ice-9 q)'. All of MODULES must be either names of
1478modules to be found in the MODULE-PATH search path, or a module name followed
1479by an arrow followed by a file-like object. For example:
1480
1481 (imported-modules `((guix build utils)
1482 (guix gcrypt)
1483 ((guix config) => ,(scheme-file …))))
1484
1485In this example, the first two modules are taken from MODULE-PATH, and the
1486last one is created from the given <scheme-file> object."
4d20d87b
LC
1487 (let ((files (map (match-lambda
1488 (((module ...) '=> file)
1489 (cons (module->source-file-name module)
1490 file))
1491 ((module ...)
1492 (let ((f (module->source-file-name module)))
1493 (cons f (search-path* module-path f)))))
1494 modules)))
8df2eca6 1495 (imported-files files #:name name
8df2eca6 1496 #:system system
8afa18d6 1497 #:guile guile)))
aa72d9af
LC
1498
1499(define* (compiled-modules modules
1500 #:key (name "module-import-compiled")
1501 (system (%current-system))
2cc5ec7f 1502 target
aa72d9af 1503 (guile (%guile-for-build))
a912c723 1504 (module-path %load-path)
838e17d8 1505 (extensions '())
3c6b9fb5 1506 (deprecation-warnings #f))
aa72d9af
LC
1507 "Return a derivation that builds a tree containing the `.go' files
1508corresponding to MODULES. All the MODULES are built in a context where
2cc5ec7f
LC
1509they can refer to each other. When TARGET is true, cross-compile MODULES for
1510TARGET, a GNU triplet."
d3292275
LC
1511 (define total (length modules))
1512
aa72d9af
LC
1513 (mlet %store-monad ((modules (imported-modules modules
1514 #:system system
1515 #:guile guile
1516 #:module-path
8afa18d6 1517 module-path)))
aa72d9af
LC
1518 (define build
1519 (gexp
1520 (begin
df2d51f0
LC
1521 (primitive-load (ungexp %utils-module)) ;for 'mkdir-p'
1522
aa72d9af 1523 (use-modules (ice-9 ftw)
d3292275
LC
1524 (ice-9 format)
1525 (srfi srfi-1)
aa72d9af 1526 (srfi srfi-26)
326dc630 1527 (system base target)
aa72d9af
LC
1528 (system base compile))
1529
aa72d9af
LC
1530 (define (regular? file)
1531 (not (member file '("." ".."))))
1532
d3292275 1533 (define (process-entry entry output processed)
e640c9e6
LC
1534 (if (file-is-directory? entry)
1535 (let ((output (string-append output "/" (basename entry))))
1536 (mkdir-p output)
d3292275 1537 (process-directory entry output processed))
e640c9e6
LC
1538 (let* ((base (basename entry ".scm"))
1539 (output (string-append output "/" base ".go")))
d3292275 1540 (format #t "[~2@a/~2@a] Compiling '~a'...~%"
3c6b9fb5
LC
1541 (+ 1 processed (ungexp total))
1542 (ungexp (* total 2))
a31174e8 1543 entry)
2cc5ec7f
LC
1544
1545 (ungexp-splicing
1546 (if target
1547 (gexp ((with-target (ungexp target)
1548 (lambda ()
1549 (compile-file entry
1550 #:output-file output
1551 #:opts
1552 %auto-compilation-options)))))
1553 (gexp ((compile-file entry
1554 #:output-file output
1555 #:opts %auto-compilation-options)))))
1556
d3292275 1557 (+ 1 processed))))
e640c9e6 1558
d3292275 1559 (define (process-directory directory output processed)
aa72d9af
LC
1560 (let ((entries (map (cut string-append directory "/" <>)
1561 (scandir directory regular?))))
d3292275
LC
1562 (fold (cut process-entry <> output <>)
1563 processed
1564 entries)))
1565
3c6b9fb5
LC
1566 (define* (load-from-directory directory
1567 #:optional (loaded 0))
1568 "Load all the source files found in DIRECTORY."
1569 ;; XXX: This works around <https://bugs.gnu.org/15602>.
1570 (let ((entries (map (cut string-append directory "/" <>)
1571 (scandir directory regular?))))
1572 (fold (lambda (file loaded)
1573 (if (file-is-directory? file)
1574 (load-from-directory file loaded)
1575 (begin
1576 (format #t "[~2@a/~2@a] Loading '~a'...~%"
1577 (+ 1 loaded) (ungexp (* 2 total))
1578 file)
1579 (save-module-excursion
1580 (lambda ()
1581 (primitive-load file)))
1582 (+ 1 loaded))))
1583 loaded
1584 entries)))
1585
d3292275
LC
1586 (setvbuf (current-output-port)
1587 (cond-expand (guile-2.2 'line) (else _IOLBF)))
aa72d9af 1588
4a42abc5
LC
1589 (define mkdir-p
1590 ;; Capture 'mkdir-p'.
1591 (@ (guix build utils) mkdir-p))
5d669883 1592
838e17d8 1593 ;; Add EXTENSIONS to the search path.
4a42abc5
LC
1594 (set! %load-path
1595 (append (map (lambda (extension)
1596 (string-append extension
1597 "/share/guile/site/"
1598 (effective-version)))
1599 '((ungexp-native-splicing extensions)))
1600 %load-path))
1601 (set! %load-compiled-path
1602 (append (map (lambda (extension)
1603 (string-append extension "/lib/guile/"
1604 (effective-version)
1605 "/site-ccache"))
1606 '((ungexp-native-splicing extensions)))
1607 %load-compiled-path))
838e17d8 1608
aa72d9af 1609 (set! %load-path (cons (ungexp modules) %load-path))
5d669883 1610
4a42abc5
LC
1611 ;; Above we loaded our own (guix build utils) but now we may need to
1612 ;; load a compile a different one. Thus, force a reload.
1613 (let ((utils (string-append (ungexp modules)
1614 "/guix/build/utils.scm")))
1615 (when (file-exists? utils)
1616 (load utils)))
5d669883 1617
aa72d9af
LC
1618 (mkdir (ungexp output))
1619 (chdir (ungexp modules))
a31174e8 1620
3c6b9fb5 1621 (load-from-directory ".")
d3292275 1622 (process-directory "." (ungexp output) 0))))
aa72d9af
LC
1623
1624 ;; TODO: Pass MODULES as an environment variable.
1625 (gexp->derivation name build
1626 #:system system
1627 #:guile-for-build guile
a912c723
LC
1628 #:local-build? #t
1629 #:env-vars
1630 (case deprecation-warnings
1631 ((#f)
1632 '(("GUILE_WARN_DEPRECATED" . "no")))
1633 ((detailed)
1634 '(("GUILE_WARN_DEPRECATED" . "detailed")))
1635 (else
1636 '())))))
aa72d9af
LC
1637
1638\f
21b679f6
LC
1639;;;
1640;;; Convenience procedures.
1641;;;
1642
53e89b17 1643(define (default-guile)
b6bee63b 1644 ;; Lazily resolve 'guile-3.0' (not 'guile-final' because this is for
6ee797f3
LC
1645 ;; programs returned by 'program-file' and we don't want to keep references
1646 ;; to several Guile packages). This module must not refer to (gnu …)
53e89b17 1647 ;; modules directly, to avoid circular dependencies, hence this hack.
6ee797f3 1648 (module-ref (resolve-interface '(gnu packages guile))
b6bee63b 1649 'guile-3.0))
53e89b17 1650
838e17d8 1651(define* (load-path-expression modules #:optional (path %load-path)
2e8cabb8 1652 #:key (extensions '()) system target)
dd8d1a30 1653 "Return as a monadic value a gexp that sets '%load-path' and
1ae16033 1654'%load-compiled-path' to point to MODULES, a list of module names. MODULES
efff3245
LC
1655are searched for in PATH. Return #f when MODULES and EXTENSIONS are empty."
1656 (if (and (null? modules) (null? extensions))
1657 (with-monad %store-monad
1658 (return #f))
1659 (mlet %store-monad ((modules (imported-modules modules
2e8cabb8
LC
1660 #:module-path path
1661 #:system system))
efff3245
LC
1662 (compiled (compiled-modules modules
1663 #:extensions extensions
2e8cabb8
LC
1664 #:module-path path
1665 #:system system
1666 #:target target)))
cdf9811d
LC
1667 (return
1668 (gexp (eval-when (expand load eval)
1669 ;; Augment the load paths and delete duplicates. Do that
1670 ;; without loading (srfi srfi-1) or anything.
396b05f0 1671 (let ((extensions '((ungexp-splicing extensions)))
cdf9811d
LC
1672 (prepend (lambda (items lst)
1673 ;; This is O(N²) but N is typically small.
1674 (let loop ((items items)
1675 (lst lst))
1676 (if (null? items)
1677 lst
1678 (loop (cdr items)
1679 (cons (car items)
1680 (delete (car items) lst))))))))
1681 (set! %load-path
1682 (prepend (cons (ungexp modules)
1683 (map (lambda (extension)
1684 (string-append extension
1685 "/share/guile/site/"
1686 (effective-version)))
1687 extensions))
1688 %load-path))
1689 (set! %load-compiled-path
1690 (prepend (cons (ungexp compiled)
1691 (map (lambda (extension)
1692 (string-append extension
1693 "/lib/guile/"
1694 (effective-version)
1695 "/site-ccache"))
1696 extensions))
1697 %load-compiled-path)))))))))
dd8d1a30 1698
21b679f6 1699(define* (gexp->script name exp
1ae16033 1700 #:key (guile (default-guile))
2e8cabb8
LC
1701 (module-path %load-path)
1702 (system (%current-system))
a6bf7a97 1703 (target 'current))
9c14a487 1704 "Return an executable script NAME that runs EXP using GUILE, with EXP's
1ae16033 1705imported modules in its search path. Look up EXP's modules in MODULE-PATH."
a6bf7a97
MO
1706 (mlet* %store-monad ((target (if (eq? target 'current)
1707 (current-target-system)
1708 (return target)))
1709 (set-load-path
1710 (load-path-expression (gexp-modules exp)
1711 module-path
1712 #:extensions
1713 (gexp-extensions exp)
1714 #:system system
1715 #:target target)))
21b679f6
LC
1716 (gexp->derivation name
1717 (gexp
1718 (call-with-output-file (ungexp output)
1719 (lambda (port)
c17b5ab4
LC
1720 ;; Note: that makes a long shebang. When the store
1721 ;; is /gnu/store, that fits within the 128-byte
1722 ;; limit imposed by Linux, but that may go beyond
1723 ;; when running tests.
21b679f6
LC
1724 (format port
1725 "#!~a/bin/guile --no-auto-compile~%!#~%"
1726 (ungexp guile))
4a4cbd0b 1727
efff3245
LC
1728 (ungexp-splicing
1729 (if set-load-path
1730 (gexp ((write '(ungexp set-load-path) port)))
1731 (gexp ())))
1732
21b679f6 1733 (write '(ungexp exp) port)
1ae16033 1734 (chmod port #o555))))
2e8cabb8
LC
1735 #:system system
1736 #:target target
52207b39
LC
1737 #:module-path module-path
1738
1739 ;; These derivations are not worth offloading or
1740 ;; substituting.
1741 #:local-build? #t
1742 #:substitutable? #f)))
21b679f6 1743
1ae16033
LC
1744(define* (gexp->file name exp #:key
1745 (set-load-path? #t)
4fbd1a2b 1746 (module-path %load-path)
3cd1444d
MO
1747 (splice? #f)
1748 (system (%current-system))
a6bf7a97 1749 (target 'current))
4fbd1a2b
LC
1750 "Return a derivation that builds a file NAME containing EXP. When SPLICE?
1751is true, EXP is considered to be a list of expressions that will be spliced in
1752the resulting file.
1753
1754When SET-LOAD-PATH? is true, emit code in the resulting file to set
1755'%load-path' and '%load-compiled-path' to honor EXP's imported modules.
1756Lookup EXP's modules in MODULE-PATH."
838e17d8
LC
1757 (define modules (gexp-modules exp))
1758 (define extensions (gexp-extensions exp))
1759
a6bf7a97
MO
1760 (mlet* %store-monad
1761 ((target (if (eq? target 'current)
1762 (current-target-system)
1763 (return target)))
1764 (no-load-path? -> (or (not set-load-path?)
1765 (and (null? modules)
1766 (null? extensions))))
1767 (set-load-path
1768 (load-path-expression modules module-path
1769 #:extensions extensions
1770 #:system system
1771 #:target target)))
1772 (if no-load-path?
1773 (gexp->derivation name
1774 (gexp
1775 (call-with-output-file (ungexp output)
1776 (lambda (port)
1777 (for-each
1778 (lambda (exp)
1779 (write exp port))
1780 '(ungexp (if splice?
1781 exp
1782 (gexp ((ungexp exp)))))))))
1783 #:local-build? #t
1784 #:substitutable? #f
1785 #:system system
1786 #:target target)
838e17d8
LC
1787 (gexp->derivation name
1788 (gexp
1789 (call-with-output-file (ungexp output)
1790 (lambda (port)
1791 (write '(ungexp set-load-path) port)
a6bf7a97
MO
1792 (for-each
1793 (lambda (exp)
1794 (write exp port))
1795 '(ungexp (if splice?
1796 exp
1797 (gexp ((ungexp exp)))))))))
838e17d8
LC
1798 #:module-path module-path
1799 #:local-build? #t
3cd1444d
MO
1800 #:substitutable? #f
1801 #:system system
1802 #:target target))))
21b679f6 1803
462a3fa3
LC
1804(define* (text-file* name #:rest text)
1805 "Return as a monadic value a derivation that builds a text file containing
d9ae938f
LC
1806all of TEXT. TEXT may list, in addition to strings, objects of any type that
1807can be used in a gexp: packages, derivations, local file objects, etc. The
1808resulting store file holds references to all these."
462a3fa3
LC
1809 (define builder
1810 (gexp (call-with-output-file (ungexp output "out")
1811 (lambda (port)
1812 (display (string-append (ungexp-splicing text)) port)))))
1813
851b6f62
LC
1814 (gexp->derivation name builder
1815 #:local-build? #t
1816 #:substitutable? #f))
462a3fa3 1817
b751cde3
LC
1818(define* (mixed-text-file name #:rest text)
1819 "Return an object representing store file NAME containing TEXT. TEXT is a
1820sequence of strings and file-like objects, as in:
1821
1822 (mixed-text-file \"profile\"
1823 \"export PATH=\" coreutils \"/bin:\" grep \"/bin\")
1824
1825This is the declarative counterpart of 'text-file*'."
1826 (define build
1827 (gexp (call-with-output-file (ungexp output "out")
1828 (lambda (port)
1829 (display (string-append (ungexp-splicing text)) port)))))
1830
1831 (computed-file name build))
1832
dedb512f
LC
1833(define (file-union name files)
1834 "Return a <computed-file> that builds a directory containing all of FILES.
1835Each item in FILES must be a two-element list where the first element is the
1836file name to use in the new directory, and the second element is a gexp
1837denoting the target file. Here's an example:
1838
1839 (file-union \"etc\"
1840 `((\"hosts\" ,(plain-file \"hosts\"
1841 \"127.0.0.1 localhost\"))
1842 (\"bashrc\" ,(plain-file \"bashrc\"
5dec93bb
LC
1843 \"alias ls='ls --color'\"))
1844 (\"libvirt/qemu.conf\" ,(plain-file \"qemu.conf\" \"\"))))
dedb512f
LC
1845
1846This yields an 'etc' directory containing these two files."
1847 (computed-file name
5dec93bb
LC
1848 (with-imported-modules '((guix build utils))
1849 (gexp
1850 (begin
1851 (use-modules (guix build utils))
1852
1853 (mkdir (ungexp output))
1854 (chdir (ungexp output))
1855 (ungexp-splicing
1856 (map (match-lambda
1857 ((target source)
1858 (gexp
1859 (begin
1860 ;; Stat the source to abort early if it does
1861 ;; not exist.
1862 (stat (ungexp source))
1863
1864 (mkdir-p (dirname (ungexp target)))
1865 (symlink (ungexp source)
1866 (ungexp target))))))
1867 files)))))))
dedb512f 1868
59523429 1869(define* (directory-union name things
b244ae25
LC
1870 #:key (copy? #f) (quiet? #f)
1871 (resolve-collision 'warn-about-collision))
d298c815
LC
1872 "Return a directory that is the union of THINGS, where THINGS is a list of
1873file-like objects denoting directories. For example:
1874
1875 (directory-union \"guile+emacs\" (list guile emacs))
1876
59523429
LC
1877yields a directory that is the union of the 'guile' and 'emacs' packages.
1878
b244ae25
LC
1879Call RESOLVE-COLLISION when several files collide, passing it the list of
1880colliding files. RESOLVE-COLLISION must return the chosen file or #f, in
1881which case the colliding entry is skipped altogether.
1882
de98b302
LC
1883When HARD-LINKS? is true, create hard links instead of symlinks. When QUIET?
1884is true, the derivation will not print anything."
59523429
LC
1885 (define symlink
1886 (if copy?
1887 (gexp (lambda (old new)
1888 (if (file-is-directory? old)
1889 (symlink old new)
1890 (copy-file old new))))
1891 (gexp symlink)))
1892
de98b302
LC
1893 (define log-port
1894 (if quiet?
1895 (gexp (%make-void-port "w"))
1896 (gexp (current-error-port))))
1897
d298c815
LC
1898 (match things
1899 ((one)
1900 ;; Only one thing; return it.
1901 one)
1902 (_
1903 (computed-file name
1904 (with-imported-modules '((guix build union))
1905 (gexp (begin
b244ae25
LC
1906 (use-modules (guix build union)
1907 (srfi srfi-1)) ;for 'first' and 'last'
1908
d298c815 1909 (union-build (ungexp output)
59523429
LC
1910 '(ungexp things)
1911
de98b302 1912 #:log-port (ungexp log-port)
b244ae25
LC
1913 #:symlink (ungexp symlink)
1914 #:resolve-collision
1915 (ungexp resolve-collision)))))))))
d298c815 1916
21b679f6
LC
1917\f
1918;;;
1919;;; Syntactic sugar.
1920;;;
1921
1922(eval-when (expand load eval)
667b2508
LC
1923 (define* (read-ungexp chr port #:optional native?)
1924 "Read an 'ungexp' or 'ungexp-splicing' form from PORT. When NATIVE? is
1925true, use 'ungexp-native' and 'ungexp-native-splicing' instead."
21b679f6
LC
1926 (define unquote-symbol
1927 (match (peek-char port)
1928 (#\@
1929 (read-char port)
667b2508
LC
1930 (if native?
1931 'ungexp-native-splicing
1932 'ungexp-splicing))
21b679f6 1933 (_
667b2508
LC
1934 (if native?
1935 'ungexp-native
1936 'ungexp))))
21b679f6
LC
1937
1938 (match (read port)
1939 ((? symbol? symbol)
1940 (let ((str (symbol->string symbol)))
1941 (match (string-index-right str #\:)
1942 (#f
1943 `(,unquote-symbol ,symbol))
1944 (colon
1945 (let ((name (string->symbol (substring str 0 colon)))
1946 (output (substring str (+ colon 1))))
1947 `(,unquote-symbol ,name ,output))))))
1948 (x
1949 `(,unquote-symbol ,x))))
1950
1951 (define (read-gexp chr port)
1952 "Read a 'gexp' form from PORT."
1953 `(gexp ,(read port)))
1954
1955 ;; Extend the reader
1956 (read-hash-extend #\~ read-gexp)
667b2508
LC
1957 (read-hash-extend #\$ read-ungexp)
1958 (read-hash-extend #\+ (cut read-ungexp <> <> #t)))
21b679f6
LC
1959
1960;;; gexp.scm ends here