pack: Adjust test to expect relative symlinks.
[jackhill/guix/guix.git] / guix / gexp.scm
CommitLineData
21b679f6 1;;; GNU Guix --- Functional package management for GNU
1ae16033 2;;; Copyright © 2014, 2015, 2016, 2017, 2018 Ludovic Courtès <ludo@gnu.org>
bdcf0e6f 3;;; Copyright © 2018 Clément Lassieur <clement@lassieur.org>
21b679f6
LC
4;;;
5;;; This file is part of GNU Guix.
6;;;
7;;; GNU Guix is free software; you can redistribute it and/or modify it
8;;; under the terms of the GNU General Public License as published by
9;;; the Free Software Foundation; either version 3 of the License, or (at
10;;; your option) any later version.
11;;;
12;;; GNU Guix is distributed in the hope that it will be useful, but
13;;; WITHOUT ANY WARRANTY; without even the implied warranty of
14;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15;;; GNU General Public License for more details.
16;;;
17;;; You should have received a copy of the GNU General Public License
18;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
19
20(define-module (guix gexp)
e87f0591 21 #:use-module (guix store)
21b679f6 22 #:use-module (guix monads)
e87f0591 23 #:use-module (guix derivations)
7adf9b84 24 #:use-module (guix grafts)
aa72d9af 25 #:use-module (guix utils)
21b679f6
LC
26 #:use-module (srfi srfi-1)
27 #:use-module (srfi srfi-9)
7560b00b 28 #:use-module (srfi srfi-9 gnu)
21b679f6 29 #:use-module (srfi srfi-26)
3e43166f
LC
30 #:use-module (srfi srfi-34)
31 #:use-module (srfi srfi-35)
21b679f6
LC
32 #:use-module (ice-9 match)
33 #:export (gexp
34 gexp?
0bb9929e 35 with-imported-modules
0dbea56b
LC
36
37 gexp-input
38 gexp-input?
558e8b11 39
d9ae938f
LC
40 local-file
41 local-file?
74d441ab 42 local-file-file
9d3994f7 43 local-file-absolute-file-name
74d441ab
LC
44 local-file-name
45 local-file-recursive?
0dbea56b 46
558e8b11
LC
47 plain-file
48 plain-file?
49 plain-file-name
50 plain-file-content
51
91937029
LC
52 computed-file
53 computed-file?
54 computed-file-name
55 computed-file-gexp
91937029
LC
56 computed-file-options
57
15a01c72
LC
58 program-file
59 program-file?
60 program-file-name
61 program-file-gexp
15a01c72 62 program-file-guile
427ec19e 63 program-file-module-path
15a01c72 64
e1c153e0
LC
65 scheme-file
66 scheme-file?
67 scheme-file-name
68 scheme-file-gexp
69
a9e5e92f
LC
70 file-append
71 file-append?
72 file-append-base
73 file-append-suffix
74
64fc9f65
RJ
75 load-path-expression
76 gexp-modules
77
21b679f6
LC
78 gexp->derivation
79 gexp->file
462a3fa3 80 gexp->script
aa72d9af 81 text-file*
b751cde3 82 mixed-text-file
dedb512f 83 file-union
d298c815 84 directory-union
aa72d9af
LC
85 imported-files
86 imported-modules
ff40e9b7
LC
87 compiled-modules
88
89 define-gexp-compiler
6b6298ae 90 gexp-compiler?
bdcf0e6f 91 file-like?
c2b84676 92 lower-object
6b6298ae 93
3e43166f
LC
94 lower-inputs
95
96 &gexp-error
97 gexp-error?
98 &gexp-input-error
99 gexp-input-error?
100 gexp-error-invalid-input))
21b679f6
LC
101
102;;; Commentary:
103;;;
104;;; This module implements "G-expressions", or "gexps". Gexps are like
105;;; S-expressions (sexps), with two differences:
106;;;
107;;; 1. References (un-quotations) to derivations or packages in a gexp are
667b2508
LC
108;;; replaced by the corresponding output file name; in addition, the
109;;; 'ungexp-native' unquote-like form allows code to explicitly refer to
110;;; the native code of a given package, in case of cross-compilation;
21b679f6
LC
111;;;
112;;; 2. Gexps embed information about the derivations they refer to.
113;;;
114;;; Gexps make it easy to write to files Scheme code that refers to store
115;;; items, or to write Scheme code to build derivations.
116;;;
117;;; Code:
118
119;; "G expressions".
120(define-record-type <gexp>
0bb9929e 121 (make-gexp references modules proc)
21b679f6 122 gexp?
affd7761 123 (references gexp-references) ;list of <gexp-input>
0bb9929e 124 (modules gexp-self-modules) ;list of module names
affd7761 125 (proc gexp-proc)) ;procedure
21b679f6 126
7560b00b
LC
127(define (write-gexp gexp port)
128 "Write GEXP on PORT."
129 (display "#<gexp " port)
2cf0ea0d
LC
130
131 ;; Try to write the underlying sexp. Now, this trick doesn't work when
132 ;; doing things like (ungexp-splicing (gexp ())) because GEXP's procedure
133 ;; tries to use 'append' on that, which fails with wrong-type-arg.
134 (false-if-exception
667b2508 135 (write (apply (gexp-proc gexp)
affd7761 136 (gexp-references gexp))
667b2508 137 port))
7560b00b
LC
138 (format port " ~a>"
139 (number->string (object-address gexp) 16)))
140
141(set-record-type-printer! <gexp> write-gexp)
142
bcb13287
LC
143\f
144;;;
145;;; Methods.
146;;;
147
148;; Compiler for a type of objects that may be introduced in a gexp.
149(define-record-type <gexp-compiler>
1cdecf24 150 (gexp-compiler type lower expand)
bcb13287 151 gexp-compiler?
1cdecf24 152 (type gexp-compiler-type) ;record type descriptor
ebdfd776 153 (lower gexp-compiler-lower)
1cdecf24 154 (expand gexp-compiler-expand)) ;#f | DRV -> sexp
bcb13287 155
3e43166f
LC
156(define-condition-type &gexp-error &error
157 gexp-error?)
158
159(define-condition-type &gexp-input-error &gexp-error
160 gexp-input-error?
161 (input gexp-error-invalid-input))
162
163
bcb13287 164(define %gexp-compilers
1cdecf24
LC
165 ;; 'eq?' mapping of record type descriptor to <gexp-compiler>.
166 (make-hash-table 20))
bcb13287 167
ebdfd776
LC
168(define (default-expander thing obj output)
169 "This is the default expander for \"things\" that appear in gexps. It
170returns its output file name of OBJ's OUTPUT."
171 (match obj
172 ((? derivation? drv)
173 (derivation->output-path drv output))
174 ((? string? file)
175 file)))
176
bcb13287
LC
177(define (register-compiler! compiler)
178 "Register COMPILER as a gexp compiler."
1cdecf24
LC
179 (hashq-set! %gexp-compilers
180 (gexp-compiler-type compiler) compiler))
bcb13287
LC
181
182(define (lookup-compiler object)
ebdfd776 183 "Search for a compiler for OBJECT. Upon success, return the three argument
bcb13287 184procedure to lower it; otherwise return #f."
1cdecf24
LC
185 (and=> (hashq-ref %gexp-compilers (struct-vtable object))
186 gexp-compiler-lower))
bcb13287 187
bdcf0e6f
CL
188(define (file-like? object)
189 "Return #t if OBJECT leads to a file in the store once unquoted in a
190G-expression; otherwise return #f."
191 (and (struct? object) (->bool (lookup-compiler object))))
192
ebdfd776
LC
193(define (lookup-expander object)
194 "Search for an expander for OBJECT. Upon success, return the three argument
195procedure to expand it; otherwise return #f."
1cdecf24
LC
196 (and=> (hashq-ref %gexp-compilers (struct-vtable object))
197 gexp-compiler-expand))
ebdfd776 198
c2b84676
LC
199(define* (lower-object obj
200 #:optional (system (%current-system))
201 #:key target)
202 "Return as a value in %STORE-MONAD the derivation or store item
203corresponding to OBJ for SYSTEM, cross-compiling for TARGET if TARGET is true.
204OBJ must be an object that has an associated gexp compiler, such as a
205<package>."
3e43166f
LC
206 (match (lookup-compiler obj)
207 (#f
208 (raise (condition (&gexp-input-error (input obj)))))
209 (lower
210 (lower obj system target))))
c2b84676 211
ebdfd776
LC
212(define-syntax define-gexp-compiler
213 (syntax-rules (=> compiler expander)
214 "Define NAME as a compiler for objects matching PREDICATE encountered in
215gexps.
216
217In the simplest form of the macro, BODY must return a derivation for PARAM, an
218object that matches PREDICATE, for SYSTEM and TARGET (the latter of which is
219#f except when cross-compiling.)
220
221The more elaborate form allows you to specify an expander:
222
223 (define-gexp-compiler something something?
224 compiler => (lambda (param system target) ...)
225 expander => (lambda (param drv output) ...))
226
227The expander specifies how an object is converted to its sexp representation."
1cdecf24
LC
228 ((_ (name (param record-type) system target) body ...)
229 (define-gexp-compiler name record-type
ebdfd776
LC
230 compiler => (lambda (param system target) body ...)
231 expander => default-expander))
1cdecf24 232 ((_ name record-type
ebdfd776
LC
233 compiler => compile
234 expander => expand)
235 (begin
236 (define name
1cdecf24 237 (gexp-compiler record-type compile expand))
ebdfd776 238 (register-compiler! name)))))
bcb13287 239
1cdecf24 240(define-gexp-compiler (derivation-compiler (drv <derivation>) system target)
2924f0d6
LC
241 ;; Derivations are the lowest-level representation, so this is the identity
242 ;; compiler.
243 (with-monad %store-monad
244 (return drv)))
245
bcb13287 246\f
d9ae938f 247;;;
558e8b11 248;;; File declarations.
d9ae938f
LC
249;;;
250
9d3994f7
LC
251;; A local file name. FILE is the file name the user entered, which can be a
252;; relative file name, and ABSOLUTE is a promise that computes its canonical
253;; absolute file name. We keep it in a promise to compute it lazily and avoid
254;; repeated 'stat' calls.
d9ae938f 255(define-record-type <local-file>
0687fc9c 256 (%%local-file file absolute name recursive? select?)
d9ae938f
LC
257 local-file?
258 (file local-file-file) ;string
9d3994f7 259 (absolute %local-file-absolute-file-name) ;promise string
d9ae938f 260 (name local-file-name) ;string
0687fc9c
LC
261 (recursive? local-file-recursive?) ;Boolean
262 (select? local-file-select?)) ;string stat -> Boolean
263
264(define (true file stat) #t)
d9ae938f 265
9d3994f7 266(define* (%local-file file promise #:optional (name (basename file))
0687fc9c 267 #:key recursive? (select? true))
9d3994f7
LC
268 ;; This intermediate procedure is part of our ABI, but the underlying
269 ;; %%LOCAL-FILE is not.
0687fc9c 270 (%%local-file file promise name recursive? select?))
9d3994f7 271
9d3994f7
LC
272(define (absolute-file-name file directory)
273 "Return the canonical absolute file name for FILE, which lives in the
274vicinity of DIRECTORY."
275 (canonicalize-path
276 (cond ((string-prefix? "/" file) file)
277 ((not directory) file)
278 ((string-prefix? "/" directory)
279 (string-append directory "/" file))
280 (else file))))
281
302d46e6
LC
282(define-syntax local-file
283 (lambda (s)
284 "Return an object representing local file FILE to add to the store; this
9d3994f7
LC
285object can be used in a gexp. If FILE is a relative file name, it is looked
286up relative to the source file where this form appears. FILE will be added to
287the store under NAME--by default the base name of FILE.
d9ae938f
LC
288
289When RECURSIVE? is true, the contents of FILE are added recursively; if FILE
290designates a flat file and RECURSIVE? is true, its contents are added, and its
291permission bits are kept.
292
0687fc9c
LC
293When RECURSIVE? is true, call (SELECT? FILE STAT) for each directory entry,
294where FILE is the entry's absolute file name and STAT is the result of
295'lstat'; exclude entries for which SELECT? does not return true.
296
302d46e6
LC
297This is the declarative counterpart of the 'interned-file' monadic procedure.
298It is implemented as a macro to capture the current source directory where it
299appears."
300 (syntax-case s ()
301 ((_ file rest ...)
302 #'(%local-file file
303 (delay (absolute-file-name file (current-source-directory)))
304 rest ...))
305 ((_)
306 #'(syntax-error "missing file name"))
307 (id
308 (identifier? #'id)
309 ;; XXX: We could return #'(lambda (file . rest) ...). However,
310 ;; (syntax-source #'id) is #f so (current-source-directory) would not
311 ;; work. Thus, simply forbid this form.
312 #'(syntax-error
313 "'local-file' is a macro and cannot be used like this")))))
9d3994f7
LC
314
315(define (local-file-absolute-file-name file)
316 "Return the absolute file name for FILE, a <local-file> instance. A
317'system-error' exception is raised if FILE could not be found."
318 (force (%local-file-absolute-file-name file)))
d9ae938f 319
1cdecf24 320(define-gexp-compiler (local-file-compiler (file <local-file>) system target)
d9ae938f
LC
321 ;; "Compile" FILE by adding it to the store.
322 (match file
0687fc9c 323 (($ <local-file> file (= force absolute) name recursive? select?)
9d3994f7
LC
324 ;; Canonicalize FILE so that if it's a symlink, it is resolved. Failing
325 ;; to do that, when RECURSIVE? is #t, we could end up creating a dangling
326 ;; symlink in the store, and when RECURSIVE? is #f 'add-to-store' would
327 ;; just throw an error, both of which are inconvenient.
0687fc9c
LC
328 (interned-file absolute name
329 #:recursive? recursive? #:select? select?))))
d9ae938f 330
558e8b11
LC
331(define-record-type <plain-file>
332 (%plain-file name content references)
333 plain-file?
334 (name plain-file-name) ;string
335 (content plain-file-content) ;string
336 (references plain-file-references)) ;list (currently unused)
337
338(define (plain-file name content)
339 "Return an object representing a text file called NAME with the given
340CONTENT (a string) to be added to the store.
341
342This is the declarative counterpart of 'text-file'."
343 ;; XXX: For now just ignore 'references' because it's not clear how to use
344 ;; them in a declarative context.
345 (%plain-file name content '()))
346
1cdecf24 347(define-gexp-compiler (plain-file-compiler (file <plain-file>) system target)
558e8b11
LC
348 ;; "Compile" FILE by adding it to the store.
349 (match file
350 (($ <plain-file> name content references)
351 (text-file name content references))))
352
91937029 353(define-record-type <computed-file>
ab25eb7c 354 (%computed-file name gexp guile options)
91937029
LC
355 computed-file?
356 (name computed-file-name) ;string
357 (gexp computed-file-gexp) ;gexp
ab25eb7c 358 (guile computed-file-guile) ;<package>
91937029
LC
359 (options computed-file-options)) ;list of arguments
360
361(define* (computed-file name gexp
ab25eb7c 362 #:key guile (options '(#:local-build? #t)))
91937029 363 "Return an object representing the store item NAME, a file or directory
a769bffb 364computed by GEXP. OPTIONS is a list of additional arguments to pass
91937029
LC
365to 'gexp->derivation'.
366
367This is the declarative counterpart of 'gexp->derivation'."
ab25eb7c 368 (%computed-file name gexp guile options))
91937029 369
1cdecf24 370(define-gexp-compiler (computed-file-compiler (file <computed-file>)
91937029
LC
371 system target)
372 ;; Compile FILE by returning a derivation whose build expression is its
373 ;; gexp.
374 (match file
ab25eb7c
LC
375 (($ <computed-file> name gexp guile options)
376 (if guile
377 (mlet %store-monad ((guile (lower-object guile system
378 #:target target)))
379 (apply gexp->derivation name gexp #:guile-for-build guile
380 options))
381 (apply gexp->derivation name gexp options)))))
91937029 382
15a01c72 383(define-record-type <program-file>
427ec19e 384 (%program-file name gexp guile path)
15a01c72
LC
385 program-file?
386 (name program-file-name) ;string
387 (gexp program-file-gexp) ;gexp
427ec19e
LC
388 (guile program-file-guile) ;package
389 (path program-file-module-path)) ;list of strings
15a01c72 390
427ec19e 391(define* (program-file name gexp #:key (guile #f) (module-path %load-path))
15a01c72 392 "Return an object representing the executable store item NAME that runs
427ec19e
LC
393GEXP. GUILE is the Guile package used to execute that script. Imported
394modules of GEXP are looked up in MODULE-PATH.
15a01c72
LC
395
396This is the declarative counterpart of 'gexp->script'."
427ec19e 397 (%program-file name gexp guile module-path))
15a01c72 398
1cdecf24 399(define-gexp-compiler (program-file-compiler (file <program-file>)
15a01c72
LC
400 system target)
401 ;; Compile FILE by returning a derivation that builds the script.
402 (match file
427ec19e 403 (($ <program-file> name gexp guile module-path)
15a01c72 404 (gexp->script name gexp
427ec19e 405 #:module-path module-path
15a01c72
LC
406 #:guile (or guile (default-guile))))))
407
e1c153e0 408(define-record-type <scheme-file>
4fbd1a2b 409 (%scheme-file name gexp splice?)
e1c153e0
LC
410 scheme-file?
411 (name scheme-file-name) ;string
4fbd1a2b
LC
412 (gexp scheme-file-gexp) ;gexp
413 (splice? scheme-file-splice?)) ;Boolean
e1c153e0 414
4fbd1a2b 415(define* (scheme-file name gexp #:key splice?)
e1c153e0
LC
416 "Return an object representing the Scheme file NAME that contains GEXP.
417
418This is the declarative counterpart of 'gexp->file'."
4fbd1a2b 419 (%scheme-file name gexp splice?))
e1c153e0 420
1cdecf24 421(define-gexp-compiler (scheme-file-compiler (file <scheme-file>)
e1c153e0
LC
422 system target)
423 ;; Compile FILE by returning a derivation that builds the file.
424 (match file
4fbd1a2b
LC
425 (($ <scheme-file> name gexp splice?)
426 (gexp->file name gexp #:splice? splice?))))
e1c153e0 427
a9e5e92f
LC
428;; Appending SUFFIX to BASE's output file name.
429(define-record-type <file-append>
430 (%file-append base suffix)
431 file-append?
432 (base file-append-base) ;<package> | <derivation> | ...
433 (suffix file-append-suffix)) ;list of strings
434
435(define (file-append base . suffix)
436 "Return a <file-append> object that expands to the concatenation of BASE and
437SUFFIX."
438 (%file-append base suffix))
439
1cdecf24 440(define-gexp-compiler file-append-compiler <file-append>
a9e5e92f
LC
441 compiler => (lambda (obj system target)
442 (match obj
443 (($ <file-append> base _)
444 (lower-object base system #:target target))))
445 expander => (lambda (obj lowered output)
446 (match obj
447 (($ <file-append> base suffix)
448 (let* ((expand (lookup-expander base))
449 (base (expand base lowered output)))
450 (string-append base (string-concatenate suffix)))))))
451
d9ae938f 452\f
bcb13287
LC
453;;;
454;;; Inputs & outputs.
455;;;
456
e39d1461
LC
457;; The input of a gexp.
458(define-record-type <gexp-input>
0dbea56b 459 (%gexp-input thing output native?)
e39d1461
LC
460 gexp-input?
461 (thing gexp-input-thing) ;<package> | <origin> | <derivation> | ...
462 (output gexp-input-output) ;string
463 (native? gexp-input-native?)) ;Boolean
464
f7328634
LC
465(define (write-gexp-input input port)
466 (match input
467 (($ <gexp-input> thing output #f)
468 (format port "#<gexp-input ~s:~a>" thing output))
469 (($ <gexp-input> thing output #t)
470 (format port "#<gexp-input native ~s:~a>" thing output))))
471
472(set-record-type-printer! <gexp-input> write-gexp-input)
473
0dbea56b
LC
474(define* (gexp-input thing ;convenience procedure
475 #:optional (output "out")
476 #:key native?)
477 "Return a new <gexp-input> for the OUTPUT of THING; NATIVE? determines
478whether this should be considered a \"native\" input or not."
479 (%gexp-input thing output native?))
480
21b679f6
LC
481;; Reference to one of the derivation's outputs, for gexps used in
482;; derivations.
1e87da58
LC
483(define-record-type <gexp-output>
484 (gexp-output name)
485 gexp-output?
486 (name gexp-output-name))
21b679f6 487
f7328634
LC
488(define (write-gexp-output output port)
489 (match output
490 (($ <gexp-output> name)
491 (format port "#<gexp-output ~a>" name))))
492
493(set-record-type-printer! <gexp-output> write-gexp-output)
494
0bb9929e 495(define (gexp-modules gexp)
2363bdd7
LC
496 "Return the list of Guile module names GEXP relies on. If (gexp? GEXP) is
497false, meaning that GEXP is a plain Scheme object, return the empty list."
498 (if (gexp? gexp)
499 (delete-duplicates
500 (append (gexp-self-modules gexp)
501 (append-map (match-lambda
502 (($ <gexp-input> (? gexp? exp))
503 (gexp-modules exp))
504 (($ <gexp-input> (lst ...))
505 (append-map (lambda (item)
506 (if (gexp? item)
507 (gexp-modules item)
508 '()))
509 lst))
510 (_
511 '()))
512 (gexp-references gexp))))
513 '())) ;plain Scheme data type
0bb9929e 514
68a61e9f
LC
515(define* (lower-inputs inputs
516 #:key system target)
517 "Turn any package from INPUTS into a derivation for SYSTEM; return the
518corresponding input list as a monadic value. When TARGET is true, use it as
519the cross-compilation target triplet."
21b679f6
LC
520 (with-monad %store-monad
521 (sequence %store-monad
522 (map (match-lambda
2242ff45 523 (((? struct? thing) sub-drv ...)
c2b84676
LC
524 (mlet %store-monad ((drv (lower-object
525 thing system #:target target)))
2242ff45
LC
526 (return `(,drv ,@sub-drv))))
527 (input
528 (return input)))
21b679f6
LC
529 inputs))))
530
b53833b2
LC
531(define* (lower-reference-graphs graphs #:key system target)
532 "Given GRAPHS, a list of (FILE-NAME INPUT ...) lists for use as a
533#:reference-graphs argument, lower it such that each INPUT is replaced by the
534corresponding derivation."
535 (match graphs
536 (((file-names . inputs) ...)
537 (mlet %store-monad ((inputs (lower-inputs inputs
538 #:system system
539 #:target target)))
540 (return (map cons file-names inputs))))))
541
c8351d9a
LC
542(define* (lower-references lst #:key system target)
543 "Based on LST, a list of output names and packages, return a list of output
544names and file names suitable for the #:allowed-references argument to
545'derivation'."
c8351d9a
LC
546 (with-monad %store-monad
547 (define lower
548 (match-lambda
549 ((? string? output)
550 (return output))
accb682c 551 (($ <gexp-input> thing output native?)
c2b84676
LC
552 (mlet %store-monad ((drv (lower-object thing system
553 #:target (if native?
554 #f target))))
accb682c 555 (return (derivation->output-path drv output))))
bcb13287 556 (thing
c2b84676
LC
557 (mlet %store-monad ((drv (lower-object thing system
558 #:target target)))
c8351d9a
LC
559 (return (derivation->output-path drv))))))
560
561 (sequence %store-monad (map lower lst))))
562
ff40e9b7
LC
563(define default-guile-derivation
564 ;; Here we break the abstraction by talking to the higher-level layer.
565 ;; Thus, do the resolution lazily to hide the circular dependency.
566 (let ((proc (delay
567 (let ((iface (resolve-interface '(guix packages))))
568 (module-ref iface 'default-guile-derivation)))))
569 (lambda (system)
570 ((force proc) system))))
571
21b679f6
LC
572(define* (gexp->derivation name exp
573 #:key
68a61e9f 574 system (target 'current)
21b679f6
LC
575 hash hash-algo recursive?
576 (env-vars '())
577 (modules '())
4684f301 578 (module-path %load-path)
21b679f6 579 (guile-for-build (%guile-for-build))
ce45eb4c 580 (graft? (%graft?))
21b679f6 581 references-graphs
3f4ecf32 582 allowed-references disallowed-references
c0468155 583 leaked-env-vars
0309e1b0 584 local-build? (substitutable? #t)
a912c723 585 deprecation-warnings
0309e1b0 586 (script-name (string-append name "-builder")))
21b679f6 587 "Return a derivation NAME that runs EXP (a gexp) with GUILE-FOR-BUILD (a
0309e1b0
LC
588derivation) on SYSTEM; EXP is stored in a file called SCRIPT-NAME. When
589TARGET is true, it is used as the cross-compilation target triplet for
590packages referred to by EXP.
21b679f6 591
0bb9929e
LC
592MODULES is deprecated in favor of 'with-imported-modules'. Its meaning is to
593make MODULES available in the evaluation context of EXP; MODULES is a list of
4684f301 594names of Guile modules searched in MODULE-PATH to be copied in the store,
21b679f6
LC
595compiled, and made available in the load path during the execution of
596EXP---e.g., '((guix build utils) (guix build gnu-build-system)).
597
ce45eb4c
LC
598GRAFT? determines whether packages referred to by EXP should be grafted when
599applicable.
600
b53833b2
LC
601When REFERENCES-GRAPHS is true, it must be a list of tuples of one of the
602following forms:
603
604 (FILE-NAME PACKAGE)
605 (FILE-NAME PACKAGE OUTPUT)
606 (FILE-NAME DERIVATION)
607 (FILE-NAME DERIVATION OUTPUT)
608 (FILE-NAME STORE-ITEM)
609
610The right-hand-side of each element of REFERENCES-GRAPHS is automatically made
611an input of the build process of EXP. In the build environment, each
612FILE-NAME contains the reference graph of the corresponding item, in a simple
613text format.
614
c8351d9a
LC
615ALLOWED-REFERENCES must be either #f or a list of output names and packages.
616In the latter case, the list denotes store items that the result is allowed to
617refer to. Any reference to another store item will lead to a build error.
3f4ecf32
LC
618Similarly for DISALLOWED-REFERENCES, which can list items that must not be
619referenced by the outputs.
b53833b2 620
a912c723
LC
621DEPRECATION-WARNINGS determines whether to show deprecation warnings while
622compiling modules. It can be #f, #t, or 'detailed.
623
21b679f6 624The other arguments are as for 'derivation'."
0bb9929e
LC
625 (define %modules
626 (delete-duplicates
627 (append modules (gexp-modules exp))))
21b679f6
LC
628 (define outputs (gexp-outputs exp))
629
b53833b2
LC
630 (define (graphs-file-names graphs)
631 ;; Return a list of (FILE-NAME . STORE-PATH) pairs made from GRAPHS.
632 (map (match-lambda
2924f0d6 633 ;; TODO: Remove 'derivation?' special cases.
b53833b2
LC
634 ((file-name (? derivation? drv))
635 (cons file-name (derivation->output-path drv)))
636 ((file-name (? derivation? drv) sub-drv)
637 (cons file-name (derivation->output-path drv sub-drv)))
638 ((file-name thing)
639 (cons file-name thing)))
640 graphs))
641
ce45eb4c
LC
642 (mlet* %store-monad (;; The following binding forces '%current-system' and
643 ;; '%current-target-system' to be looked up at >>=
644 ;; time.
645 (graft? (set-grafting graft?))
68a61e9f 646
5d098459 647 (system -> (or system (%current-system)))
68a61e9f
LC
648 (target -> (if (eq? target 'current)
649 (%current-target-system)
650 target))
667b2508 651 (normals (lower-inputs (gexp-inputs exp)
68a61e9f
LC
652 #:system system
653 #:target target))
667b2508
LC
654 (natives (lower-inputs (gexp-native-inputs exp)
655 #:system system
656 #:target #f))
657 (inputs -> (append normals natives))
68a61e9f
LC
658 (sexp (gexp->sexp exp
659 #:system system
660 #:target target))
0309e1b0 661 (builder (text-file script-name
21b679f6
LC
662 (object->string sexp)))
663 (modules (if (pair? %modules)
664 (imported-modules %modules
665 #:system system
4684f301 666 #:module-path module-path
30d722c3
LC
667 #:guile guile-for-build
668 #:deprecation-warnings
669 deprecation-warnings)
21b679f6
LC
670 (return #f)))
671 (compiled (if (pair? %modules)
672 (compiled-modules %modules
673 #:system system
4684f301 674 #:module-path module-path
a912c723
LC
675 #:guile guile-for-build
676 #:deprecation-warnings
677 deprecation-warnings)
21b679f6 678 (return #f)))
b53833b2
LC
679 (graphs (if references-graphs
680 (lower-reference-graphs references-graphs
681 #:system system
682 #:target target)
683 (return #f)))
c8351d9a
LC
684 (allowed (if allowed-references
685 (lower-references allowed-references
686 #:system system
687 #:target target)
688 (return #f)))
3f4ecf32
LC
689 (disallowed (if disallowed-references
690 (lower-references disallowed-references
691 #:system system
692 #:target target)
693 (return #f)))
21b679f6
LC
694 (guile (if guile-for-build
695 (return guile-for-build)
ff40e9b7 696 (default-guile-derivation system))))
ce45eb4c
LC
697 (mbegin %store-monad
698 (set-grafting graft?) ;restore the initial setting
699 (raw-derivation name
700 (string-append (derivation->output-path guile)
701 "/bin/guile")
702 `("--no-auto-compile"
703 ,@(if (pair? %modules)
704 `("-L" ,(derivation->output-path modules)
705 "-C" ,(derivation->output-path compiled))
706 '())
707 ,builder)
708 #:outputs outputs
709 #:env-vars env-vars
710 #:system system
711 #:inputs `((,guile)
712 (,builder)
713 ,@(if modules
714 `((,modules) (,compiled) ,@inputs)
715 inputs)
716 ,@(match graphs
717 (((_ . inputs) ...) inputs)
718 (_ '())))
719 #:hash hash #:hash-algo hash-algo #:recursive? recursive?
720 #:references-graphs (and=> graphs graphs-file-names)
721 #:allowed-references allowed
3f4ecf32 722 #:disallowed-references disallowed
c0468155 723 #:leaked-env-vars leaked-env-vars
4a6aeb67
LC
724 #:local-build? local-build?
725 #:substitutable? substitutable?))))
21b679f6 726
1123759b
LC
727(define* (gexp-inputs exp #:key native?)
728 "Return the input list for EXP. When NATIVE? is true, return only native
729references; otherwise, return only non-native references."
21b679f6
LC
730 (define (add-reference-inputs ref result)
731 (match ref
1123759b
LC
732 (($ <gexp-input> (? gexp? exp) _ #t)
733 (if native?
734 (append (gexp-inputs exp)
735 (gexp-inputs exp #:native? #t)
736 result)
737 result))
738 (($ <gexp-input> (? gexp? exp) _ #f)
d343a60f
LC
739 (append (gexp-inputs exp #:native? native?)
740 result))
e39d1461
LC
741 (($ <gexp-input> (? string? str))
742 (if (direct-store-path? str)
743 (cons `(,str) result)
21b679f6 744 result))
5b14a790
LC
745 (($ <gexp-input> (? struct? thing) output n?)
746 (if (and (eqv? n? native?) (lookup-compiler thing))
bcb13287
LC
747 ;; THING is a derivation, or a package, or an origin, etc.
748 (cons `(,thing ,output) result)
749 result))
1123759b 750 (($ <gexp-input> (lst ...) output n?)
578dfbe0
LC
751 (fold-right add-reference-inputs result
752 ;; XXX: For now, automatically convert LST to a list of
753 ;; gexp-inputs. Inherit N?.
754 (map (match-lambda
755 ((? gexp-input? x)
756 (%gexp-input (gexp-input-thing x)
757 (gexp-input-output x)
758 n?))
759 (x
760 (%gexp-input x "out" n?)))
761 lst)))
21b679f6
LC
762 (_
763 ;; Ignore references to other kinds of objects.
764 result)))
765
766 (fold-right add-reference-inputs
767 '()
5b14a790 768 (gexp-references exp)))
667b2508
LC
769
770(define gexp-native-inputs
1123759b 771 (cut gexp-inputs <> #:native? #t))
21b679f6
LC
772
773(define (gexp-outputs exp)
774 "Return the outputs referred to by EXP as a list of strings."
775 (define (add-reference-output ref result)
776 (match ref
1e87da58 777 (($ <gexp-output> name)
21b679f6 778 (cons name result))
e39d1461 779 (($ <gexp-input> (? gexp? exp))
21b679f6 780 (append (gexp-outputs exp) result))
e39d1461
LC
781 (($ <gexp-input> (lst ...) output native?)
782 ;; XXX: Automatically convert LST.
0dbea56b
LC
783 (add-reference-output (map (match-lambda
784 ((? gexp-input? x) x)
785 (x (%gexp-input x "out" native?)))
786 lst)
e39d1461 787 result))
f9efe568
LC
788 ((lst ...)
789 (fold-right add-reference-output result lst))
21b679f6
LC
790 (_
791 result)))
792
7e75a673
LC
793 (delete-duplicates
794 (add-reference-output (gexp-references exp) '())))
21b679f6 795
68a61e9f
LC
796(define* (gexp->sexp exp #:key
797 (system (%current-system))
798 (target (%current-target-system)))
21b679f6
LC
799 "Return (monadically) the sexp corresponding to EXP for the given OUTPUT,
800and in the current monad setting (system type, etc.)"
667b2508 801 (define* (reference->sexp ref #:optional native?)
21b679f6
LC
802 (with-monad %store-monad
803 (match ref
1e87da58 804 (($ <gexp-output> output)
bfd9eed9
LC
805 ;; Output file names are not known in advance but the daemon defines
806 ;; an environment variable for each of them at build time, so use
807 ;; that trick.
808 (return `((@ (guile) getenv) ,output)))
e39d1461 809 (($ <gexp-input> (? gexp? exp) output n?)
667b2508
LC
810 (gexp->sexp exp
811 #:system system
e39d1461
LC
812 #:target (if (or n? native?) #f target)))
813 (($ <gexp-input> (refs ...) output n?)
667b2508 814 (sequence %store-monad
e39d1461
LC
815 (map (lambda (ref)
816 ;; XXX: Automatically convert REF to an gexp-input.
0dbea56b
LC
817 (reference->sexp
818 (if (gexp-input? ref)
819 ref
820 (%gexp-input ref "out" n?))
affd7761 821 (or n? native?)))
e39d1461 822 refs)))
bcb13287 823 (($ <gexp-input> (? struct? thing) output n?)
ebdfd776
LC
824 (let ((target (if (or n? native?) #f target))
825 (expand (lookup-expander thing)))
c2b84676
LC
826 (mlet %store-monad ((obj (lower-object thing system
827 #:target target)))
d9ae938f 828 ;; OBJ must be either a derivation or a store file name.
ebdfd776 829 (return (expand thing obj output)))))
e39d1461
LC
830 (($ <gexp-input> x)
831 (return x))
21b679f6
LC
832 (x
833 (return x)))))
834
835 (mlet %store-monad
836 ((args (sequence %store-monad
affd7761 837 (map reference->sexp (gexp-references exp)))))
21b679f6
LC
838 (return (apply (gexp-proc exp) args))))
839
21b679f6
LC
840(define (syntax-location-string s)
841 "Return a string representing the source code location of S."
842 (let ((props (syntax-source s)))
843 (if props
844 (let ((file (assoc-ref props 'filename))
845 (line (and=> (assoc-ref props 'line) 1+))
846 (column (assoc-ref props 'column)))
847 (if file
848 (simple-format #f "~a:~a:~a"
849 file line column)
850 (simple-format #f "~a:~a" line column)))
851 "<unknown location>")))
852
0bb9929e
LC
853(define-syntax-parameter current-imported-modules
854 ;; Current list of imported modules.
855 (identifier-syntax '()))
856
857(define-syntax-rule (with-imported-modules modules body ...)
858 "Mark the gexps defined in BODY... as requiring MODULES in their execution
859environment."
860 (syntax-parameterize ((current-imported-modules
861 (identifier-syntax modules)))
862 body ...))
863
21b679f6
LC
864(define-syntax gexp
865 (lambda (s)
866 (define (collect-escapes exp)
867 ;; Return all the 'ungexp' present in EXP.
868 (let loop ((exp exp)
869 (result '()))
607e1b51
LC
870 (syntax-case exp (ungexp
871 ungexp-splicing
872 ungexp-native
873 ungexp-native-splicing)
21b679f6
LC
874 ((ungexp _)
875 (cons exp result))
876 ((ungexp _ _)
877 (cons exp result))
878 ((ungexp-splicing _ ...)
879 (cons exp result))
607e1b51 880 ((ungexp-native _ ...)
667b2508
LC
881 (cons exp result))
882 ((ungexp-native-splicing _ ...)
883 (cons exp result))
5e2e4a51 884 ((exp0 . exp)
667b2508 885 (let ((result (loop #'exp0 result)))
5e2e4a51 886 (loop #'exp result)))
667b2508
LC
887 (_
888 result))))
889
21b679f6
LC
890 (define (escape->ref exp)
891 ;; Turn 'ungexp' form EXP into a "reference".
667b2508
LC
892 (syntax-case exp (ungexp ungexp-splicing
893 ungexp-native ungexp-native-splicing
894 output)
21b679f6 895 ((ungexp output)
1e87da58 896 #'(gexp-output "out"))
21b679f6 897 ((ungexp output name)
1e87da58 898 #'(gexp-output name))
21b679f6 899 ((ungexp thing)
0dbea56b 900 #'(%gexp-input thing "out" #f))
21b679f6 901 ((ungexp drv-or-pkg out)
0dbea56b 902 #'(%gexp-input drv-or-pkg out #f))
21b679f6 903 ((ungexp-splicing lst)
0dbea56b 904 #'(%gexp-input lst "out" #f))
667b2508 905 ((ungexp-native thing)
0dbea56b 906 #'(%gexp-input thing "out" #t))
667b2508 907 ((ungexp-native drv-or-pkg out)
0dbea56b 908 #'(%gexp-input drv-or-pkg out #t))
667b2508 909 ((ungexp-native-splicing lst)
0dbea56b 910 #'(%gexp-input lst "out" #t))))
21b679f6 911
667b2508
LC
912 (define (substitute-ungexp exp substs)
913 ;; Given EXP, an 'ungexp' or 'ungexp-native' form, substitute it with
914 ;; the corresponding form in SUBSTS.
915 (match (assoc exp substs)
916 ((_ id)
917 id)
4a6e889f
LC
918 (_ ;internal error
919 (with-syntax ((exp exp))
920 #'(syntax-error "error: no 'ungexp' substitution" exp)))))
667b2508
LC
921
922 (define (substitute-ungexp-splicing exp substs)
923 (syntax-case exp ()
924 ((exp rest ...)
925 (match (assoc #'exp substs)
926 ((_ id)
927 (with-syntax ((id id))
928 #`(append id
929 #,(substitute-references #'(rest ...) substs))))
930 (_
931 #'(syntax-error "error: no 'ungexp-splicing' substitution"
4a6e889f 932 exp))))))
667b2508 933
21b679f6
LC
934 (define (substitute-references exp substs)
935 ;; Return a variant of EXP where all the cars of SUBSTS have been
936 ;; replaced by the corresponding cdr.
667b2508
LC
937 (syntax-case exp (ungexp ungexp-native
938 ungexp-splicing ungexp-native-splicing)
21b679f6 939 ((ungexp _ ...)
667b2508
LC
940 (substitute-ungexp exp substs))
941 ((ungexp-native _ ...)
942 (substitute-ungexp exp substs))
21b679f6 943 (((ungexp-splicing _ ...) rest ...)
667b2508
LC
944 (substitute-ungexp-splicing exp substs))
945 (((ungexp-native-splicing _ ...) rest ...)
946 (substitute-ungexp-splicing exp substs))
5e2e4a51 947 ((exp0 . exp)
21b679f6 948 #`(cons #,(substitute-references #'exp0 substs)
5e2e4a51 949 #,(substitute-references #'exp substs)))
21b679f6
LC
950 (x #''x)))
951
952 (syntax-case s (ungexp output)
953 ((_ exp)
affd7761 954 (let* ((escapes (delete-duplicates (collect-escapes #'exp)))
21b679f6
LC
955 (formals (generate-temporaries escapes))
956 (sexp (substitute-references #'exp (zip escapes formals)))
affd7761
LC
957 (refs (map escape->ref escapes)))
958 #`(make-gexp (list #,@refs)
0bb9929e 959 current-imported-modules
21b679f6
LC
960 (lambda #,formals
961 #,sexp)))))))
962
963\f
aa72d9af
LC
964;;;
965;;; Module handling.
966;;;
967
df2d51f0
LC
968(define %utils-module
969 ;; This file provides 'mkdir-p', needed to implement 'imported-files' and
a9601e23
LC
970 ;; other primitives below. Note: We give the file name relative to this
971 ;; file you are currently reading; 'search-path' could return a file name
972 ;; relative to the current working directory.
973 (local-file "build/utils.scm"
df2d51f0 974 "build-utils.scm"))
aa72d9af
LC
975
976(define* (imported-files files
977 #:key (name "file-import")
978 (system (%current-system))
30d722c3
LC
979 (guile (%guile-for-build))
980
981 ;; XXX: The only reason we have
982 ;; #:deprecation-warnings is because (guix build
983 ;; utils), which we use here, relies on _IO*, which
984 ;; is deprecated in 2.2. On the next full-rebuild
985 ;; cycle, we should disable such warnings
986 ;; unconditionally.
987 (deprecation-warnings #f))
aa72d9af 988 "Return a derivation that imports FILES into STORE. FILES must be a list
d938a58b
LC
989of (FINAL-PATH . FILE) pairs. Each FILE is mapped to FINAL-PATH in the
990resulting store path. FILE can be either a file name, or a file-like object,
991as returned by 'local-file' for example."
aa72d9af
LC
992 (define file-pair
993 (match-lambda
d938a58b 994 ((final-path . (? string? file-name))
aa72d9af
LC
995 (mlet %store-monad ((file (interned-file file-name
996 (basename final-path))))
d938a58b
LC
997 (return (list final-path file))))
998 ((final-path . file-like)
999 (mlet %store-monad ((file (lower-object file-like system)))
aa72d9af
LC
1000 (return (list final-path file))))))
1001
1002 (mlet %store-monad ((files (sequence %store-monad
1003 (map file-pair files))))
1004 (define build
1005 (gexp
1006 (begin
df2d51f0 1007 (primitive-load (ungexp %utils-module)) ;for 'mkdir-p'
aa72d9af
LC
1008 (use-modules (ice-9 match))
1009
aa72d9af
LC
1010 (mkdir (ungexp output)) (chdir (ungexp output))
1011 (for-each (match-lambda
1012 ((final-path store-path)
1013 (mkdir-p (dirname final-path))
1014 (symlink store-path final-path)))
1015 '(ungexp files)))))
1016
1017 ;; TODO: Pass FILES as an environment variable so that BUILD remains
1018 ;; exactly the same regardless of FILES: less disk space, and fewer
1019 ;; 'add-to-store' RPCs.
1020 (gexp->derivation name build
1021 #:system system
1022 #:guile-for-build guile
30d722c3
LC
1023 #:local-build? #t
1024
1025 ;; TODO: On the next rebuild cycle, set to "no"
1026 ;; unconditionally.
1027 #:env-vars
1028 (case deprecation-warnings
1029 ((#f)
1030 '(("GUILE_WARN_DEPRECATED" . "no")))
1031 ((detailed)
1032 '(("GUILE_WARN_DEPRECATED" . "detailed")))
1033 (else
1034 '())))))
aa72d9af 1035
aa72d9af
LC
1036(define* (imported-modules modules
1037 #:key (name "module-import")
1038 (system (%current-system))
1039 (guile (%guile-for-build))
30d722c3
LC
1040 (module-path %load-path)
1041 (deprecation-warnings #f))
aa72d9af 1042 "Return a derivation that contains the source files of MODULES, a list of
d938a58b
LC
1043module names such as `(ice-9 q)'. All of MODULES must be either names of
1044modules to be found in the MODULE-PATH search path, or a module name followed
1045by an arrow followed by a file-like object. For example:
1046
1047 (imported-modules `((guix build utils)
1048 (guix gcrypt)
1049 ((guix config) => ,(scheme-file …))))
1050
1051In this example, the first two modules are taken from MODULE-PATH, and the
1052last one is created from the given <scheme-file> object."
1053 (mlet %store-monad ((files
1054 (mapm %store-monad
1055 (match-lambda
1056 (((module ...) '=> file)
1057 (return
1058 (cons (module->source-file-name module)
1059 file)))
1060 ((module ...)
1061 (let ((f (module->source-file-name module)))
1062 (return
1063 (cons f (search-path* module-path f))))))
1064 modules)))
aa72d9af 1065 (imported-files files #:name name #:system system
30d722c3
LC
1066 #:guile guile
1067 #:deprecation-warnings deprecation-warnings)))
aa72d9af
LC
1068
1069(define* (compiled-modules modules
1070 #:key (name "module-import-compiled")
1071 (system (%current-system))
1072 (guile (%guile-for-build))
a912c723
LC
1073 (module-path %load-path)
1074 (deprecation-warnings #f))
aa72d9af
LC
1075 "Return a derivation that builds a tree containing the `.go' files
1076corresponding to MODULES. All the MODULES are built in a context where
1077they can refer to each other."
5d669883
LC
1078 (define build-utils-hack?
1079 ;; To avoid a full rebuild, we limit the fix below to the case where
1080 ;; MODULE-PATH is different from %LOAD-PATH. This happens when building
1081 ;; modules for 'compute-guix-derivation' upon 'guix pull'. TODO: Make
1082 ;; this unconditional on the next rebuild cycle.
1083 (and (member '(guix build utils) modules)
1084 (not (equal? module-path %load-path))))
1085
aa72d9af
LC
1086 (mlet %store-monad ((modules (imported-modules modules
1087 #:system system
1088 #:guile guile
1089 #:module-path
30d722c3
LC
1090 module-path
1091 #:deprecation-warnings
1092 deprecation-warnings)))
aa72d9af
LC
1093 (define build
1094 (gexp
1095 (begin
df2d51f0
LC
1096 (primitive-load (ungexp %utils-module)) ;for 'mkdir-p'
1097
aa72d9af 1098 (use-modules (ice-9 ftw)
aa72d9af
LC
1099 (srfi srfi-26)
1100 (system base compile))
1101
aa72d9af
LC
1102 (define (regular? file)
1103 (not (member file '("." ".."))))
1104
1105 (define (process-directory directory output)
1106 (let ((entries (map (cut string-append directory "/" <>)
1107 (scandir directory regular?))))
1108 (for-each (lambda (entry)
1109 (if (file-is-directory? entry)
1110 (let ((output (string-append output "/"
1111 (basename entry))))
1112 (mkdir-p output)
1113 (process-directory entry output))
1114 (let* ((base (string-drop-right
1115 (basename entry)
1116 4)) ;.scm
1117 (output (string-append output "/" base
1118 ".go")))
1119 (compile-file entry
1120 #:output-file output
1121 #:opts
1122 %auto-compilation-options))))
1123 entries)))
1124
5d669883
LC
1125 (ungexp-splicing
1126 (if build-utils-hack?
1127 (gexp ((define mkdir-p
1128 ;; Capture 'mkdir-p'.
1129 (@ (guix build utils) mkdir-p))))
1130 '()))
1131
aa72d9af 1132 (set! %load-path (cons (ungexp modules) %load-path))
5d669883
LC
1133
1134 (ungexp-splicing
1135 (if build-utils-hack?
1136 ;; Above we loaded our own (guix build utils) but now we may
1137 ;; need to load a compile a different one. Thus, force a
1138 ;; reload.
1139 (gexp ((let ((utils (ungexp
1140 (file-append modules
1141 "/guix/build/utils.scm"))))
1142 (when (file-exists? utils)
1143 (load utils)))))
1144 '()))
1145
aa72d9af
LC
1146 (mkdir (ungexp output))
1147 (chdir (ungexp modules))
1148 (process-directory "." (ungexp output)))))
1149
1150 ;; TODO: Pass MODULES as an environment variable.
1151 (gexp->derivation name build
1152 #:system system
1153 #:guile-for-build guile
a912c723
LC
1154 #:local-build? #t
1155 #:env-vars
1156 (case deprecation-warnings
1157 ((#f)
1158 '(("GUILE_WARN_DEPRECATED" . "no")))
1159 ((detailed)
1160 '(("GUILE_WARN_DEPRECATED" . "detailed")))
1161 (else
1162 '())))))
aa72d9af
LC
1163
1164\f
21b679f6
LC
1165;;;
1166;;; Convenience procedures.
1167;;;
1168
53e89b17 1169(define (default-guile)
6ee797f3
LC
1170 ;; Lazily resolve 'guile-2.2' (not 'guile-final' because this is for
1171 ;; programs returned by 'program-file' and we don't want to keep references
1172 ;; to several Guile packages). This module must not refer to (gnu …)
53e89b17 1173 ;; modules directly, to avoid circular dependencies, hence this hack.
6ee797f3
LC
1174 (module-ref (resolve-interface '(gnu packages guile))
1175 'guile-2.2))
53e89b17 1176
1ae16033 1177(define* (load-path-expression modules #:optional (path %load-path))
dd8d1a30 1178 "Return as a monadic value a gexp that sets '%load-path' and
1ae16033
LC
1179'%load-compiled-path' to point to MODULES, a list of module names. MODULES
1180are searched for in PATH."
1181 (mlet %store-monad ((modules (imported-modules modules
1182 #:module-path path))
1183 (compiled (compiled-modules modules
1184 #:module-path path)))
dd8d1a30
LC
1185 (return (gexp (eval-when (expand load eval)
1186 (set! %load-path
1187 (cons (ungexp modules) %load-path))
1188 (set! %load-compiled-path
1189 (cons (ungexp compiled)
1190 %load-compiled-path)))))))
1191
21b679f6 1192(define* (gexp->script name exp
1ae16033
LC
1193 #:key (guile (default-guile))
1194 (module-path %load-path))
9c14a487 1195 "Return an executable script NAME that runs EXP using GUILE, with EXP's
1ae16033 1196imported modules in its search path. Look up EXP's modules in MODULE-PATH."
9c14a487 1197 (mlet %store-monad ((set-load-path
1ae16033
LC
1198 (load-path-expression (gexp-modules exp)
1199 module-path)))
21b679f6
LC
1200 (gexp->derivation name
1201 (gexp
1202 (call-with-output-file (ungexp output)
1203 (lambda (port)
c17b5ab4
LC
1204 ;; Note: that makes a long shebang. When the store
1205 ;; is /gnu/store, that fits within the 128-byte
1206 ;; limit imposed by Linux, but that may go beyond
1207 ;; when running tests.
21b679f6
LC
1208 (format port
1209 "#!~a/bin/guile --no-auto-compile~%!#~%"
1210 (ungexp guile))
4a4cbd0b 1211
dd8d1a30 1212 (write '(ungexp set-load-path) port)
21b679f6 1213 (write '(ungexp exp) port)
1ae16033
LC
1214 (chmod port #o555))))
1215 #:module-path module-path)))
21b679f6 1216
1ae16033
LC
1217(define* (gexp->file name exp #:key
1218 (set-load-path? #t)
4fbd1a2b
LC
1219 (module-path %load-path)
1220 (splice? #f))
1221 "Return a derivation that builds a file NAME containing EXP. When SPLICE?
1222is true, EXP is considered to be a list of expressions that will be spliced in
1223the resulting file.
1224
1225When SET-LOAD-PATH? is true, emit code in the resulting file to set
1226'%load-path' and '%load-compiled-path' to honor EXP's imported modules.
1227Lookup EXP's modules in MODULE-PATH."
2b418579
LC
1228 (match (if set-load-path? (gexp-modules exp) '())
1229 (() ;zero modules
1230 (gexp->derivation name
1231 (gexp
1232 (call-with-output-file (ungexp output)
1233 (lambda (port)
4fbd1a2b
LC
1234 (for-each (lambda (exp)
1235 (write exp port))
1236 '(ungexp (if splice?
1237 exp
1238 (gexp ((ungexp exp)))))))))
2b418579
LC
1239 #:local-build? #t
1240 #:substitutable? #f))
1241 ((modules ...)
1ae16033
LC
1242 (mlet %store-monad ((set-load-path (load-path-expression modules
1243 module-path)))
2b418579
LC
1244 (gexp->derivation name
1245 (gexp
1246 (call-with-output-file (ungexp output)
1247 (lambda (port)
1248 (write '(ungexp set-load-path) port)
4fbd1a2b
LC
1249 (for-each (lambda (exp)
1250 (write exp port))
1251 '(ungexp (if splice?
1252 exp
1253 (gexp ((ungexp exp)))))))))
1ae16033 1254 #:module-path module-path
2b418579
LC
1255 #:local-build? #t
1256 #:substitutable? #f)))))
21b679f6 1257
462a3fa3
LC
1258(define* (text-file* name #:rest text)
1259 "Return as a monadic value a derivation that builds a text file containing
d9ae938f
LC
1260all of TEXT. TEXT may list, in addition to strings, objects of any type that
1261can be used in a gexp: packages, derivations, local file objects, etc. The
1262resulting store file holds references to all these."
462a3fa3
LC
1263 (define builder
1264 (gexp (call-with-output-file (ungexp output "out")
1265 (lambda (port)
1266 (display (string-append (ungexp-splicing text)) port)))))
1267
851b6f62
LC
1268 (gexp->derivation name builder
1269 #:local-build? #t
1270 #:substitutable? #f))
462a3fa3 1271
b751cde3
LC
1272(define* (mixed-text-file name #:rest text)
1273 "Return an object representing store file NAME containing TEXT. TEXT is a
1274sequence of strings and file-like objects, as in:
1275
1276 (mixed-text-file \"profile\"
1277 \"export PATH=\" coreutils \"/bin:\" grep \"/bin\")
1278
1279This is the declarative counterpart of 'text-file*'."
1280 (define build
1281 (gexp (call-with-output-file (ungexp output "out")
1282 (lambda (port)
1283 (display (string-append (ungexp-splicing text)) port)))))
1284
1285 (computed-file name build))
1286
dedb512f
LC
1287(define (file-union name files)
1288 "Return a <computed-file> that builds a directory containing all of FILES.
1289Each item in FILES must be a two-element list where the first element is the
1290file name to use in the new directory, and the second element is a gexp
1291denoting the target file. Here's an example:
1292
1293 (file-union \"etc\"
1294 `((\"hosts\" ,(plain-file \"hosts\"
1295 \"127.0.0.1 localhost\"))
1296 (\"bashrc\" ,(plain-file \"bashrc\"
1297 \"alias ls='ls --color'\"))))
1298
1299This yields an 'etc' directory containing these two files."
1300 (computed-file name
1301 (gexp
1302 (begin
1303 (mkdir (ungexp output))
1304 (chdir (ungexp output))
1305 (ungexp-splicing
1306 (map (match-lambda
1307 ((target source)
1308 (gexp
1309 (begin
1310 ;; Stat the source to abort early if it does
1311 ;; not exist.
1312 (stat (ungexp source))
1313
1314 (symlink (ungexp source)
1315 (ungexp target))))))
1316 files))))))
1317
59523429 1318(define* (directory-union name things
b244ae25
LC
1319 #:key (copy? #f) (quiet? #f)
1320 (resolve-collision 'warn-about-collision))
d298c815
LC
1321 "Return a directory that is the union of THINGS, where THINGS is a list of
1322file-like objects denoting directories. For example:
1323
1324 (directory-union \"guile+emacs\" (list guile emacs))
1325
59523429
LC
1326yields a directory that is the union of the 'guile' and 'emacs' packages.
1327
b244ae25
LC
1328Call RESOLVE-COLLISION when several files collide, passing it the list of
1329colliding files. RESOLVE-COLLISION must return the chosen file or #f, in
1330which case the colliding entry is skipped altogether.
1331
de98b302
LC
1332When HARD-LINKS? is true, create hard links instead of symlinks. When QUIET?
1333is true, the derivation will not print anything."
59523429
LC
1334 (define symlink
1335 (if copy?
1336 (gexp (lambda (old new)
1337 (if (file-is-directory? old)
1338 (symlink old new)
1339 (copy-file old new))))
1340 (gexp symlink)))
1341
de98b302
LC
1342 (define log-port
1343 (if quiet?
1344 (gexp (%make-void-port "w"))
1345 (gexp (current-error-port))))
1346
d298c815
LC
1347 (match things
1348 ((one)
1349 ;; Only one thing; return it.
1350 one)
1351 (_
1352 (computed-file name
1353 (with-imported-modules '((guix build union))
1354 (gexp (begin
b244ae25
LC
1355 (use-modules (guix build union)
1356 (srfi srfi-1)) ;for 'first' and 'last'
1357
d298c815 1358 (union-build (ungexp output)
59523429
LC
1359 '(ungexp things)
1360
de98b302 1361 #:log-port (ungexp log-port)
b244ae25
LC
1362 #:symlink (ungexp symlink)
1363 #:resolve-collision
1364 (ungexp resolve-collision)))))))))
d298c815 1365
21b679f6
LC
1366\f
1367;;;
1368;;; Syntactic sugar.
1369;;;
1370
1371(eval-when (expand load eval)
667b2508
LC
1372 (define* (read-ungexp chr port #:optional native?)
1373 "Read an 'ungexp' or 'ungexp-splicing' form from PORT. When NATIVE? is
1374true, use 'ungexp-native' and 'ungexp-native-splicing' instead."
21b679f6
LC
1375 (define unquote-symbol
1376 (match (peek-char port)
1377 (#\@
1378 (read-char port)
667b2508
LC
1379 (if native?
1380 'ungexp-native-splicing
1381 'ungexp-splicing))
21b679f6 1382 (_
667b2508
LC
1383 (if native?
1384 'ungexp-native
1385 'ungexp))))
21b679f6
LC
1386
1387 (match (read port)
1388 ((? symbol? symbol)
1389 (let ((str (symbol->string symbol)))
1390 (match (string-index-right str #\:)
1391 (#f
1392 `(,unquote-symbol ,symbol))
1393 (colon
1394 (let ((name (string->symbol (substring str 0 colon)))
1395 (output (substring str (+ colon 1))))
1396 `(,unquote-symbol ,name ,output))))))
1397 (x
1398 `(,unquote-symbol ,x))))
1399
1400 (define (read-gexp chr port)
1401 "Read a 'gexp' form from PORT."
1402 `(gexp ,(read port)))
1403
1404 ;; Extend the reader
1405 (read-hash-extend #\~ read-gexp)
667b2508
LC
1406 (read-hash-extend #\$ read-ungexp)
1407 (read-hash-extend #\+ (cut read-ungexp <> <> #t)))
21b679f6
LC
1408
1409;;; gexp.scm ends here