gnu: rust: Add support for building 32-bit packages on 64-bit hosts.
[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."
1078 (mlet %store-monad ((modules (imported-modules modules
1079 #:system system
1080 #:guile guile
1081 #:module-path
30d722c3
LC
1082 module-path
1083 #:deprecation-warnings
1084 deprecation-warnings)))
aa72d9af
LC
1085 (define build
1086 (gexp
1087 (begin
df2d51f0
LC
1088 (primitive-load (ungexp %utils-module)) ;for 'mkdir-p'
1089
aa72d9af 1090 (use-modules (ice-9 ftw)
aa72d9af
LC
1091 (srfi srfi-26)
1092 (system base compile))
1093
aa72d9af
LC
1094 (define (regular? file)
1095 (not (member file '("." ".."))))
1096
1097 (define (process-directory directory output)
1098 (let ((entries (map (cut string-append directory "/" <>)
1099 (scandir directory regular?))))
1100 (for-each (lambda (entry)
1101 (if (file-is-directory? entry)
1102 (let ((output (string-append output "/"
1103 (basename entry))))
1104 (mkdir-p output)
1105 (process-directory entry output))
1106 (let* ((base (string-drop-right
1107 (basename entry)
1108 4)) ;.scm
1109 (output (string-append output "/" base
1110 ".go")))
1111 (compile-file entry
1112 #:output-file output
1113 #:opts
1114 %auto-compilation-options))))
1115 entries)))
1116
1117 (set! %load-path (cons (ungexp modules) %load-path))
1118 (mkdir (ungexp output))
1119 (chdir (ungexp modules))
1120 (process-directory "." (ungexp output)))))
1121
1122 ;; TODO: Pass MODULES as an environment variable.
1123 (gexp->derivation name build
1124 #:system system
1125 #:guile-for-build guile
a912c723
LC
1126 #:local-build? #t
1127 #:env-vars
1128 (case deprecation-warnings
1129 ((#f)
1130 '(("GUILE_WARN_DEPRECATED" . "no")))
1131 ((detailed)
1132 '(("GUILE_WARN_DEPRECATED" . "detailed")))
1133 (else
1134 '())))))
aa72d9af
LC
1135
1136\f
21b679f6
LC
1137;;;
1138;;; Convenience procedures.
1139;;;
1140
53e89b17 1141(define (default-guile)
6ee797f3
LC
1142 ;; Lazily resolve 'guile-2.2' (not 'guile-final' because this is for
1143 ;; programs returned by 'program-file' and we don't want to keep references
1144 ;; to several Guile packages). This module must not refer to (gnu …)
53e89b17 1145 ;; modules directly, to avoid circular dependencies, hence this hack.
6ee797f3
LC
1146 (module-ref (resolve-interface '(gnu packages guile))
1147 'guile-2.2))
53e89b17 1148
1ae16033 1149(define* (load-path-expression modules #:optional (path %load-path))
dd8d1a30 1150 "Return as a monadic value a gexp that sets '%load-path' and
1ae16033
LC
1151'%load-compiled-path' to point to MODULES, a list of module names. MODULES
1152are searched for in PATH."
1153 (mlet %store-monad ((modules (imported-modules modules
1154 #:module-path path))
1155 (compiled (compiled-modules modules
1156 #:module-path path)))
dd8d1a30
LC
1157 (return (gexp (eval-when (expand load eval)
1158 (set! %load-path
1159 (cons (ungexp modules) %load-path))
1160 (set! %load-compiled-path
1161 (cons (ungexp compiled)
1162 %load-compiled-path)))))))
1163
21b679f6 1164(define* (gexp->script name exp
1ae16033
LC
1165 #:key (guile (default-guile))
1166 (module-path %load-path))
9c14a487 1167 "Return an executable script NAME that runs EXP using GUILE, with EXP's
1ae16033 1168imported modules in its search path. Look up EXP's modules in MODULE-PATH."
9c14a487 1169 (mlet %store-monad ((set-load-path
1ae16033
LC
1170 (load-path-expression (gexp-modules exp)
1171 module-path)))
21b679f6
LC
1172 (gexp->derivation name
1173 (gexp
1174 (call-with-output-file (ungexp output)
1175 (lambda (port)
c17b5ab4
LC
1176 ;; Note: that makes a long shebang. When the store
1177 ;; is /gnu/store, that fits within the 128-byte
1178 ;; limit imposed by Linux, but that may go beyond
1179 ;; when running tests.
21b679f6
LC
1180 (format port
1181 "#!~a/bin/guile --no-auto-compile~%!#~%"
1182 (ungexp guile))
4a4cbd0b 1183
dd8d1a30 1184 (write '(ungexp set-load-path) port)
21b679f6 1185 (write '(ungexp exp) port)
1ae16033
LC
1186 (chmod port #o555))))
1187 #:module-path module-path)))
21b679f6 1188
1ae16033
LC
1189(define* (gexp->file name exp #:key
1190 (set-load-path? #t)
4fbd1a2b
LC
1191 (module-path %load-path)
1192 (splice? #f))
1193 "Return a derivation that builds a file NAME containing EXP. When SPLICE?
1194is true, EXP is considered to be a list of expressions that will be spliced in
1195the resulting file.
1196
1197When SET-LOAD-PATH? is true, emit code in the resulting file to set
1198'%load-path' and '%load-compiled-path' to honor EXP's imported modules.
1199Lookup EXP's modules in MODULE-PATH."
2b418579
LC
1200 (match (if set-load-path? (gexp-modules exp) '())
1201 (() ;zero modules
1202 (gexp->derivation name
1203 (gexp
1204 (call-with-output-file (ungexp output)
1205 (lambda (port)
4fbd1a2b
LC
1206 (for-each (lambda (exp)
1207 (write exp port))
1208 '(ungexp (if splice?
1209 exp
1210 (gexp ((ungexp exp)))))))))
2b418579
LC
1211 #:local-build? #t
1212 #:substitutable? #f))
1213 ((modules ...)
1ae16033
LC
1214 (mlet %store-monad ((set-load-path (load-path-expression modules
1215 module-path)))
2b418579
LC
1216 (gexp->derivation name
1217 (gexp
1218 (call-with-output-file (ungexp output)
1219 (lambda (port)
1220 (write '(ungexp set-load-path) port)
4fbd1a2b
LC
1221 (for-each (lambda (exp)
1222 (write exp port))
1223 '(ungexp (if splice?
1224 exp
1225 (gexp ((ungexp exp)))))))))
1ae16033 1226 #:module-path module-path
2b418579
LC
1227 #:local-build? #t
1228 #:substitutable? #f)))))
21b679f6 1229
462a3fa3
LC
1230(define* (text-file* name #:rest text)
1231 "Return as a monadic value a derivation that builds a text file containing
d9ae938f
LC
1232all of TEXT. TEXT may list, in addition to strings, objects of any type that
1233can be used in a gexp: packages, derivations, local file objects, etc. The
1234resulting store file holds references to all these."
462a3fa3
LC
1235 (define builder
1236 (gexp (call-with-output-file (ungexp output "out")
1237 (lambda (port)
1238 (display (string-append (ungexp-splicing text)) port)))))
1239
851b6f62
LC
1240 (gexp->derivation name builder
1241 #:local-build? #t
1242 #:substitutable? #f))
462a3fa3 1243
b751cde3
LC
1244(define* (mixed-text-file name #:rest text)
1245 "Return an object representing store file NAME containing TEXT. TEXT is a
1246sequence of strings and file-like objects, as in:
1247
1248 (mixed-text-file \"profile\"
1249 \"export PATH=\" coreutils \"/bin:\" grep \"/bin\")
1250
1251This is the declarative counterpart of 'text-file*'."
1252 (define build
1253 (gexp (call-with-output-file (ungexp output "out")
1254 (lambda (port)
1255 (display (string-append (ungexp-splicing text)) port)))))
1256
1257 (computed-file name build))
1258
dedb512f
LC
1259(define (file-union name files)
1260 "Return a <computed-file> that builds a directory containing all of FILES.
1261Each item in FILES must be a two-element list where the first element is the
1262file name to use in the new directory, and the second element is a gexp
1263denoting the target file. Here's an example:
1264
1265 (file-union \"etc\"
1266 `((\"hosts\" ,(plain-file \"hosts\"
1267 \"127.0.0.1 localhost\"))
1268 (\"bashrc\" ,(plain-file \"bashrc\"
1269 \"alias ls='ls --color'\"))))
1270
1271This yields an 'etc' directory containing these two files."
1272 (computed-file name
1273 (gexp
1274 (begin
1275 (mkdir (ungexp output))
1276 (chdir (ungexp output))
1277 (ungexp-splicing
1278 (map (match-lambda
1279 ((target source)
1280 (gexp
1281 (begin
1282 ;; Stat the source to abort early if it does
1283 ;; not exist.
1284 (stat (ungexp source))
1285
1286 (symlink (ungexp source)
1287 (ungexp target))))))
1288 files))))))
1289
59523429 1290(define* (directory-union name things
b244ae25
LC
1291 #:key (copy? #f) (quiet? #f)
1292 (resolve-collision 'warn-about-collision))
d298c815
LC
1293 "Return a directory that is the union of THINGS, where THINGS is a list of
1294file-like objects denoting directories. For example:
1295
1296 (directory-union \"guile+emacs\" (list guile emacs))
1297
59523429
LC
1298yields a directory that is the union of the 'guile' and 'emacs' packages.
1299
b244ae25
LC
1300Call RESOLVE-COLLISION when several files collide, passing it the list of
1301colliding files. RESOLVE-COLLISION must return the chosen file or #f, in
1302which case the colliding entry is skipped altogether.
1303
de98b302
LC
1304When HARD-LINKS? is true, create hard links instead of symlinks. When QUIET?
1305is true, the derivation will not print anything."
59523429
LC
1306 (define symlink
1307 (if copy?
1308 (gexp (lambda (old new)
1309 (if (file-is-directory? old)
1310 (symlink old new)
1311 (copy-file old new))))
1312 (gexp symlink)))
1313
de98b302
LC
1314 (define log-port
1315 (if quiet?
1316 (gexp (%make-void-port "w"))
1317 (gexp (current-error-port))))
1318
d298c815
LC
1319 (match things
1320 ((one)
1321 ;; Only one thing; return it.
1322 one)
1323 (_
1324 (computed-file name
1325 (with-imported-modules '((guix build union))
1326 (gexp (begin
b244ae25
LC
1327 (use-modules (guix build union)
1328 (srfi srfi-1)) ;for 'first' and 'last'
1329
d298c815 1330 (union-build (ungexp output)
59523429
LC
1331 '(ungexp things)
1332
de98b302 1333 #:log-port (ungexp log-port)
b244ae25
LC
1334 #:symlink (ungexp symlink)
1335 #:resolve-collision
1336 (ungexp resolve-collision)))))))))
d298c815 1337
21b679f6
LC
1338\f
1339;;;
1340;;; Syntactic sugar.
1341;;;
1342
1343(eval-when (expand load eval)
667b2508
LC
1344 (define* (read-ungexp chr port #:optional native?)
1345 "Read an 'ungexp' or 'ungexp-splicing' form from PORT. When NATIVE? is
1346true, use 'ungexp-native' and 'ungexp-native-splicing' instead."
21b679f6
LC
1347 (define unquote-symbol
1348 (match (peek-char port)
1349 (#\@
1350 (read-char port)
667b2508
LC
1351 (if native?
1352 'ungexp-native-splicing
1353 'ungexp-splicing))
21b679f6 1354 (_
667b2508
LC
1355 (if native?
1356 'ungexp-native
1357 'ungexp))))
21b679f6
LC
1358
1359 (match (read port)
1360 ((? symbol? symbol)
1361 (let ((str (symbol->string symbol)))
1362 (match (string-index-right str #\:)
1363 (#f
1364 `(,unquote-symbol ,symbol))
1365 (colon
1366 (let ((name (string->symbol (substring str 0 colon)))
1367 (output (substring str (+ colon 1))))
1368 `(,unquote-symbol ,name ,output))))))
1369 (x
1370 `(,unquote-symbol ,x))))
1371
1372 (define (read-gexp chr port)
1373 "Read a 'gexp' form from PORT."
1374 `(gexp ,(read port)))
1375
1376 ;; Extend the reader
1377 (read-hash-extend #\~ read-gexp)
667b2508
LC
1378 (read-hash-extend #\$ read-ungexp)
1379 (read-hash-extend #\+ (cut read-ungexp <> <> #t)))
21b679f6
LC
1380
1381;;; gexp.scm ends here