Merge branch 'master' into staging
[jackhill/guix/guix.git] / guix / self.scm
1 ;;; GNU Guix --- Functional package management for GNU
2 ;;; Copyright © 2017, 2018 Ludovic Courtès <ludo@gnu.org>
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 self)
20 #:use-module (guix config)
21 #:use-module (guix i18n)
22 #:use-module (guix modules)
23 #:use-module (guix gexp)
24 #:use-module (guix store)
25 #:use-module (guix monads)
26 #:use-module (guix discovery)
27 #:use-module (guix packages)
28 #:use-module (guix sets)
29 #:use-module (guix modules)
30 #:use-module ((guix build utils) #:select (find-files))
31 #:use-module ((guix build compile) #:select (%lightweight-optimizations))
32 #:use-module (srfi srfi-1)
33 #:use-module (srfi srfi-9)
34 #:use-module (ice-9 match)
35 #:export (make-config.scm
36 whole-package ;for internal use in 'guix pull'
37 compiled-guix
38 guix-derivation
39 reload-guix))
40
41 \f
42 ;;;
43 ;;; Dependency handling.
44 ;;;
45
46 (define* (false-if-wrong-guile package
47 #:optional (guile-version (effective-version)))
48 "Return #f if PACKAGE depends on the \"wrong\" major version of Guile (e.g.,
49 2.0 instead of 2.2), otherwise return PACKAGE."
50 (let ((guile (any (match-lambda
51 ((label (? package? dep) _ ...)
52 (and (string=? (package-name dep) "guile")
53 dep)))
54 (package-direct-inputs package))))
55 (and (or (not guile)
56 (string-prefix? guile-version
57 (package-version guile)))
58 package)))
59
60 (define (package-for-guile guile-version . names)
61 "Return the package with one of the given NAMES that depends on
62 GUILE-VERSION (\"2.0\" or \"2.2\"), or #f if none of the packages matches."
63 (let loop ((names names))
64 (match names
65 (()
66 #f)
67 ((name rest ...)
68 (match (specification->package name)
69 (#f
70 (loop rest))
71 ((? package? package)
72 (or (false-if-wrong-guile package guile-version)
73 (loop rest))))))))
74
75 (define specification->package
76 ;; Use our own variant of that procedure because that of (gnu packages)
77 ;; would traverse all the .scm files, which is wasteful.
78 (let ((ref (lambda (module variable)
79 (module-ref (resolve-interface module) variable))))
80 (match-lambda
81 ("guile" (ref '(gnu packages commencement) 'guile-final))
82 ("guile-json" (ref '(gnu packages guile) 'guile-json))
83 ("guile-ssh" (ref '(gnu packages ssh) 'guile-ssh))
84 ("guile-git" (ref '(gnu packages guile) 'guile-git))
85 ("guile-sqlite3" (ref '(gnu packages guile) 'guile-sqlite3))
86 ("guile-gcrypt" (ref '(gnu packages gnupg) 'guile-gcrypt))
87 ("gnutls" (ref '(gnu packages tls) 'gnutls))
88 ("zlib" (ref '(gnu packages compression) 'zlib))
89 ("gzip" (ref '(gnu packages compression) 'gzip))
90 ("bzip2" (ref '(gnu packages compression) 'bzip2))
91 ("xz" (ref '(gnu packages compression) 'xz))
92 ("guile2.0-json" (ref '(gnu packages guile) 'guile2.0-json))
93 ("guile2.0-ssh" (ref '(gnu packages ssh) 'guile2.0-ssh))
94 ("guile2.0-git" (ref '(gnu packages guile) 'guile2.0-git))
95 ;; XXX: No "guile2.0-sqlite3".
96 ("guile2.0-gnutls" (ref '(gnu packages tls) 'gnutls/guile-2.0))
97 (_ #f)))) ;no such package
98
99 \f
100 ;;;
101 ;;; Derivations.
102 ;;;
103
104 ;; Node in a DAG of build tasks. Each node maps to a derivation, but it's
105 ;; easier to express things this way.
106 (define-record-type <node>
107 (node name modules source dependencies compiled)
108 node?
109 (name node-name) ;string
110 (modules node-modules) ;list of module names
111 (source node-source) ;list of source files
112 (dependencies node-dependencies) ;list of nodes
113 (compiled node-compiled)) ;node -> lowerable object
114
115 ;; File mappings are essentially an alist as passed to 'imported-files'.
116 (define-record-type <file-mapping>
117 (file-mapping name alist)
118 file-mapping?
119 (name file-mapping-name)
120 (alist file-mapping-alist))
121
122 (define-gexp-compiler (file-mapping-compiler (mapping <file-mapping>)
123 system target)
124 ;; Here we use 'imported-files', which can arrange to directly import all
125 ;; the files instead of creating a derivation, when possible.
126 (imported-files (map (match-lambda
127 ((destination (? local-file? file))
128 (cons destination
129 (local-file-absolute-file-name file)))
130 ((destination source)
131 (cons destination source))) ;silliness
132 (file-mapping-alist mapping))
133 #:name (file-mapping-name mapping)
134 #:system system))
135
136 (define (node-fold proc init nodes)
137 (let loop ((nodes nodes)
138 (visited (setq))
139 (result init))
140 (match nodes
141 (() result)
142 ((head tail ...)
143 (if (set-contains? visited head)
144 (loop tail visited result)
145 (loop tail (set-insert head visited)
146 (proc head result)))))))
147
148 (define (node-modules/recursive nodes)
149 (node-fold (lambda (node modules)
150 (append (node-modules node) modules))
151 '()
152 nodes))
153
154 (define* (closure modules #:optional (except '()))
155 (source-module-closure modules
156 #:select?
157 (match-lambda
158 (('guix 'config)
159 #f)
160 ((and module
161 (or ('guix _ ...) ('gnu _ ...)))
162 (not (member module except)))
163 (rest #f))))
164
165 (define module->import
166 ;; Return a file-name/file-like object pair for the specified module and
167 ;; suitable for 'imported-files'.
168 (match-lambda
169 ((module '=> thing)
170 (let ((file (module-name->file-name module)))
171 (list file thing)))
172 (module
173 (let ((file (module-name->file-name module)))
174 (list file
175 (local-file (search-path %load-path file)))))))
176
177 (define* (scheme-node name modules #:optional (dependencies '())
178 #:key (extra-modules '()) (extra-files '())
179 (extensions '())
180 parallel? guile-for-build)
181 "Return a node that builds the given Scheme MODULES, and depends on
182 DEPENDENCIES (a list of nodes). EXTRA-MODULES is a list of additional modules
183 added to the source, and EXTRA-FILES is a list of additional files.
184 EXTENSIONS is a set of full-blown Guile packages (e.g., 'guile-json') that
185 must be present in the search path."
186 (let* ((modules (append extra-modules
187 (closure modules
188 (node-modules/recursive dependencies))))
189 (module-files (map module->import modules))
190 (source (file-mapping (string-append name "-source")
191 (append module-files extra-files))))
192 (node name modules source dependencies
193 (compiled-modules name source
194 (map car module-files)
195 (map node-source dependencies)
196 (map node-compiled dependencies)
197 #:extensions extensions
198 #:parallel? parallel?
199 #:guile-for-build guile-for-build))))
200
201 (define (file-imports directory sub-directory pred)
202 "List all the files matching PRED under DIRECTORY/SUB-DIRECTORY. Return a
203 list of file-name/file-like objects suitable as inputs to 'imported-files'."
204 (map (lambda (file)
205 (list (string-drop file (+ 1 (string-length directory)))
206 (local-file file #:recursive? #t)))
207 (find-files (string-append directory "/" sub-directory) pred)))
208
209 (define* (file-append* item file #:key (recursive? #t))
210 "Return FILE within ITEM, which may be a file name or a file-like object.
211 When ITEM is a plain file name (a string), simply return a 'local-file'
212 record with the new file name."
213 (match item
214 ((? string?)
215 ;; This is the optimal case: we return a new "source". Thus, a
216 ;; derivation that depends on this sub-directory does not depend on ITEM
217 ;; itself.
218 (local-file (string-append item "/" file)
219 #:recursive? recursive?))
220 ;; TODO: Add 'local-file?' case.
221 (_
222 ;; In this case, anything that refers to the result also depends on ITEM,
223 ;; which isn't great.
224 (file-append item "/" file))))
225
226 (define* (locale-data source domain
227 #:optional (directory domain))
228 "Return the locale data from 'po/DIRECTORY' in SOURCE, corresponding to
229 DOMAIN, a gettext domain."
230 (define gettext
231 (module-ref (resolve-interface '(gnu packages gettext))
232 'gettext-minimal))
233
234 (define build
235 (with-imported-modules '((guix build utils))
236 #~(begin
237 (use-modules (guix build utils)
238 (srfi srfi-26)
239 (ice-9 match) (ice-9 ftw))
240
241 (define po-directory
242 #+(file-append* source (string-append "po/" directory)))
243
244 (define (compile language)
245 (let ((gmo (string-append #$output "/" language "/LC_MESSAGES/"
246 #$domain ".mo")))
247 (mkdir-p (dirname gmo))
248 (invoke #+(file-append gettext "/bin/msgfmt")
249 "-c" "--statistics" "--verbose"
250 "-o" gmo
251 (string-append po-directory "/" language ".po"))))
252
253 (define (linguas)
254 ;; Return the list of languages. Note: don't read 'LINGUAS'
255 ;; because it contains things like 'en@boldquot' that do not have
256 ;; a corresponding .po file.
257 (map (cut basename <> ".po")
258 (scandir po-directory
259 (cut string-suffix? ".po" <>))))
260
261 (for-each compile (linguas)))))
262
263 (computed-file (string-append "guix-locale-" domain)
264 build))
265
266 (define (info-manual source)
267 "Return the Info manual built from SOURCE."
268 (define texinfo
269 (module-ref (resolve-interface '(gnu packages texinfo))
270 'texinfo))
271
272 (define graphviz
273 (module-ref (resolve-interface '(gnu packages graphviz))
274 'graphviz))
275
276 (define glibc-utf8-locales
277 (module-ref (resolve-interface '(gnu packages base))
278 'glibc-utf8-locales))
279
280 (define documentation
281 (file-append* source "doc"))
282
283 (define examples
284 (file-append* source "gnu/system/examples"))
285
286 (define build
287 (with-imported-modules '((guix build utils))
288 #~(begin
289 (use-modules (guix build utils))
290
291 (mkdir #$output)
292
293 ;; Create 'version.texi'.
294 ;; XXX: Can we use a more meaningful version string yet one that
295 ;; doesn't change at each commit?
296 (call-with-output-file "version.texi"
297 (lambda (port)
298 (let ((version "0.0-git"))
299 (format port "
300 @set UPDATED 1 January 1970
301 @set UPDATED-MONTH January 1970
302 @set EDITION ~a
303 @set VERSION ~a\n" version version))))
304
305 ;; Copy configuration templates that the manual includes.
306 (for-each (lambda (template)
307 (copy-file template
308 (string-append
309 "os-config-"
310 (basename template ".tmpl")
311 ".texi")))
312 (find-files #$examples "\\.tmpl$"))
313
314 ;; Build graphs.
315 (mkdir-p (string-append #$output "/images"))
316 (for-each (lambda (dot-file)
317 (invoke #+(file-append graphviz "/bin/dot")
318 "-Tpng" "-Gratio=.9" "-Gnodesep=.005"
319 "-Granksep=.00005" "-Nfontsize=9"
320 "-Nheight=.1" "-Nwidth=.1"
321 "-o" (string-append #$output "/images/"
322 (basename dot-file ".dot")
323 ".png")
324 dot-file))
325 (find-files (string-append #$documentation "/images")
326 "\\.dot$"))
327
328 ;; Copy other PNGs.
329 (for-each (lambda (png-file)
330 (install-file png-file
331 (string-append #$output "/images")))
332 (find-files (string-append #$documentation "/images")
333 "\\.png$"))
334
335 ;; Finally build the manual. Copy it the Texinfo files to $PWD and
336 ;; add a symlink to the 'images' directory so that 'makeinfo' can
337 ;; see those images and produce image references in the Info output.
338 (copy-recursively #$documentation "."
339 #:log (%make-void-port "w"))
340 (delete-file-recursively "images")
341 (symlink (string-append #$output "/images") "images")
342
343 ;; Provide UTF-8 locales needed by the 'xspara.c' code in makeinfo.
344 (setenv "GUIX_LOCPATH"
345 #+(file-append glibc-utf8-locales "/lib/locale"))
346
347 (for-each (lambda (texi)
348 (unless (string=? "guix.texi" texi)
349 ;; Create 'version-LL.texi'.
350 (let* ((base (basename texi ".texi"))
351 (dot (string-index base #\.))
352 (tag (string-drop base (+ 1 dot))))
353 (symlink "version.texi"
354 (string-append "version-" tag ".texi"))))
355
356 (invoke #+(file-append texinfo "/bin/makeinfo")
357 texi "-I" #$documentation
358 "-I" "."
359 "-o" (string-append #$output "/"
360 (basename texi ".texi")
361 ".info")))
362 (cons "guix.texi"
363 (find-files "." "^guix\\.[a-z]{2}\\.texi$"))))))
364
365 (computed-file "guix-manual" build))
366
367 (define* (guix-command modules #:optional compiled-modules
368 #:key source (dependencies '())
369 guile (guile-version (effective-version)))
370 "Return the 'guix' command such that it adds MODULES and DEPENDENCIES in its
371 load path."
372 (define source-directories
373 (map (lambda (package)
374 (file-append package "/share/guile/site/"
375 guile-version))
376 dependencies))
377
378 (define object-directories
379 (map (lambda (package)
380 (file-append package "/lib/guile/"
381 guile-version "/site-ccache"))
382 dependencies))
383
384 (program-file "guix-command"
385 #~(begin
386 (set! %load-path
387 (append (filter file-exists? '#$source-directories)
388 %load-path))
389
390 (set! %load-compiled-path
391 (append (filter file-exists? '#$object-directories)
392 %load-compiled-path))
393
394 (set! %load-path (cons #$modules %load-path))
395 (set! %load-compiled-path
396 (cons (or #$compiled-modules #$modules)
397 %load-compiled-path))
398
399 (let ((guix-main (module-ref (resolve-interface '(guix ui))
400 'guix-main)))
401 #$(if source
402 #~(begin
403 (bindtextdomain "guix"
404 #$(locale-data source "guix"))
405 (bindtextdomain "guix-packages"
406 #$(locale-data source
407 "guix-packages"
408 "packages")))
409 #t)
410
411 ;; XXX: It would be more convenient to change it to:
412 ;; (exit (apply guix-main (command-line)))
413 (apply guix-main (command-line))))
414 #:guile guile))
415
416 (define (miscellaneous-files source)
417 "Return data files taken from SOURCE."
418 (file-mapping "guix-misc"
419 `(("etc/bash_completion.d/guix"
420 ,(file-append* source "/etc/completion/bash/guix"))
421 ("etc/bash_completion.d/guix-daemon"
422 ,(file-append* source "/etc/completion/bash/guix-daemon"))
423 ("share/zsh/site-functions/_guix"
424 ,(file-append* source "/etc/completion/zsh/_guix"))
425 ("share/fish/vendor_completions.d/guix.fish"
426 ,(file-append* source "/etc/completion/fish/guix.fish"))
427 ("share/guix/hydra.gnu.org.pub"
428 ,(file-append* source
429 "/etc/substitutes/hydra.gnu.org.pub"))
430 ("share/guix/berlin.guixsd.org.pub"
431 ,(file-append* source "/etc/substitutes/berlin.guixsd.org.pub")))))
432
433 (define* (whole-package name modules dependencies
434 #:key
435 (guile-version (effective-version))
436 compiled-modules
437 info daemon miscellany
438 guile
439 (command (guix-command modules
440 #:dependencies dependencies
441 #:guile guile
442 #:guile-version guile-version)))
443 "Return the whole Guix package NAME that uses MODULES, a derivation of all
444 the modules, and DEPENDENCIES, a list of packages depended on. COMMAND is the
445 'guix' program to use; INFO is the Info manual. When COMPILED-MODULES is
446 true, it is linked as 'lib/guile/X.Y/site-ccache'; otherwise, .go files are
447 assumed to be part of MODULES."
448 (computed-file name
449 (with-imported-modules '((guix build utils))
450 #~(begin
451 (use-modules (guix build utils))
452
453 (mkdir-p (string-append #$output "/bin"))
454 (symlink #$command
455 (string-append #$output "/bin/guix"))
456
457 (when #$daemon
458 (symlink (string-append #$daemon "/bin/guix-daemon")
459 (string-append #$output "/bin/guix-daemon")))
460
461 (let ((modules (string-append #$output
462 "/share/guile/site/"
463 (effective-version)))
464 (info #$info))
465 (mkdir-p (dirname modules))
466 (symlink #$modules modules)
467 (when info
468 (symlink #$info
469 (string-append #$output
470 "/share/info"))))
471
472 (when #$miscellany
473 (copy-recursively #$miscellany #$output
474 #:log (%make-void-port "w")))
475
476 ;; Object files.
477 (when #$compiled-modules
478 (let ((modules (string-append #$output "/lib/guile/"
479 (effective-version)
480 "/site-ccache")))
481 (mkdir-p (dirname modules))
482 (symlink #$compiled-modules modules)))))))
483
484 (define* (compiled-guix source #:key (version %guix-version)
485 (pull-version 1)
486 (name (string-append "guix-" version))
487 (guile-version (effective-version))
488 (guile-for-build (guile-for-build guile-version))
489 (zlib (specification->package "zlib"))
490 (gzip (specification->package "gzip"))
491 (bzip2 (specification->package "bzip2"))
492 (xz (specification->package "xz"))
493 (guix (specification->package "guix")))
494 "Return a file-like object that contains a compiled Guix."
495 (define guile-json
496 (package-for-guile guile-version
497 "guile-json"
498 "guile2.0-json"))
499
500 (define guile-ssh
501 (package-for-guile guile-version
502 "guile-ssh"
503 "guile2.0-ssh"))
504
505 (define guile-git
506 (package-for-guile guile-version
507 "guile-git"
508 "guile2.0-git"))
509
510 (define guile-sqlite3
511 (package-for-guile guile-version
512 "guile-sqlite3"
513 "guile2.0-sqlite3"))
514
515 (define guile-gcrypt
516 (package-for-guile guile-version
517 "guile-gcrypt"))
518
519 (define gnutls
520 (package-for-guile guile-version
521 "gnutls" "guile2.0-gnutls"))
522
523 (define dependencies
524 (match (append-map (lambda (package)
525 (cons (list "x" package)
526 (package-transitive-propagated-inputs package)))
527 (list guile-gcrypt gnutls guile-git guile-json
528 guile-ssh guile-sqlite3))
529 (((labels packages _ ...) ...)
530 packages)))
531
532 (define *core-modules*
533 (scheme-node "guix-core"
534 '((guix)
535 (guix monad-repl)
536 (guix packages)
537 (guix download)
538 (guix discovery)
539 (guix profiles)
540 (guix build-system gnu)
541 (guix build-system trivial)
542 (guix build profiles)
543 (guix build gnu-build-system))
544
545 ;; Provide a dummy (guix config) with the default version
546 ;; number, storedir, etc. This is so that "guix-core" is the
547 ;; same across all installations and doesn't need to be
548 ;; rebuilt when the version changes, which in turn means we
549 ;; can have substitutes for it.
550 #:extra-modules
551 `(((guix config) => ,(make-config.scm)))
552
553 ;; (guix man-db) is needed at build-time by (guix profiles)
554 ;; but we don't need to compile it; not compiling it allows
555 ;; us to avoid an extra dependency on guile-gdbm-ffi.
556 #:extra-files
557 `(("guix/man-db.scm" ,(local-file "../guix/man-db.scm"))
558 ("guix/store/schema.sql"
559 ,(local-file "../guix/store/schema.sql")))
560
561 #:extensions (list guile-gcrypt)
562 #:guile-for-build guile-for-build))
563
564 (define *extra-modules*
565 (scheme-node "guix-extra"
566 (filter-map (match-lambda
567 (('guix 'scripts _ ..1) #f)
568 (('guix 'man-db) #f)
569 (name name))
570 (scheme-modules* source "guix"))
571 (list *core-modules*)
572 #:extensions dependencies
573 #:guile-for-build guile-for-build))
574
575 (define *core-package-modules*
576 (scheme-node "guix-packages-base"
577 `((gnu packages)
578 (gnu packages base))
579 (list *core-modules* *extra-modules*)
580 #:extensions dependencies
581
582 ;; Add all the non-Scheme files here. We must do it here so
583 ;; that 'search-patches' & co. can find them. Ideally we'd
584 ;; keep them next to the .scm files that use them but it's
585 ;; difficult to do (XXX).
586 #:extra-files
587 (file-imports source "gnu/packages"
588 (lambda (file stat)
589 (and (eq? 'regular (stat:type stat))
590 (not (string-suffix? ".scm" file))
591 (not (string-suffix? ".go" file))
592 (not (string-prefix? ".#" file))
593 (not (string-suffix? "~" file)))))
594 #:guile-for-build guile-for-build))
595
596 (define *package-modules*
597 (scheme-node "guix-packages"
598 (scheme-modules* source "gnu/packages")
599 (list *core-modules* *extra-modules* *core-package-modules*)
600 #:extensions dependencies
601 #:guile-for-build guile-for-build))
602
603 (define *system-modules*
604 (scheme-node "guix-system"
605 `((gnu system)
606 (gnu services)
607 ,@(scheme-modules* source "gnu/system")
608 ,@(scheme-modules* source "gnu/services"))
609 (list *core-package-modules* *package-modules*
610 *extra-modules* *core-modules*)
611 #:extensions dependencies
612 #:extra-files
613 (append (file-imports source "gnu/system/examples"
614 (const #t))
615
616 ;; Build-side code that we don't build. Some of
617 ;; these depend on guile-rsvg, the Shepherd, etc.
618 (file-imports source "gnu/build" (const #t)))
619 #:guile-for-build
620 guile-for-build))
621
622 (define *cli-modules*
623 (scheme-node "guix-cli"
624 (scheme-modules* source "/guix/scripts")
625 (list *core-modules* *extra-modules*
626 *core-package-modules* *package-modules*
627 *system-modules*)
628 #:extensions dependencies
629 #:guile-for-build guile-for-build))
630
631 (define *config*
632 (scheme-node "guix-config"
633 '()
634 #:extra-modules
635 `(((guix config)
636 => ,(make-config.scm #:zlib zlib
637 #:gzip gzip
638 #:bzip2 bzip2
639 #:xz xz
640 #:package-name
641 %guix-package-name
642 #:package-version
643 version
644 #:bug-report-address
645 %guix-bug-report-address
646 #:home-page-url
647 %guix-home-page-url)))
648 #:guile-for-build guile-for-build))
649
650 (define (built-modules node-subset)
651 (directory-union (string-append name "-modules")
652 (append-map node-subset
653
654 ;; Note: *CONFIG* comes first so that it
655 ;; overrides the (guix config) module that
656 ;; comes with *CORE-MODULES*.
657 (list *config*
658 *cli-modules*
659 *system-modules*
660 *package-modules*
661 *core-package-modules*
662 *extra-modules*
663 *core-modules*))
664
665 ;; Silently choose the first entry upon collision so that
666 ;; we choose *CONFIG*.
667 #:resolve-collision 'first
668
669 ;; When we do (add-to-store "utils.scm"), "utils.scm" must
670 ;; be a regular file, not a symlink. Thus, arrange so that
671 ;; regular files appear as regular files in the final
672 ;; output.
673 #:copy? #t
674 #:quiet? #t))
675
676 ;; Version 0 of 'guix pull' meant we'd just return Scheme modules.
677 ;; Version 1 is when we return the full package.
678 (cond ((= 1 pull-version)
679 ;; The whole package, with a standard file hierarchy.
680 (let* ((modules (built-modules (compose list node-source)))
681 (compiled (built-modules (compose list node-compiled)))
682 (command (guix-command modules compiled
683 #:source source
684 #:dependencies dependencies
685 #:guile guile-for-build
686 #:guile-version guile-version)))
687 (whole-package name modules dependencies
688 #:compiled-modules compiled
689 #:command command
690 #:guile guile-for-build
691
692 ;; Include 'guix-daemon'. XXX: Here we inject an
693 ;; older snapshot of guix-daemon, but that's a good
694 ;; enough approximation for now.
695 #:daemon (module-ref (resolve-interface
696 '(gnu packages
697 package-management))
698 'guix-daemon)
699
700 #:info (info-manual source)
701 #:miscellany (miscellaneous-files source)
702 #:guile-version guile-version)))
703 ((= 0 pull-version)
704 ;; Legacy 'guix pull': return the .scm and .go files as one
705 ;; directory.
706 (built-modules (lambda (node)
707 (list (node-source node)
708 (node-compiled node)))))
709 (else
710 ;; Unsupported 'guix pull' version.
711 #f)))
712
713 \f
714 ;;;
715 ;;; Generating (guix config).
716 ;;;
717
718 (define %dependency-variables
719 ;; (guix config) variables corresponding to dependencies.
720 '(%libz %xz %gzip %bzip2))
721
722 (define %persona-variables
723 ;; (guix config) variables that define Guix's persona.
724 '(%guix-package-name
725 %guix-version
726 %guix-bug-report-address
727 %guix-home-page-url))
728
729 (define %config-variables
730 ;; (guix config) variables corresponding to Guix configuration.
731 (letrec-syntax ((variables (syntax-rules ()
732 ((_)
733 '())
734 ((_ variable rest ...)
735 (cons `(variable . ,variable)
736 (variables rest ...))))))
737 (variables %localstatedir %storedir %sysconfdir %system)))
738
739 (define* (make-config.scm #:key zlib gzip xz bzip2
740 (package-name "GNU Guix")
741 (package-version "0")
742 (bug-report-address "bug-guix@gnu.org")
743 (home-page-url "https://gnu.org/s/guix"))
744
745 ;; Hack so that Geiser is not confused.
746 (define defmod 'define-module)
747
748 (scheme-file "config.scm"
749 #~(;; The following expressions get spliced.
750 (#$defmod (guix config)
751 #:export (%guix-package-name
752 %guix-version
753 %guix-bug-report-address
754 %guix-home-page-url
755 %store-directory
756 %state-directory
757 %store-database-directory
758 %config-directory
759 %libz
760 %gzip
761 %bzip2
762 %xz))
763
764 #$@(map (match-lambda
765 ((name . value)
766 #~(define-public #$name #$value)))
767 %config-variables)
768
769 (define %store-directory
770 (or (and=> (getenv "NIX_STORE_DIR") canonicalize-path)
771 %storedir))
772
773 (define %state-directory
774 ;; This must match `NIX_STATE_DIR' as defined in
775 ;; `nix/local.mk'.
776 (or (getenv "NIX_STATE_DIR")
777 (string-append %localstatedir "/guix")))
778
779 (define %store-database-directory
780 (or (getenv "NIX_DB_DIR")
781 (string-append %state-directory "/db")))
782
783 (define %config-directory
784 ;; This must match `GUIX_CONFIGURATION_DIRECTORY' as
785 ;; defined in `nix/local.mk'.
786 (or (getenv "GUIX_CONFIGURATION_DIRECTORY")
787 (string-append %sysconfdir "/guix")))
788
789 (define %guix-package-name #$package-name)
790 (define %guix-version #$package-version)
791 (define %guix-bug-report-address #$bug-report-address)
792 (define %guix-home-page-url #$home-page-url)
793
794 (define %gzip
795 #+(and gzip (file-append gzip "/bin/gzip")))
796 (define %bzip2
797 #+(and bzip2 (file-append bzip2 "/bin/bzip2")))
798 (define %xz
799 #+(and xz (file-append xz "/bin/xz")))
800
801 (define %libz
802 #+(and zlib
803 (file-append zlib "/lib/libz"))))
804
805 ;; Guile 2.0 *requires* the 'define-module' to be at the
806 ;; top-level or the 'toplevel-ref' in the resulting .go file are
807 ;; made relative to a nonexistent anonymous module.
808 #:splice? #t))
809
810
811 \f
812 ;;;
813 ;;; Building.
814 ;;;
815
816 (define* (compiled-modules name module-tree module-files
817 #:optional
818 (dependencies '())
819 (dependencies-compiled '())
820 #:key
821 (extensions '()) ;full-blown Guile packages
822 parallel?
823 guile-for-build)
824 "Build all the MODULE-FILES from MODULE-TREE. MODULE-FILES must be a list
825 like '(\"guix/foo.scm\" \"gnu/bar.scm\") and MODULE-TREE is the directory
826 containing MODULE-FILES and possibly other files as well."
827 ;; This is a non-monadic, enhanced version of 'compiled-file' from (guix
828 ;; gexp).
829 (define build
830 (with-imported-modules (source-module-closure
831 '((guix build compile)
832 (guix build utils)))
833 #~(begin
834 (use-modules (srfi srfi-26)
835 (ice-9 match)
836 (ice-9 format)
837 (ice-9 threads)
838 (guix build compile)
839 (guix build utils))
840
841 (define (regular? file)
842 (not (member file '("." ".."))))
843
844 (define (report-load file total completed)
845 (display #\cr)
846 (format #t
847 "loading...\t~5,1f% of ~d files" ;FIXME: i18n
848 (* 100. (/ completed total)) total)
849 (force-output))
850
851 (define (report-compilation file total completed)
852 (display #\cr)
853 (format #t "compiling...\t~5,1f% of ~d files" ;FIXME: i18n
854 (* 100. (/ completed total)) total)
855 (force-output))
856
857 (define (process-directory directory files output)
858 ;; Hide compilation warnings.
859 (parameterize ((current-warning-port (%make-void-port "w")))
860 (compile-files directory #$output files
861 #:workers (parallel-job-count)
862 #:report-load report-load
863 #:report-compilation report-compilation)))
864
865 (setvbuf (current-output-port) _IONBF)
866 (setvbuf (current-error-port) _IONBF)
867
868 (set! %load-path (cons #+module-tree %load-path))
869 (set! %load-path
870 (append '#+dependencies
871 (map (lambda (extension)
872 (string-append extension "/share/guile/site/"
873 (effective-version)))
874 '#+extensions)
875 %load-path))
876
877 (set! %load-compiled-path
878 (append '#+dependencies-compiled
879 (map (lambda (extension)
880 (string-append extension "/lib/guile/"
881 (effective-version)
882 "/site-ccache"))
883 '#+extensions)
884 %load-compiled-path))
885
886 ;; Load the compiler modules upfront.
887 (compile #f)
888
889 (mkdir #$output)
890 (chdir #+module-tree)
891 (process-directory "." '#+module-files #$output)
892 (newline))))
893
894 (computed-file name build
895 #:guile guile-for-build
896 #:options
897 `(#:local-build? #f ;allow substitutes
898
899 ;; Don't annoy people about _IONBF deprecation.
900 ;; Initialize 'terminal-width' in (system repl debug)
901 ;; to a large-enough value to make backtrace more
902 ;; verbose.
903 #:env-vars (("GUILE_WARN_DEPRECATED" . "no")
904 ("COLUMNS" . "200")))))
905
906 \f
907 ;;;
908 ;;; Building.
909 ;;;
910
911 (define (guile-for-build version)
912 "Return a derivation for Guile 2.0 or 2.2, whichever matches the currently
913 running Guile."
914 (define canonical-package ;soft reference
915 (module-ref (resolve-interface '(gnu packages base))
916 'canonical-package))
917
918 (match version
919 ("2.2"
920 (canonical-package (module-ref (resolve-interface '(gnu packages guile))
921 'guile-2.2)))
922 ("2.0"
923 (module-ref (resolve-interface '(gnu packages guile))
924 'guile-2.0))))
925
926 (define* (guix-derivation source version
927 #:optional (guile-version (effective-version))
928 #:key (pull-version 0))
929 "Return, as a monadic value, the derivation to build the Guix from SOURCE
930 for GUILE-VERSION. Use VERSION as the version string. PULL-VERSION specifies
931 the version of the 'guix pull' protocol. Return #f if this PULL-VERSION value
932 is not supported."
933 (define (shorten version)
934 (if (and (string-every char-set:hex-digit version)
935 (> (string-length version) 9))
936 (string-take version 9) ;Git commit
937 version))
938
939 (define guile
940 ;; When PULL-VERSION >= 1, produce a self-contained Guix and use Guile 2.2
941 ;; unconditionally.
942 (guile-for-build (if (>= pull-version 1)
943 "2.2"
944 guile-version)))
945
946 (mbegin %store-monad
947 (set-guile-for-build guile)
948 (let ((guix (compiled-guix source
949 #:version version
950 #:name (string-append "guix-"
951 (shorten version))
952 #:pull-version pull-version
953 #:guile-version (if (>= pull-version 1)
954 "2.2" guile-version)
955 #:guile-for-build guile)))
956 (if guix
957 (lower-object guix)
958 (return #f)))))