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