gexp: Add 'with-imported-modules' macro.
[jackhill/guix/guix.git] / guix / gexp.scm
CommitLineData
21b679f6 1;;; GNU Guix --- Functional package management for GNU
7adf9b84 2;;; Copyright © 2014, 2015, 2016 Ludovic Courtès <ludo@gnu.org>
21b679f6
LC
3;;;
4;;; This file is part of GNU Guix.
5;;;
6;;; GNU Guix is free software; you can redistribute it and/or modify it
7;;; under the terms of the GNU General Public License as published by
8;;; the Free Software Foundation; either version 3 of the License, or (at
9;;; your option) any later version.
10;;;
11;;; GNU Guix is distributed in the hope that it will be useful, but
12;;; WITHOUT ANY WARRANTY; without even the implied warranty of
13;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14;;; GNU General Public License for more details.
15;;;
16;;; You should have received a copy of the GNU General Public License
17;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
18
19(define-module (guix gexp)
e87f0591 20 #:use-module (guix store)
21b679f6 21 #:use-module (guix monads)
e87f0591 22 #:use-module (guix derivations)
7adf9b84 23 #:use-module (guix grafts)
aa72d9af 24 #:use-module (guix utils)
21b679f6
LC
25 #:use-module (srfi srfi-1)
26 #:use-module (srfi srfi-9)
7560b00b 27 #:use-module (srfi srfi-9 gnu)
21b679f6
LC
28 #:use-module (srfi srfi-26)
29 #:use-module (ice-9 match)
30 #:export (gexp
31 gexp?
0bb9929e 32 with-imported-modules
0dbea56b
LC
33
34 gexp-input
35 gexp-input?
558e8b11 36
d9ae938f
LC
37 local-file
38 local-file?
74d441ab 39 local-file-file
9d3994f7 40 local-file-absolute-file-name
74d441ab
LC
41 local-file-name
42 local-file-recursive?
0dbea56b 43
558e8b11
LC
44 plain-file
45 plain-file?
46 plain-file-name
47 plain-file-content
48
91937029
LC
49 computed-file
50 computed-file?
51 computed-file-name
52 computed-file-gexp
53 computed-file-modules
54 computed-file-options
55
15a01c72
LC
56 program-file
57 program-file?
58 program-file-name
59 program-file-gexp
60 program-file-modules
61 program-file-guile
62
e1c153e0
LC
63 scheme-file
64 scheme-file?
65 scheme-file-name
66 scheme-file-gexp
67
21b679f6
LC
68 gexp->derivation
69 gexp->file
462a3fa3 70 gexp->script
aa72d9af 71 text-file*
b751cde3 72 mixed-text-file
aa72d9af
LC
73 imported-files
74 imported-modules
ff40e9b7
LC
75 compiled-modules
76
77 define-gexp-compiler
6b6298ae 78 gexp-compiler?
c2b84676 79 lower-object
6b6298ae
LC
80
81 lower-inputs))
21b679f6
LC
82
83;;; Commentary:
84;;;
85;;; This module implements "G-expressions", or "gexps". Gexps are like
86;;; S-expressions (sexps), with two differences:
87;;;
88;;; 1. References (un-quotations) to derivations or packages in a gexp are
667b2508
LC
89;;; replaced by the corresponding output file name; in addition, the
90;;; 'ungexp-native' unquote-like form allows code to explicitly refer to
91;;; the native code of a given package, in case of cross-compilation;
21b679f6
LC
92;;;
93;;; 2. Gexps embed information about the derivations they refer to.
94;;;
95;;; Gexps make it easy to write to files Scheme code that refers to store
96;;; items, or to write Scheme code to build derivations.
97;;;
98;;; Code:
99
100;; "G expressions".
101(define-record-type <gexp>
0bb9929e 102 (make-gexp references modules proc)
21b679f6 103 gexp?
affd7761 104 (references gexp-references) ;list of <gexp-input>
0bb9929e 105 (modules gexp-self-modules) ;list of module names
affd7761 106 (proc gexp-proc)) ;procedure
21b679f6 107
7560b00b
LC
108(define (write-gexp gexp port)
109 "Write GEXP on PORT."
110 (display "#<gexp " port)
2cf0ea0d
LC
111
112 ;; Try to write the underlying sexp. Now, this trick doesn't work when
113 ;; doing things like (ungexp-splicing (gexp ())) because GEXP's procedure
114 ;; tries to use 'append' on that, which fails with wrong-type-arg.
115 (false-if-exception
667b2508 116 (write (apply (gexp-proc gexp)
affd7761 117 (gexp-references gexp))
667b2508 118 port))
7560b00b
LC
119 (format port " ~a>"
120 (number->string (object-address gexp) 16)))
121
122(set-record-type-printer! <gexp> write-gexp)
123
bcb13287
LC
124\f
125;;;
126;;; Methods.
127;;;
128
129;; Compiler for a type of objects that may be introduced in a gexp.
130(define-record-type <gexp-compiler>
131 (gexp-compiler predicate lower)
132 gexp-compiler?
133 (predicate gexp-compiler-predicate)
134 (lower gexp-compiler-lower))
135
136(define %gexp-compilers
137 ;; List of <gexp-compiler>.
138 '())
139
140(define (register-compiler! compiler)
141 "Register COMPILER as a gexp compiler."
142 (set! %gexp-compilers (cons compiler %gexp-compilers)))
143
144(define (lookup-compiler object)
145 "Search a compiler for OBJECT. Upon success, return the three argument
146procedure to lower it; otherwise return #f."
147 (any (match-lambda
148 (($ <gexp-compiler> predicate lower)
149 (and (predicate object) lower)))
150 %gexp-compilers))
151
c2b84676
LC
152(define* (lower-object obj
153 #:optional (system (%current-system))
154 #:key target)
155 "Return as a value in %STORE-MONAD the derivation or store item
156corresponding to OBJ for SYSTEM, cross-compiling for TARGET if TARGET is true.
157OBJ must be an object that has an associated gexp compiler, such as a
158<package>."
159 (let ((lower (lookup-compiler obj)))
160 (lower obj system target)))
161
bcb13287
LC
162(define-syntax-rule (define-gexp-compiler (name (param predicate)
163 system target)
164 body ...)
165 "Define NAME as a compiler for objects matching PREDICATE encountered in
166gexps. BODY must return a derivation for PARAM, an object that matches
167PREDICATE, for SYSTEM and TARGET (the latter of which is #f except when
168cross-compiling.)"
169 (begin
170 (define name
171 (gexp-compiler predicate
172 (lambda (param system target)
173 body ...)))
174 (register-compiler! name)))
175
2924f0d6
LC
176(define-gexp-compiler (derivation-compiler (drv derivation?) system target)
177 ;; Derivations are the lowest-level representation, so this is the identity
178 ;; compiler.
179 (with-monad %store-monad
180 (return drv)))
181
bcb13287 182\f
d9ae938f 183;;;
558e8b11 184;;; File declarations.
d9ae938f
LC
185;;;
186
9d3994f7
LC
187;; A local file name. FILE is the file name the user entered, which can be a
188;; relative file name, and ABSOLUTE is a promise that computes its canonical
189;; absolute file name. We keep it in a promise to compute it lazily and avoid
190;; repeated 'stat' calls.
d9ae938f 191(define-record-type <local-file>
0687fc9c 192 (%%local-file file absolute name recursive? select?)
d9ae938f
LC
193 local-file?
194 (file local-file-file) ;string
9d3994f7 195 (absolute %local-file-absolute-file-name) ;promise string
d9ae938f 196 (name local-file-name) ;string
0687fc9c
LC
197 (recursive? local-file-recursive?) ;Boolean
198 (select? local-file-select?)) ;string stat -> Boolean
199
200(define (true file stat) #t)
d9ae938f 201
9d3994f7 202(define* (%local-file file promise #:optional (name (basename file))
0687fc9c 203 #:key recursive? (select? true))
9d3994f7
LC
204 ;; This intermediate procedure is part of our ABI, but the underlying
205 ;; %%LOCAL-FILE is not.
0687fc9c 206 (%%local-file file promise name recursive? select?))
9d3994f7 207
9d3994f7
LC
208(define (absolute-file-name file directory)
209 "Return the canonical absolute file name for FILE, which lives in the
210vicinity of DIRECTORY."
211 (canonicalize-path
212 (cond ((string-prefix? "/" file) file)
213 ((not directory) file)
214 ((string-prefix? "/" directory)
215 (string-append directory "/" file))
216 (else file))))
217
218(define-syntax-rule (local-file file rest ...)
d9ae938f 219 "Return an object representing local file FILE to add to the store; this
9d3994f7
LC
220object can be used in a gexp. If FILE is a relative file name, it is looked
221up relative to the source file where this form appears. FILE will be added to
222the store under NAME--by default the base name of FILE.
d9ae938f
LC
223
224When RECURSIVE? is true, the contents of FILE are added recursively; if FILE
225designates a flat file and RECURSIVE? is true, its contents are added, and its
226permission bits are kept.
227
0687fc9c
LC
228When RECURSIVE? is true, call (SELECT? FILE STAT) for each directory entry,
229where FILE is the entry's absolute file name and STAT is the result of
230'lstat'; exclude entries for which SELECT? does not return true.
231
d9ae938f 232This is the declarative counterpart of the 'interned-file' monadic procedure."
9d3994f7
LC
233 (%local-file file
234 (delay (absolute-file-name file (current-source-directory)))
235 rest ...))
236
237(define (local-file-absolute-file-name file)
238 "Return the absolute file name for FILE, a <local-file> instance. A
239'system-error' exception is raised if FILE could not be found."
240 (force (%local-file-absolute-file-name file)))
d9ae938f
LC
241
242(define-gexp-compiler (local-file-compiler (file local-file?) system target)
243 ;; "Compile" FILE by adding it to the store.
244 (match file
0687fc9c 245 (($ <local-file> file (= force absolute) name recursive? select?)
9d3994f7
LC
246 ;; Canonicalize FILE so that if it's a symlink, it is resolved. Failing
247 ;; to do that, when RECURSIVE? is #t, we could end up creating a dangling
248 ;; symlink in the store, and when RECURSIVE? is #f 'add-to-store' would
249 ;; just throw an error, both of which are inconvenient.
0687fc9c
LC
250 (interned-file absolute name
251 #:recursive? recursive? #:select? select?))))
d9ae938f 252
558e8b11
LC
253(define-record-type <plain-file>
254 (%plain-file name content references)
255 plain-file?
256 (name plain-file-name) ;string
257 (content plain-file-content) ;string
258 (references plain-file-references)) ;list (currently unused)
259
260(define (plain-file name content)
261 "Return an object representing a text file called NAME with the given
262CONTENT (a string) to be added to the store.
263
264This is the declarative counterpart of 'text-file'."
265 ;; XXX: For now just ignore 'references' because it's not clear how to use
266 ;; them in a declarative context.
267 (%plain-file name content '()))
268
269(define-gexp-compiler (plain-file-compiler (file plain-file?) system target)
270 ;; "Compile" FILE by adding it to the store.
271 (match file
272 (($ <plain-file> name content references)
273 (text-file name content references))))
274
91937029
LC
275(define-record-type <computed-file>
276 (%computed-file name gexp modules options)
277 computed-file?
278 (name computed-file-name) ;string
279 (gexp computed-file-gexp) ;gexp
280 (modules computed-file-modules) ;list of module names
281 (options computed-file-options)) ;list of arguments
282
283(define* (computed-file name gexp
284 #:key (modules '()) (options '(#:local-build? #t)))
285 "Return an object representing the store item NAME, a file or directory
286computed by GEXP. MODULES specifies the set of modules visible in the
287execution context of GEXP. OPTIONS is a list of additional arguments to pass
288to 'gexp->derivation'.
289
290This is the declarative counterpart of 'gexp->derivation'."
291 (%computed-file name gexp modules options))
292
293(define-gexp-compiler (computed-file-compiler (file computed-file?)
294 system target)
295 ;; Compile FILE by returning a derivation whose build expression is its
296 ;; gexp.
297 (match file
298 (($ <computed-file> name gexp modules options)
299 (apply gexp->derivation name gexp #:modules modules options))))
300
15a01c72
LC
301(define-record-type <program-file>
302 (%program-file name gexp modules guile)
303 program-file?
304 (name program-file-name) ;string
305 (gexp program-file-gexp) ;gexp
306 (modules program-file-modules) ;list of module names
307 (guile program-file-guile)) ;package
308
309(define* (program-file name gexp
310 #:key (modules '()) (guile #f))
311 "Return an object representing the executable store item NAME that runs
312GEXP. GUILE is the Guile package used to execute that script, and MODULES is
313the list of modules visible to that script.
314
315This is the declarative counterpart of 'gexp->script'."
316 (%program-file name gexp modules guile))
317
318(define-gexp-compiler (program-file-compiler (file program-file?)
319 system target)
320 ;; Compile FILE by returning a derivation that builds the script.
321 (match file
322 (($ <program-file> name gexp modules guile)
323 (gexp->script name gexp
324 #:modules modules
325 #:guile (or guile (default-guile))))))
326
e1c153e0
LC
327(define-record-type <scheme-file>
328 (%scheme-file name gexp)
329 scheme-file?
330 (name scheme-file-name) ;string
331 (gexp scheme-file-gexp)) ;gexp
332
333(define* (scheme-file name gexp)
334 "Return an object representing the Scheme file NAME that contains GEXP.
335
336This is the declarative counterpart of 'gexp->file'."
337 (%scheme-file name gexp))
338
339(define-gexp-compiler (scheme-file-compiler (file scheme-file?)
340 system target)
341 ;; Compile FILE by returning a derivation that builds the file.
342 (match file
343 (($ <scheme-file> name gexp)
344 (gexp->file name gexp))))
345
d9ae938f 346\f
bcb13287
LC
347;;;
348;;; Inputs & outputs.
349;;;
350
e39d1461
LC
351;; The input of a gexp.
352(define-record-type <gexp-input>
0dbea56b 353 (%gexp-input thing output native?)
e39d1461
LC
354 gexp-input?
355 (thing gexp-input-thing) ;<package> | <origin> | <derivation> | ...
356 (output gexp-input-output) ;string
357 (native? gexp-input-native?)) ;Boolean
358
f7328634
LC
359(define (write-gexp-input input port)
360 (match input
361 (($ <gexp-input> thing output #f)
362 (format port "#<gexp-input ~s:~a>" thing output))
363 (($ <gexp-input> thing output #t)
364 (format port "#<gexp-input native ~s:~a>" thing output))))
365
366(set-record-type-printer! <gexp-input> write-gexp-input)
367
0dbea56b
LC
368(define* (gexp-input thing ;convenience procedure
369 #:optional (output "out")
370 #:key native?)
371 "Return a new <gexp-input> for the OUTPUT of THING; NATIVE? determines
372whether this should be considered a \"native\" input or not."
373 (%gexp-input thing output native?))
374
21b679f6
LC
375;; Reference to one of the derivation's outputs, for gexps used in
376;; derivations.
1e87da58
LC
377(define-record-type <gexp-output>
378 (gexp-output name)
379 gexp-output?
380 (name gexp-output-name))
21b679f6 381
f7328634
LC
382(define (write-gexp-output output port)
383 (match output
384 (($ <gexp-output> name)
385 (format port "#<gexp-output ~a>" name))))
386
387(set-record-type-printer! <gexp-output> write-gexp-output)
388
0bb9929e
LC
389(define (gexp-modules gexp)
390 "Return the list of Guile module names GEXP relies on."
391 (delete-duplicates
392 (append (gexp-self-modules gexp)
393 (append-map (match-lambda
394 (($ <gexp-input> (? gexp? exp))
395 (gexp-modules exp))
396 (($ <gexp-input> (lst ...))
397 (append-map (lambda (item)
398 (if (gexp? item)
399 (gexp-modules item)
400 '()))
401 lst))
402 (_
403 '()))
404 (gexp-references gexp)))))
405
21b679f6
LC
406(define raw-derivation
407 (store-lift derivation))
408
68a61e9f
LC
409(define* (lower-inputs inputs
410 #:key system target)
411 "Turn any package from INPUTS into a derivation for SYSTEM; return the
412corresponding input list as a monadic value. When TARGET is true, use it as
413the cross-compilation target triplet."
21b679f6
LC
414 (with-monad %store-monad
415 (sequence %store-monad
416 (map (match-lambda
2242ff45 417 (((? struct? thing) sub-drv ...)
c2b84676
LC
418 (mlet %store-monad ((drv (lower-object
419 thing system #:target target)))
2242ff45
LC
420 (return `(,drv ,@sub-drv))))
421 (input
422 (return input)))
21b679f6
LC
423 inputs))))
424
b53833b2
LC
425(define* (lower-reference-graphs graphs #:key system target)
426 "Given GRAPHS, a list of (FILE-NAME INPUT ...) lists for use as a
427#:reference-graphs argument, lower it such that each INPUT is replaced by the
428corresponding derivation."
429 (match graphs
430 (((file-names . inputs) ...)
431 (mlet %store-monad ((inputs (lower-inputs inputs
432 #:system system
433 #:target target)))
434 (return (map cons file-names inputs))))))
435
c8351d9a
LC
436(define* (lower-references lst #:key system target)
437 "Based on LST, a list of output names and packages, return a list of output
438names and file names suitable for the #:allowed-references argument to
439'derivation'."
440 ;; XXX: Currently outputs other than "out" are not supported, and things
441 ;; other than packages aren't either.
442 (with-monad %store-monad
443 (define lower
444 (match-lambda
445 ((? string? output)
446 (return output))
accb682c 447 (($ <gexp-input> thing output native?)
c2b84676
LC
448 (mlet %store-monad ((drv (lower-object thing system
449 #:target (if native?
450 #f target))))
accb682c 451 (return (derivation->output-path drv output))))
bcb13287 452 (thing
c2b84676
LC
453 (mlet %store-monad ((drv (lower-object thing system
454 #:target target)))
c8351d9a
LC
455 (return (derivation->output-path drv))))))
456
457 (sequence %store-monad (map lower lst))))
458
ff40e9b7
LC
459(define default-guile-derivation
460 ;; Here we break the abstraction by talking to the higher-level layer.
461 ;; Thus, do the resolution lazily to hide the circular dependency.
462 (let ((proc (delay
463 (let ((iface (resolve-interface '(guix packages))))
464 (module-ref iface 'default-guile-derivation)))))
465 (lambda (system)
466 ((force proc) system))))
467
21b679f6
LC
468(define* (gexp->derivation name exp
469 #:key
68a61e9f 470 system (target 'current)
21b679f6
LC
471 hash hash-algo recursive?
472 (env-vars '())
473 (modules '())
4684f301 474 (module-path %load-path)
21b679f6 475 (guile-for-build (%guile-for-build))
ce45eb4c 476 (graft? (%graft?))
21b679f6 477 references-graphs
3f4ecf32 478 allowed-references disallowed-references
c0468155 479 leaked-env-vars
0309e1b0
LC
480 local-build? (substitutable? #t)
481 (script-name (string-append name "-builder")))
21b679f6 482 "Return a derivation NAME that runs EXP (a gexp) with GUILE-FOR-BUILD (a
0309e1b0
LC
483derivation) on SYSTEM; EXP is stored in a file called SCRIPT-NAME. When
484TARGET is true, it is used as the cross-compilation target triplet for
485packages referred to by EXP.
21b679f6 486
0bb9929e
LC
487MODULES is deprecated in favor of 'with-imported-modules'. Its meaning is to
488make MODULES available in the evaluation context of EXP; MODULES is a list of
4684f301 489names of Guile modules searched in MODULE-PATH to be copied in the store,
21b679f6
LC
490compiled, and made available in the load path during the execution of
491EXP---e.g., '((guix build utils) (guix build gnu-build-system)).
492
ce45eb4c
LC
493GRAFT? determines whether packages referred to by EXP should be grafted when
494applicable.
495
b53833b2
LC
496When REFERENCES-GRAPHS is true, it must be a list of tuples of one of the
497following forms:
498
499 (FILE-NAME PACKAGE)
500 (FILE-NAME PACKAGE OUTPUT)
501 (FILE-NAME DERIVATION)
502 (FILE-NAME DERIVATION OUTPUT)
503 (FILE-NAME STORE-ITEM)
504
505The right-hand-side of each element of REFERENCES-GRAPHS is automatically made
506an input of the build process of EXP. In the build environment, each
507FILE-NAME contains the reference graph of the corresponding item, in a simple
508text format.
509
c8351d9a
LC
510ALLOWED-REFERENCES must be either #f or a list of output names and packages.
511In the latter case, the list denotes store items that the result is allowed to
512refer to. Any reference to another store item will lead to a build error.
3f4ecf32
LC
513Similarly for DISALLOWED-REFERENCES, which can list items that must not be
514referenced by the outputs.
b53833b2 515
21b679f6 516The other arguments are as for 'derivation'."
0bb9929e
LC
517 (define %modules
518 (delete-duplicates
519 (append modules (gexp-modules exp))))
21b679f6
LC
520 (define outputs (gexp-outputs exp))
521
b53833b2
LC
522 (define (graphs-file-names graphs)
523 ;; Return a list of (FILE-NAME . STORE-PATH) pairs made from GRAPHS.
524 (map (match-lambda
2924f0d6 525 ;; TODO: Remove 'derivation?' special cases.
b53833b2
LC
526 ((file-name (? derivation? drv))
527 (cons file-name (derivation->output-path drv)))
528 ((file-name (? derivation? drv) sub-drv)
529 (cons file-name (derivation->output-path drv sub-drv)))
530 ((file-name thing)
531 (cons file-name thing)))
532 graphs))
533
ce45eb4c
LC
534 (mlet* %store-monad (;; The following binding forces '%current-system' and
535 ;; '%current-target-system' to be looked up at >>=
536 ;; time.
537 (graft? (set-grafting graft?))
68a61e9f 538
5d098459 539 (system -> (or system (%current-system)))
68a61e9f
LC
540 (target -> (if (eq? target 'current)
541 (%current-target-system)
542 target))
667b2508 543 (normals (lower-inputs (gexp-inputs exp)
68a61e9f
LC
544 #:system system
545 #:target target))
667b2508
LC
546 (natives (lower-inputs (gexp-native-inputs exp)
547 #:system system
548 #:target #f))
549 (inputs -> (append normals natives))
68a61e9f
LC
550 (sexp (gexp->sexp exp
551 #:system system
552 #:target target))
0309e1b0 553 (builder (text-file script-name
21b679f6
LC
554 (object->string sexp)))
555 (modules (if (pair? %modules)
556 (imported-modules %modules
557 #:system system
4684f301 558 #:module-path module-path
21b679f6
LC
559 #:guile guile-for-build)
560 (return #f)))
561 (compiled (if (pair? %modules)
562 (compiled-modules %modules
563 #:system system
4684f301 564 #:module-path module-path
21b679f6
LC
565 #:guile guile-for-build)
566 (return #f)))
b53833b2
LC
567 (graphs (if references-graphs
568 (lower-reference-graphs references-graphs
569 #:system system
570 #:target target)
571 (return #f)))
c8351d9a
LC
572 (allowed (if allowed-references
573 (lower-references allowed-references
574 #:system system
575 #:target target)
576 (return #f)))
3f4ecf32
LC
577 (disallowed (if disallowed-references
578 (lower-references disallowed-references
579 #:system system
580 #:target target)
581 (return #f)))
21b679f6
LC
582 (guile (if guile-for-build
583 (return guile-for-build)
ff40e9b7 584 (default-guile-derivation system))))
ce45eb4c
LC
585 (mbegin %store-monad
586 (set-grafting graft?) ;restore the initial setting
587 (raw-derivation name
588 (string-append (derivation->output-path guile)
589 "/bin/guile")
590 `("--no-auto-compile"
591 ,@(if (pair? %modules)
592 `("-L" ,(derivation->output-path modules)
593 "-C" ,(derivation->output-path compiled))
594 '())
595 ,builder)
596 #:outputs outputs
597 #:env-vars env-vars
598 #:system system
599 #:inputs `((,guile)
600 (,builder)
601 ,@(if modules
602 `((,modules) (,compiled) ,@inputs)
603 inputs)
604 ,@(match graphs
605 (((_ . inputs) ...) inputs)
606 (_ '())))
607 #:hash hash #:hash-algo hash-algo #:recursive? recursive?
608 #:references-graphs (and=> graphs graphs-file-names)
609 #:allowed-references allowed
3f4ecf32 610 #:disallowed-references disallowed
c0468155 611 #:leaked-env-vars leaked-env-vars
4a6aeb67
LC
612 #:local-build? local-build?
613 #:substitutable? substitutable?))))
21b679f6 614
1123759b
LC
615(define* (gexp-inputs exp #:key native?)
616 "Return the input list for EXP. When NATIVE? is true, return only native
617references; otherwise, return only non-native references."
21b679f6
LC
618 (define (add-reference-inputs ref result)
619 (match ref
1123759b
LC
620 (($ <gexp-input> (? gexp? exp) _ #t)
621 (if native?
622 (append (gexp-inputs exp)
623 (gexp-inputs exp #:native? #t)
624 result)
625 result))
626 (($ <gexp-input> (? gexp? exp) _ #f)
627 (if native?
628 (append (gexp-inputs exp #:native? #t)
629 result)
630 (append (gexp-inputs exp)
631 result)))
e39d1461
LC
632 (($ <gexp-input> (? string? str))
633 (if (direct-store-path? str)
634 (cons `(,str) result)
21b679f6 635 result))
bcb13287
LC
636 (($ <gexp-input> (? struct? thing) output)
637 (if (lookup-compiler thing)
638 ;; THING is a derivation, or a package, or an origin, etc.
639 (cons `(,thing ,output) result)
640 result))
1123759b 641 (($ <gexp-input> (lst ...) output n?)
e39d1461
LC
642 (fold-right add-reference-inputs result
643 ;; XXX: For now, automatically convert LST to a list of
644 ;; gexp-inputs.
0dbea56b
LC
645 (map (match-lambda
646 ((? gexp-input? x) x)
1123759b 647 (x (%gexp-input x "out" (or n? native?))))
0dbea56b 648 lst)))
21b679f6
LC
649 (_
650 ;; Ignore references to other kinds of objects.
651 result)))
652
affd7761
LC
653 (define (native-input? x)
654 (and (gexp-input? x)
655 (gexp-input-native? x)))
656
21b679f6
LC
657 (fold-right add-reference-inputs
658 '()
1123759b 659 (if native?
affd7761
LC
660 (filter native-input? (gexp-references exp))
661 (remove native-input? (gexp-references exp)))))
667b2508
LC
662
663(define gexp-native-inputs
1123759b 664 (cut gexp-inputs <> #:native? #t))
21b679f6
LC
665
666(define (gexp-outputs exp)
667 "Return the outputs referred to by EXP as a list of strings."
668 (define (add-reference-output ref result)
669 (match ref
1e87da58 670 (($ <gexp-output> name)
21b679f6 671 (cons name result))
e39d1461 672 (($ <gexp-input> (? gexp? exp))
21b679f6 673 (append (gexp-outputs exp) result))
e39d1461
LC
674 (($ <gexp-input> (lst ...) output native?)
675 ;; XXX: Automatically convert LST.
0dbea56b
LC
676 (add-reference-output (map (match-lambda
677 ((? gexp-input? x) x)
678 (x (%gexp-input x "out" native?)))
679 lst)
e39d1461 680 result))
f9efe568
LC
681 ((lst ...)
682 (fold-right add-reference-output result lst))
21b679f6
LC
683 (_
684 result)))
685
7e75a673
LC
686 (delete-duplicates
687 (add-reference-output (gexp-references exp) '())))
21b679f6 688
68a61e9f
LC
689(define* (gexp->sexp exp #:key
690 (system (%current-system))
691 (target (%current-target-system)))
21b679f6
LC
692 "Return (monadically) the sexp corresponding to EXP for the given OUTPUT,
693and in the current monad setting (system type, etc.)"
667b2508 694 (define* (reference->sexp ref #:optional native?)
21b679f6
LC
695 (with-monad %store-monad
696 (match ref
1e87da58 697 (($ <gexp-output> output)
bfd9eed9
LC
698 ;; Output file names are not known in advance but the daemon defines
699 ;; an environment variable for each of them at build time, so use
700 ;; that trick.
701 (return `((@ (guile) getenv) ,output)))
e39d1461 702 (($ <gexp-input> (? gexp? exp) output n?)
667b2508
LC
703 (gexp->sexp exp
704 #:system system
e39d1461
LC
705 #:target (if (or n? native?) #f target)))
706 (($ <gexp-input> (refs ...) output n?)
667b2508 707 (sequence %store-monad
e39d1461
LC
708 (map (lambda (ref)
709 ;; XXX: Automatically convert REF to an gexp-input.
0dbea56b
LC
710 (reference->sexp
711 (if (gexp-input? ref)
712 ref
713 (%gexp-input ref "out" n?))
affd7761 714 (or n? native?)))
e39d1461 715 refs)))
bcb13287 716 (($ <gexp-input> (? struct? thing) output n?)
c2b84676
LC
717 (let ((target (if (or n? native?) #f target)))
718 (mlet %store-monad ((obj (lower-object thing system
719 #:target target)))
d9ae938f
LC
720 ;; OBJ must be either a derivation or a store file name.
721 (return (match obj
722 ((? derivation? drv)
723 (derivation->output-path drv output))
724 ((? string? file)
725 file))))))
e39d1461
LC
726 (($ <gexp-input> x)
727 (return x))
21b679f6
LC
728 (x
729 (return x)))))
730
731 (mlet %store-monad
732 ((args (sequence %store-monad
affd7761 733 (map reference->sexp (gexp-references exp)))))
21b679f6
LC
734 (return (apply (gexp-proc exp) args))))
735
21b679f6
LC
736(define (syntax-location-string s)
737 "Return a string representing the source code location of S."
738 (let ((props (syntax-source s)))
739 (if props
740 (let ((file (assoc-ref props 'filename))
741 (line (and=> (assoc-ref props 'line) 1+))
742 (column (assoc-ref props 'column)))
743 (if file
744 (simple-format #f "~a:~a:~a"
745 file line column)
746 (simple-format #f "~a:~a" line column)))
747 "<unknown location>")))
748
0bb9929e
LC
749(define-syntax-parameter current-imported-modules
750 ;; Current list of imported modules.
751 (identifier-syntax '()))
752
753(define-syntax-rule (with-imported-modules modules body ...)
754 "Mark the gexps defined in BODY... as requiring MODULES in their execution
755environment."
756 (syntax-parameterize ((current-imported-modules
757 (identifier-syntax modules)))
758 body ...))
759
21b679f6
LC
760(define-syntax gexp
761 (lambda (s)
762 (define (collect-escapes exp)
763 ;; Return all the 'ungexp' present in EXP.
764 (let loop ((exp exp)
765 (result '()))
607e1b51
LC
766 (syntax-case exp (ungexp
767 ungexp-splicing
768 ungexp-native
769 ungexp-native-splicing)
21b679f6
LC
770 ((ungexp _)
771 (cons exp result))
772 ((ungexp _ _)
773 (cons exp result))
774 ((ungexp-splicing _ ...)
775 (cons exp result))
607e1b51 776 ((ungexp-native _ ...)
667b2508
LC
777 (cons exp result))
778 ((ungexp-native-splicing _ ...)
779 (cons exp result))
780 ((exp0 exp ...)
781 (let ((result (loop #'exp0 result)))
782 (fold loop result #'(exp ...))))
783 (_
784 result))))
785
21b679f6
LC
786 (define (escape->ref exp)
787 ;; Turn 'ungexp' form EXP into a "reference".
667b2508
LC
788 (syntax-case exp (ungexp ungexp-splicing
789 ungexp-native ungexp-native-splicing
790 output)
21b679f6 791 ((ungexp output)
1e87da58 792 #'(gexp-output "out"))
21b679f6 793 ((ungexp output name)
1e87da58 794 #'(gexp-output name))
21b679f6 795 ((ungexp thing)
0dbea56b 796 #'(%gexp-input thing "out" #f))
21b679f6 797 ((ungexp drv-or-pkg out)
0dbea56b 798 #'(%gexp-input drv-or-pkg out #f))
21b679f6 799 ((ungexp-splicing lst)
0dbea56b 800 #'(%gexp-input lst "out" #f))
667b2508 801 ((ungexp-native thing)
0dbea56b 802 #'(%gexp-input thing "out" #t))
667b2508 803 ((ungexp-native drv-or-pkg out)
0dbea56b 804 #'(%gexp-input drv-or-pkg out #t))
667b2508 805 ((ungexp-native-splicing lst)
0dbea56b 806 #'(%gexp-input lst "out" #t))))
21b679f6 807
667b2508
LC
808 (define (substitute-ungexp exp substs)
809 ;; Given EXP, an 'ungexp' or 'ungexp-native' form, substitute it with
810 ;; the corresponding form in SUBSTS.
811 (match (assoc exp substs)
812 ((_ id)
813 id)
814 (_
815 #'(syntax-error "error: no 'ungexp' substitution"
816 #'ref))))
817
818 (define (substitute-ungexp-splicing exp substs)
819 (syntax-case exp ()
820 ((exp rest ...)
821 (match (assoc #'exp substs)
822 ((_ id)
823 (with-syntax ((id id))
824 #`(append id
825 #,(substitute-references #'(rest ...) substs))))
826 (_
827 #'(syntax-error "error: no 'ungexp-splicing' substitution"
828 #'ref))))))
829
21b679f6
LC
830 (define (substitute-references exp substs)
831 ;; Return a variant of EXP where all the cars of SUBSTS have been
832 ;; replaced by the corresponding cdr.
667b2508
LC
833 (syntax-case exp (ungexp ungexp-native
834 ungexp-splicing ungexp-native-splicing)
21b679f6 835 ((ungexp _ ...)
667b2508
LC
836 (substitute-ungexp exp substs))
837 ((ungexp-native _ ...)
838 (substitute-ungexp exp substs))
21b679f6 839 (((ungexp-splicing _ ...) rest ...)
667b2508
LC
840 (substitute-ungexp-splicing exp substs))
841 (((ungexp-native-splicing _ ...) rest ...)
842 (substitute-ungexp-splicing exp substs))
21b679f6
LC
843 ((exp0 exp ...)
844 #`(cons #,(substitute-references #'exp0 substs)
845 #,(substitute-references #'(exp ...) substs)))
846 (x #''x)))
847
848 (syntax-case s (ungexp output)
849 ((_ exp)
affd7761 850 (let* ((escapes (delete-duplicates (collect-escapes #'exp)))
21b679f6
LC
851 (formals (generate-temporaries escapes))
852 (sexp (substitute-references #'exp (zip escapes formals)))
affd7761
LC
853 (refs (map escape->ref escapes)))
854 #`(make-gexp (list #,@refs)
0bb9929e 855 current-imported-modules
21b679f6
LC
856 (lambda #,formals
857 #,sexp)))))))
858
859\f
aa72d9af
LC
860;;;
861;;; Module handling.
862;;;
863
df2d51f0
LC
864(define %utils-module
865 ;; This file provides 'mkdir-p', needed to implement 'imported-files' and
a9601e23
LC
866 ;; other primitives below. Note: We give the file name relative to this
867 ;; file you are currently reading; 'search-path' could return a file name
868 ;; relative to the current working directory.
869 (local-file "build/utils.scm"
df2d51f0 870 "build-utils.scm"))
aa72d9af
LC
871
872(define* (imported-files files
873 #:key (name "file-import")
874 (system (%current-system))
875 (guile (%guile-for-build)))
876 "Return a derivation that imports FILES into STORE. FILES must be a list
877of (FINAL-PATH . FILE-NAME) pairs; each FILE-NAME is read from the file
878system, imported, and appears under FINAL-PATH in the resulting store path."
879 (define file-pair
880 (match-lambda
881 ((final-path . file-name)
882 (mlet %store-monad ((file (interned-file file-name
883 (basename final-path))))
884 (return (list final-path file))))))
885
886 (mlet %store-monad ((files (sequence %store-monad
887 (map file-pair files))))
888 (define build
889 (gexp
890 (begin
df2d51f0 891 (primitive-load (ungexp %utils-module)) ;for 'mkdir-p'
aa72d9af
LC
892 (use-modules (ice-9 match))
893
aa72d9af
LC
894 (mkdir (ungexp output)) (chdir (ungexp output))
895 (for-each (match-lambda
896 ((final-path store-path)
897 (mkdir-p (dirname final-path))
898 (symlink store-path final-path)))
899 '(ungexp files)))))
900
901 ;; TODO: Pass FILES as an environment variable so that BUILD remains
902 ;; exactly the same regardless of FILES: less disk space, and fewer
903 ;; 'add-to-store' RPCs.
904 (gexp->derivation name build
905 #:system system
906 #:guile-for-build guile
907 #:local-build? #t)))
908
aa72d9af
LC
909(define* (imported-modules modules
910 #:key (name "module-import")
911 (system (%current-system))
912 (guile (%guile-for-build))
913 (module-path %load-path))
914 "Return a derivation that contains the source files of MODULES, a list of
915module names such as `(ice-9 q)'. All of MODULES must be in the MODULE-PATH
916search path."
917 ;; TODO: Determine the closure of MODULES, build the `.go' files,
918 ;; canonicalize the source files through read/write, etc.
919 (let ((files (map (lambda (m)
6985335f 920 (let ((f (module->source-file-name m)))
aa72d9af
LC
921 (cons f (search-path* module-path f))))
922 modules)))
923 (imported-files files #:name name #:system system
924 #:guile guile)))
925
926(define* (compiled-modules modules
927 #:key (name "module-import-compiled")
928 (system (%current-system))
929 (guile (%guile-for-build))
930 (module-path %load-path))
931 "Return a derivation that builds a tree containing the `.go' files
932corresponding to MODULES. All the MODULES are built in a context where
933they can refer to each other."
934 (mlet %store-monad ((modules (imported-modules modules
935 #:system system
936 #:guile guile
937 #:module-path
938 module-path)))
939 (define build
940 (gexp
941 (begin
df2d51f0
LC
942 (primitive-load (ungexp %utils-module)) ;for 'mkdir-p'
943
aa72d9af 944 (use-modules (ice-9 ftw)
aa72d9af
LC
945 (srfi srfi-26)
946 (system base compile))
947
aa72d9af
LC
948 (define (regular? file)
949 (not (member file '("." ".."))))
950
951 (define (process-directory directory output)
952 (let ((entries (map (cut string-append directory "/" <>)
953 (scandir directory regular?))))
954 (for-each (lambda (entry)
955 (if (file-is-directory? entry)
956 (let ((output (string-append output "/"
957 (basename entry))))
958 (mkdir-p output)
959 (process-directory entry output))
960 (let* ((base (string-drop-right
961 (basename entry)
962 4)) ;.scm
963 (output (string-append output "/" base
964 ".go")))
965 (compile-file entry
966 #:output-file output
967 #:opts
968 %auto-compilation-options))))
969 entries)))
970
971 (set! %load-path (cons (ungexp modules) %load-path))
972 (mkdir (ungexp output))
973 (chdir (ungexp modules))
974 (process-directory "." (ungexp output)))))
975
976 ;; TODO: Pass MODULES as an environment variable.
977 (gexp->derivation name build
978 #:system system
979 #:guile-for-build guile
980 #:local-build? #t)))
981
982\f
21b679f6
LC
983;;;
984;;; Convenience procedures.
985;;;
986
53e89b17
LC
987(define (default-guile)
988 ;; Lazily resolve 'guile-final'. This module must not refer to (gnu …)
989 ;; modules directly, to avoid circular dependencies, hence this hack.
bdb36958 990 (module-ref (resolve-interface '(gnu packages commencement))
53e89b17
LC
991 'guile-final))
992
21b679f6 993(define* (gexp->script name exp
53e89b17 994 #:key (modules '()) (guile (default-guile)))
21b679f6
LC
995 "Return an executable script NAME that runs EXP using GUILE with MODULES in
996its search path."
0bb9929e
LC
997 (define %modules
998 (append (gexp-modules exp) modules))
999
1000 (mlet %store-monad ((modules (imported-modules %modules))
1001 (compiled (compiled-modules %modules)))
21b679f6
LC
1002 (gexp->derivation name
1003 (gexp
1004 (call-with-output-file (ungexp output)
1005 (lambda (port)
c17b5ab4
LC
1006 ;; Note: that makes a long shebang. When the store
1007 ;; is /gnu/store, that fits within the 128-byte
1008 ;; limit imposed by Linux, but that may go beyond
1009 ;; when running tests.
21b679f6
LC
1010 (format port
1011 "#!~a/bin/guile --no-auto-compile~%!#~%"
1012 (ungexp guile))
4a4cbd0b
LC
1013
1014 ;; Write the 'eval-when' form so that it can be
1015 ;; compiled.
21b679f6 1016 (write
4a4cbd0b
LC
1017 '(eval-when (expand load eval)
1018 (set! %load-path
1019 (cons (ungexp modules) %load-path))
1020 (set! %load-compiled-path
1021 (cons (ungexp compiled)
1022 %load-compiled-path)))
21b679f6
LC
1023 port)
1024 (write '(ungexp exp) port)
1025 (chmod port #o555)))))))
1026
1027(define (gexp->file name exp)
1028 "Return a derivation that builds a file NAME containing EXP."
1029 (gexp->derivation name
1030 (gexp
1031 (call-with-output-file (ungexp output)
1032 (lambda (port)
dc254e05 1033 (write '(ungexp exp) port))))
851b6f62
LC
1034 #:local-build? #t
1035 #:substitutable? #f))
21b679f6 1036
462a3fa3
LC
1037(define* (text-file* name #:rest text)
1038 "Return as a monadic value a derivation that builds a text file containing
d9ae938f
LC
1039all of TEXT. TEXT may list, in addition to strings, objects of any type that
1040can be used in a gexp: packages, derivations, local file objects, etc. The
1041resulting store file holds references to all these."
462a3fa3
LC
1042 (define builder
1043 (gexp (call-with-output-file (ungexp output "out")
1044 (lambda (port)
1045 (display (string-append (ungexp-splicing text)) port)))))
1046
851b6f62
LC
1047 (gexp->derivation name builder
1048 #:local-build? #t
1049 #:substitutable? #f))
462a3fa3 1050
b751cde3
LC
1051(define* (mixed-text-file name #:rest text)
1052 "Return an object representing store file NAME containing TEXT. TEXT is a
1053sequence of strings and file-like objects, as in:
1054
1055 (mixed-text-file \"profile\"
1056 \"export PATH=\" coreutils \"/bin:\" grep \"/bin\")
1057
1058This is the declarative counterpart of 'text-file*'."
1059 (define build
1060 (gexp (call-with-output-file (ungexp output "out")
1061 (lambda (port)
1062 (display (string-append (ungexp-splicing text)) port)))))
1063
1064 (computed-file name build))
1065
21b679f6
LC
1066\f
1067;;;
1068;;; Syntactic sugar.
1069;;;
1070
1071(eval-when (expand load eval)
667b2508
LC
1072 (define* (read-ungexp chr port #:optional native?)
1073 "Read an 'ungexp' or 'ungexp-splicing' form from PORT. When NATIVE? is
1074true, use 'ungexp-native' and 'ungexp-native-splicing' instead."
21b679f6
LC
1075 (define unquote-symbol
1076 (match (peek-char port)
1077 (#\@
1078 (read-char port)
667b2508
LC
1079 (if native?
1080 'ungexp-native-splicing
1081 'ungexp-splicing))
21b679f6 1082 (_
667b2508
LC
1083 (if native?
1084 'ungexp-native
1085 'ungexp))))
21b679f6
LC
1086
1087 (match (read port)
1088 ((? symbol? symbol)
1089 (let ((str (symbol->string symbol)))
1090 (match (string-index-right str #\:)
1091 (#f
1092 `(,unquote-symbol ,symbol))
1093 (colon
1094 (let ((name (string->symbol (substring str 0 colon)))
1095 (output (substring str (+ colon 1))))
1096 `(,unquote-symbol ,name ,output))))))
1097 (x
1098 `(,unquote-symbol ,x))))
1099
1100 (define (read-gexp chr port)
1101 "Read a 'gexp' form from PORT."
1102 `(gexp ,(read port)))
1103
1104 ;; Extend the reader
1105 (read-hash-extend #\~ read-gexp)
667b2508
LC
1106 (read-hash-extend #\$ read-ungexp)
1107 (read-hash-extend #\+ (cut read-ungexp <> <> #t)))
21b679f6
LC
1108
1109;;; gexp.scm ends here