1 ;;; GNU Guix --- Functional package management for GNU
2 ;;; Copyright © 2015, 2017, 2018, 2019, 2020, 2021 Ludovic Courtès <ludo@gnu.org>
3 ;;; Copyright © 2017, 2018 Ricardo Wurmus <rekado@elephly.net>
4 ;;; Copyright © 2018 Konrad Hinsen <konrad.hinsen@fastmail.net>
5 ;;; Copyright © 2018 Chris Marusich <cmmarusich@gmail.com>
6 ;;; Copyright © 2018 Efraim Flashner <efraim@flashner.co.il>
7 ;;; Copyright © 2020 Tobias Geerinckx-Rice <me@tobias.gr>
8 ;;; Copyright © 2020 Eric Bavier <bavier@posteo.net>
10 ;;; This file is part of GNU Guix.
12 ;;; GNU Guix is free software; you can redistribute it and/or modify it
13 ;;; under the terms of the GNU General Public License as published by
14 ;;; the Free Software Foundation; either version 3 of the License, or (at
15 ;;; your option) any later version.
17 ;;; GNU Guix is distributed in the hope that it will be useful, but
18 ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 ;;; GNU General Public License for more details.
22 ;;; You should have received a copy of the GNU General Public License
23 ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
25 (define-module (guix scripts pack)
26 #:use-module (guix scripts)
27 #:use-module (guix ui)
28 #:use-module (guix gexp)
29 #:use-module (guix utils)
30 #:use-module (guix store)
31 #:use-module ((guix status) #:select (with-status-verbosity))
32 #:use-module ((guix self) #:select (make-config.scm))
33 #:use-module (guix grafts)
34 #:autoload (guix inferior) (inferior-package?
36 inferior-package-version)
37 #:use-module (guix monads)
38 #:use-module (guix modules)
39 #:use-module (guix packages)
40 #:use-module (guix profiles)
41 #:use-module (guix describe)
42 #:use-module (guix derivations)
43 #:use-module (guix search-paths)
44 #:use-module (guix build-system gnu)
45 #:use-module (guix scripts build)
46 #:use-module (guix transformations)
47 #:use-module ((guix self) #:select (make-config.scm))
48 #:use-module (gnu packages)
49 #:use-module (gnu packages bootstrap)
50 #:use-module ((gnu packages compression) #:hide (zip))
51 #:use-module (gnu packages guile)
52 #:use-module (gnu packages base)
53 #:autoload (gnu packages package-management) (guix)
54 #:autoload (gnu packages gnupg) (guile-gcrypt)
55 #:autoload (gnu packages guile) (guile2.0-json guile-json)
56 #:use-module (srfi srfi-1)
57 #:use-module (srfi srfi-9)
58 #:use-module (srfi srfi-26)
59 #:use-module (srfi srfi-37)
60 #:use-module (ice-9 match)
67 self-contained-tarball
74 ;; Type of a compression tool.
75 (define-record-type <compressor>
76 (compressor name extension command)
78 (name compressor-name) ;string (e.g., "gzip")
79 (extension compressor-extension) ;string (e.g., ".lz")
80 (command compressor-command)) ;gexp (e.g., #~("/gnu/store/…/gzip" "-9n"))
83 ;; Available compression tools.
84 (list (compressor "gzip" ".gz"
85 #~(#+(file-append gzip "/bin/gzip") "-9n"))
86 (compressor "lzip" ".lz"
87 #~(#+(file-append lzip "/bin/lzip") "-9"))
88 (compressor "xz" ".xz"
89 #~(#+(file-append xz "/bin/xz") "-e"))
90 (compressor "bzip2" ".bz2"
91 #~(#+(file-append bzip2 "/bin/bzip2") "-9"))
92 (compressor "zstd" ".zst"
93 ;; The default level 3 compresses better than gzip in a
94 ;; fraction of the time, while the highest level 19
95 ;; (de)compresses more slowly and worse than xz.
96 #~(#+(file-append zstd "/bin/zstd") "-3"))
97 (compressor "none" "" #f)))
99 ;; This one is only for use in this module, so don't put it in %compressors.
101 (compressor "bootstrap-xz" ".xz"
102 #~(#+(file-append %bootstrap-coreutils&co "/bin/xz") "-e")))
104 (define (lookup-compressor name)
105 "Return the compressor object called NAME. Error out if it could not be
107 (or (find (match-lambda
108 (($ <compressor> name*)
109 (string=? name* name)))
111 (leave (G_ "~a: compressor not found~%") name)))
114 ;; Select (guix …) and (gnu …) modules, except (guix config).
121 (define gcrypt-sqlite3&co
122 ;; Guile-Gcrypt, Guile-SQLite3, and their propagated inputs.
123 (append-map (lambda (package)
125 (match (package-transitive-propagated-inputs package)
126 (((labels packages) ...)
128 (list guile-gcrypt guile-sqlite3)))
130 (define (store-database items)
131 "Return a directory containing a store database where all of ITEMS and their
132 dependencies are registered."
134 (local-file (search-path %load-path
135 "guix/store/schema.sql")))
140 (string-append "closure" (number->string n)))
141 (iota (length items))))
144 (with-extensions gcrypt-sqlite3&co
145 (with-imported-modules `(((guix config) => ,(make-config.scm))
146 ,@(source-module-closure
147 '((guix build store-copy)
148 (guix store database))
149 #:select? not-config?))
151 (use-modules (guix store database)
152 (guix build store-copy)
155 (define (read-closure closure)
156 (call-with-input-file closure read-reference-graph))
159 (store-database-file #:state-directory #$output))
161 ;; Make sure non-ASCII file names are properly handled.
162 (setenv "GUIX_LOCPATH"
163 #+(file-append glibc-utf8-locales "/lib/locale"))
164 (setlocale LC_ALL "en_US.utf8")
166 (sql-schema #$schema)
167 (let ((items (append-map read-closure '#$labels)))
168 (with-database db-file db
169 (register-items db items
170 #:registration-time %epoch)))))))
172 (computed-file "store-database" build
173 #:options `(#:references-graphs ,(zip labels items))))
175 (define-syntax-rule (define-with-source (variable args ...) body body* ...)
176 "Bind VARIABLE to a procedure accepting ARGS defined as BODY, also setting
177 its source property."
179 (define (variable args ...)
181 (eval-when (load eval)
182 (set-procedure-property! variable 'source
183 '(define (variable args ...) body body* ...)))))
185 (define-with-source (manifest->friendly-name manifest)
186 "Return a friendly name computed from the entries in MANIFEST, a
188 (let loop ((names (map manifest-entry-name
189 (manifest-entries manifest))))
190 (define str (string-join names "-"))
191 (if (< (string-length str) 40)
195 ((names ... _) (loop names))))))
201 (define* (self-contained-tarball/builder profile
202 #:key (profile-name "guix-profile")
203 (compressor (first %compressors))
207 "Return the G-Expression of the builder used for self-contained-tarball."
210 (file-append (store-database (list profile))
213 (define set-utf8-locale
214 ;; Arrange to not depend on 'glibc-utf8-locales' when using '--bootstrap'.
215 (and (or (not (profile? profile))
216 (profile-locales? profile))
218 (setenv "GUIX_LOCPATH"
219 #+(file-append glibc-utf8-locales "/lib/locale"))
220 (setlocale LC_ALL "en_US.utf8"))))
222 (define (import-module? module)
223 ;; Since we don't use deduplication support in 'populate-store', don't
224 ;; import (guix store deduplication) and its dependencies, which includes
225 ;; Guile-Gcrypt. That way we can run tests with '--bootstrap'.
226 (and (not-config? module)
227 (not (equal? '(guix store deduplication) module))))
229 (with-imported-modules (source-module-closure
234 (gnu system file-systems))
235 #:select? import-module?)
237 (use-modules (guix build pack)
239 ((guix build union) #:select (relative-file-name))
241 ((gnu system file-systems) #:select (reduce-directories))
246 (define %root "root")
248 (define symlink->directives
249 ;; Return "populate directives" to make the given symlink and its
250 ;; parent directories.
253 (let ((target (string-append #$profile "/" target))
254 (parent (dirname source)))
255 ;; Never add a 'directory' directive for "/" so as to
256 ;; preserve its ownership when extracting the archive (see
257 ;; below), and also because this would lead to adding the
258 ;; same entries twice in the tarball.
259 `(,@(if (string=? parent "/")
261 `((directory ,parent)))
263 -> ,(relative-file-name parent target)))))))
266 ;; Fully-qualified symlinks.
267 (append-map symlink->directives '#$symlinks))
269 ;; Make sure non-ASCII file names are properly handled.
272 (define tar #+(file-append archiver "/bin/tar"))
274 ;; Note: there is not much to gain here with deduplication and there
275 ;; is the overhead of the '.links' directory, so turn it off.
276 ;; Furthermore GNU tar < 1.30 sometimes fails to extract tarballs
278 ;; <http://lists.gnu.org/archive/html/bug-tar/2017-11/msg00009.html>.
279 (populate-single-profile-directory %root
281 #:profile-name #$profile-name
283 #:database #+database)
286 (for-each (cut evaluate-populate-directive <> %root)
289 ;; Create the tarball.
290 (with-directory-excursion %root
292 `(,@(tar-base-options
294 #:compressor '#+(and=> compressor compressor-command))
296 ;; Avoid adding / and /var to the tarball, so
297 ;; that the ownership and permissions of those
298 ;; directories will not be overwritten when
299 ;; extracting the archive. Do not include /root
300 ;; because the root account might have a
301 ;; different home directory.
302 ,#$@(if localstatedir?
306 ,(string-append "." (%store-directory))
308 ,@(reduce-directories
309 (filter-map (match-lambda
310 (('directory directory)
311 (string-append "." directory))
313 (string-append "." source))
317 (define* (self-contained-tarball name profile
319 (profile-name "guix-profile")
322 (compressor (first %compressors))
326 "Return a self-contained tarball containing a store initialized with the
327 closure of PROFILE, a derivation. The tarball contains /gnu/store; if
328 LOCALSTATEDIR? is true, it also contains /var/guix, including /var/guix/db
329 with a properly initialized store database.
331 SYMLINKS must be a list of (SOURCE -> TARGET) tuples denoting symlinks to be
334 (warning (G_ "entry point not supported in the '~a' format~%")
338 (string-append name ".tar"
339 (compressor-extension compressor))
340 (self-contained-tarball/builder profile
341 #:profile-name profile-name
342 #:compressor compressor
343 #:localstatedir? localstatedir?
347 #:references-graphs `(("profile" ,profile))))
349 (define (singularity-environment-file profile)
350 "Return a shell script that defines the environment variables corresponding
351 to the search paths of PROFILE."
353 (with-extensions (list guile-gcrypt)
354 (with-imported-modules `(((guix config) => ,(make-config.scm))
355 ,@(source-module-closure
358 #:select? not-config?))
360 (use-modules (guix profiles) (guix search-paths)
363 (call-with-output-file #$output
365 (for-each (match-lambda
367 (format port "~a=~a~%export ~a~%"
368 (search-path-specification-variable spec)
370 (search-path-specification-variable spec))))
371 (profile-search-paths #$profile))))))))
373 (computed-file "singularity-environment.sh" build))
375 (define* (squashfs-image name profile
377 (profile-name "guix-profile")
378 (compressor (first %compressors))
382 (archiver squashfs-tools))
383 "Return a squashfs image containing a store initialized with the closure of
384 PROFILE, a derivation. The image contains a subset of /gnu/store, empty mount
385 points for virtual file systems (like procfs), and optional symlinks.
387 SYMLINKS must be a list of (SOURCE -> TARGET) tuples denoting symlinks to be
391 (file-append (store-database (list profile))
395 (singularity-environment-file profile))
398 ;; Singularity requires /bin (specifically /bin/sh), so ensure that
399 ;; symlink is created.
400 (if (find (match-lambda
405 `(("/bin" -> "bin") ,@symlinks)))
408 (with-extensions (list guile-gcrypt)
409 (with-imported-modules (source-module-closure
411 (guix build store-copy)
414 #:select? not-config?)
416 (use-modules (guix build utils)
417 (guix build store-copy)
418 ((guix build union) #:select (relative-file-name))
424 (define database #+database)
425 (define entry-point #$entry-point)
427 (define (mksquashfs args)
428 (apply invoke "mksquashfs"
431 ;; Do not create a "recovery file" when appending to the
432 ;; file system since it's useless in this case.
435 ;; Do not attempt to store extended attributes.
436 ;; See <https://bugs.gnu.org/40043>.
439 ;; Set file times and the file system creation time to
440 ;; one second after the Epoch.
441 "-all-time" "1" "-mkfs-time" "1"
443 ;; Reset all UIDs and GIDs.
444 "-force-uid" "0" "-force-gid" "0")))
446 (setenv "PATH" #+(file-append archiver "/bin"))
448 ;; We need an empty file in order to have a valid file argument when
449 ;; we reparent the root file system. Read on for why that's
451 (with-output-to-file ".empty" (lambda () (display "")))
453 ;; Create the squashfs image in several steps.
454 ;; Add all store items. Unfortunately mksquashfs throws away all
455 ;; ancestor directories and only keeps the basename. We fix this
456 ;; in the following invocations of mksquashfs.
457 (mksquashfs `(,@(map store-info-item
458 (call-with-input-file "profile"
459 read-reference-graph))
463 ;; Do not perform duplicate checking because we
464 ;; don't have any dupes.
467 ,#+(compressor-name compressor)))
469 ;; Here we reparent the store items. For each sub-directory of
470 ;; the store prefix we need one invocation of "mksquashfs".
471 (for-each (lambda (dir)
472 (mksquashfs `(".empty"
474 "-root-becomes" ,dir)))
475 (reverse (string-tokenize (%store-directory)
476 (char-set-complement (char-set #\/)))))
478 ;; Add symlinks and mount points.
482 ;; Create SYMLINKS via pseudo file definitions.
486 ;; Create relative symlinks to work around a bug in
488 ;; https://bugs.gnu.org/34913
489 ;; https://github.com/sylabs/singularity/issues/1487
490 (let ((target (string-append #$profile "/" target)))
493 ;; name s mode uid gid symlink
496 (relative-file-name (dirname source)
500 "-p" "/.singularity.d d 555 0 0"
502 ;; Create the environment file.
503 "-p" "/.singularity.d/env d 555 0 0"
505 "/.singularity.d/env/90-environment.sh s 777 0 0 "
506 (relative-file-name "/.singularity.d/env"
509 ;; Create /.singularity.d/actions, and optionally the 'run'
510 ;; script, used by 'singularity run'.
511 "-p" "/.singularity.d/actions d 555 0 0"
514 `( ;; This one if for Singularity 2.x.
517 "/.singularity.d/actions/run s 777 0 0 "
518 (relative-file-name "/.singularity.d/actions"
519 (string-append #$profile "/"
522 ;; This one is for Singularity 3.x.
525 "/.singularity.d/runscript s 777 0 0 "
526 (relative-file-name "/.singularity.d"
527 (string-append #$profile "/"
531 ;; Create empty mount points.
532 "-p" "/proc d 555 0 0"
533 "-p" "/sys d 555 0 0"
534 "-p" "/dev d 555 0 0"
535 "-p" "/home d 555 0 0"))
538 ;; Initialize /var/guix.
539 (install-database-and-gc-roots "var-etc" database #$profile)
540 (mksquashfs `("var-etc" ,#$output)))))))
542 (gexp->derivation (string-append name
543 (compressor-extension compressor)
547 #:references-graphs `(("profile" ,profile))))
549 (define* (docker-image name profile
551 (profile-name "guix-profile")
552 (compressor (first %compressors))
557 "Return a derivation to construct a Docker image of PROFILE. The
558 image is a tarball conforming to the Docker Image Specification, compressed
559 with COMPRESSOR. It can be passed to 'docker load'. If TARGET is true, it
560 must a be a GNU triplet and it is used to derive the architecture metadata in
564 (file-append (store-database (list profile))
567 (define defmod 'define-module) ;trick Geiser
570 ;; Guile-JSON and Guile-Gcrypt are required by (guix docker).
571 (with-extensions (list guile-json-3 guile-gcrypt)
572 (with-imported-modules `(((guix config) => ,(make-config.scm))
573 ,@(source-module-closure
575 (guix build store-copy)
578 #:select? not-config?))
580 (use-modules (guix docker) (guix build store-copy)
581 (guix profiles) (guix search-paths)
582 (srfi srfi-1) (srfi srfi-19)
585 #$(procedure-source manifest->friendly-name)
590 (cons (search-path-specification-variable spec)
592 (profile-search-paths #$profile)))
594 (define symlink->directives
595 ;; Return "populate directives" to make the given symlink and its
596 ;; parent directories.
599 (let ((target (string-append #$profile "/" target))
600 (parent (dirname source)))
601 `((directory ,parent)
602 (,source -> ,target))))))
605 ;; Create a /tmp directory, as some programs expect it, and
607 `((directory "/tmp" ,(getuid) ,(getgid) #o1777)
608 ,@(append-map symlink->directives '#$symlinks)))
610 (setenv "PATH" #+(file-append archiver "/bin"))
612 (build-docker-image #$output
614 (call-with-input-file "profile"
615 read-reference-graph))
617 #:repository (manifest->friendly-name
618 (profile-manifest #$profile))
619 #:database #+database
620 #:system (or #$target %host-type)
621 #:environment environment
624 #~(list (string-append #$profile "/"
626 #:extra-files directives
627 #:compressor '#+(compressor-command compressor)
628 #:creation-time (make-time time-utc 0 1))))))
630 (gexp->derivation (string-append name ".tar"
631 (compressor-extension compressor))
634 #:references-graphs `(("profile" ,profile))))
638 ;;; Compiling C programs.
641 ;; A C compiler. That lowers to a single program that can be passed typical C
642 ;; compiler flags, and it makes sure the whole toolchain is available.
643 (define-record-type <c-compiler>
644 (%c-compiler toolchain guile)
646 (toolchain c-compiler-toolchain)
647 (guile c-compiler-guile))
649 (define* (c-compiler #:optional inputs
650 #:key (guile (default-guile)))
651 (%c-compiler inputs guile))
653 (define (bootstrap-c-compiler)
654 "Return the C compiler that uses the bootstrap toolchain. This is used only
655 by '--bootstrap', for testing purposes."
656 (define bootstrap-toolchain
657 (list (first (assoc-ref (%bootstrap-inputs) "gcc"))
658 (first (assoc-ref (%bootstrap-inputs) "binutils"))
659 (first (assoc-ref (%bootstrap-inputs) "libc"))))
661 (c-compiler bootstrap-toolchain
662 #:guile %bootstrap-guile))
664 (define-gexp-compiler (c-compiler-compiler (compiler <c-compiler>) system target)
665 "Lower COMPILER to a single script that does the right thing."
667 (or (c-compiler-toolchain compiler)
668 (list (first (assoc-ref (standard-packages) "gcc"))
669 (first (assoc-ref (standard-packages) "ld-wrapper"))
670 (first (assoc-ref (standard-packages) "binutils"))
671 (first (assoc-ref (standard-packages) "libc"))
672 (gexp-input (first (assoc-ref (standard-packages) "libc"))
676 (match (append-map package-propagated-inputs
677 (filter package? toolchain))
678 (((labels things . _) ...)
679 (append toolchain things))))
683 (append-map package-native-search-paths
684 (filter package? inputs))))
687 (with-imported-modules (source-module-closure
689 (guix search-paths)))
691 (use-modules (guix build utils) (guix search-paths)
694 (define (output-file args)
695 (let loop ((args args))
698 (("-o" file _ ...) file)
699 ((head rest ...) (loop rest)))))
701 (set-search-paths (map sexp->search-path-specification
702 '#$(map search-path-specification->sexp
706 (let ((output (output-file (command-line))))
707 (apply invoke "gcc" (cdr (command-line)))
708 (invoke "strip" output)))))
711 ;; TODO: Yep, we'll have to do it someday!
712 (leave (G_ "cross-compilation not implemented here;
713 please email '~a'~%")
714 (@ (guix config) %guix-bug-report-address)))
716 (gexp->script "c-compiler" run
717 #:guile (c-compiler-guile compiler)))
724 (define* (wrapped-package package
727 (compiler (c-compiler))
729 "Return the OUTPUT of PACKAGE with its binaries wrapped such that they are
730 relocatable. When PROOT? is true, include PRoot in the result and use it as a
731 last resort for relocation."
733 (local-file (search-auxiliary-file "run-in-namespace.c")))
736 (local-file (search-auxiliary-file "pack-audit.c")))
739 (specification->package "proot-static"))
741 (define (fakechroot-library)
742 (computed-file "libfakechroot.so"
743 #~(copy-file #$(file-append
744 (specification->package "fakechroot")
745 "/lib/fakechroot/libfakechroot.so")
748 (define (audit-module)
749 ;; Return an ld.so audit module for use by the 'fakechroot' execution
750 ;; engine that translates file names of all the files ld.so loads.
751 (computed-file "pack-audit.so"
752 (with-imported-modules '((guix build utils))
754 (use-modules (guix build utils))
756 (copy-file #$audit-source "audit.c")
757 (substitute* "audit.c"
758 (("@STORE_DIRECTORY@")
761 (invoke #$compiler "-std=gnu99"
762 "-shared" "-fPIC" "-Os" "-g0"
763 "-Wall" "audit.c" "-o" #$output)))))
766 (with-imported-modules (source-module-closure
772 (use-modules (guix build utils)
773 ((guix build union) #:select (symlink-relative))
784 ;; The OUTPUT* output of PACKAGE.
785 (ungexp package output*))
788 ;; The output we are producing.
789 (ungexp output output*))
791 (define (strip-store-prefix file)
792 ;; Given a file name like "/gnu/store/…-foo-1.2/bin/foo", return
794 (let* ((len (string-length (%store-directory)))
795 (base (string-drop file (+ 1 len))))
796 (match (string-index base #\/)
798 (index (string-drop base index)))))
800 (define (elf-interpreter elf)
801 ;; Return the interpreter of ELF as a string, or #f if ELF has no
802 ;; interpreter segment.
803 (match (find (lambda (segment)
804 (= (elf-segment-type segment) PT_INTERP))
808 (let ((bv (make-bytevector (- (elf-segment-memsz segment) 1))))
809 (bytevector-copy! (elf-bytes elf)
810 (elf-segment-offset segment)
811 bv 0 (bytevector-length bv))
812 (utf8->string bv)))))
814 (define (runpath file)
815 ;; Return the RUNPATH of FILE as a list of directories.
816 (let* ((bv (call-with-input-file file get-bytevector-all))
818 (dyninfo (elf-dynamic-info elf)))
819 (or (and=> dyninfo elf-dynamic-info-runpath)
822 (define (elf-loader-compile-flags program)
823 ;; Return the cpp flags defining macros for the ld.so/fakechroot
824 ;; wrapper of PROGRAM.
826 ;; TODO: Handle scripts by wrapping their interpreter.
827 (if (elf-file? program)
828 (let* ((bv (call-with-input-file program
831 (interp (elf-interpreter elf))
833 (string-append (dirname interp)
836 (list (string-append "-DPROGRAM_INTERPRETER=\""
838 (string-append "-DFAKECHROOT_LIBRARY=\""
839 #$(fakechroot-library) "\"")
841 (string-append "-DLOADER_AUDIT_MODULE=\""
842 #$(audit-module) "\"")
844 ;; XXX: Normally (runpath #$(audit-module)) is
845 ;; enough. However, to work around
846 ;; <https://sourceware.org/bugzilla/show_bug.cgi?id=26634>
847 ;; (glibc <= 2.32), pass the whole search path of
848 ;; PROGRAM, which presumably is a superset of that
849 ;; of the audit module.
850 (string-append "-DLOADER_AUDIT_RUNPATH={ "
857 (string-append "-DGCONV_DIRECTORY=\""
859 "-UGCONV_DIRECTORY"))
863 (define (build-wrapper program)
864 ;; Build a user-namespace wrapper for PROGRAM.
865 (format #t "building wrapper for '~a'...~%" program)
866 (copy-file #$runner "run.c")
869 (("@WRAPPED_PROGRAM@") program)
870 (("@STORE_DIRECTORY@") (%store-directory)))
872 (let* ((base (strip-store-prefix program))
873 (result (string-append target base))
876 #$(file-append (proot) "/bin/proot")
877 (+ (string-length (%store-directory))
879 (mkdir-p (dirname result))
880 (apply invoke #$compiler "-std=gnu99" "-static" "-Os" "-g0" "-Wall"
882 (string-append "-DWRAPPER_PROGRAM=\""
883 (canonicalize-path (dirname result)) "/"
884 (basename result) "\"")
886 (list (string-append "-DPROOT_PROGRAM=\""
889 (elf-loader-compile-flags program)))
890 (delete-file "run.c")))
892 (setvbuf (current-output-port) 'line)
894 ;; Link the top-level files of PACKAGE so that search paths are
895 ;; properly defined in PROFILE/etc/profile.
897 (for-each (lambda (file)
898 (unless (member file '("." ".." "bin" "sbin" "libexec"))
899 (symlink-relative (string-append input "/" file)
900 (string-append target "/" file))))
903 (receive (executables others)
904 (partition executable-file?
905 ;; Note: Trailing slash in case these are symlinks.
906 (append (find-files (string-append input "/bin/"))
907 (find-files (string-append input "/sbin/"))
908 (find-files (string-append input "/libexec/"))))
909 ;; Wrap only executables, since the wrapper will eventually need
910 ;; to execve them. E.g. git's "libexec" directory contains many
911 ;; shell scripts that are source'd from elsewhere, which fails if
913 (for-each build-wrapper executables)
914 ;; Link any other non-executable files
915 (for-each (lambda (old)
916 (let ((new (string-append target (strip-store-prefix old))))
917 (mkdir-p (dirname new))
918 (symlink-relative old new)))
921 (computed-file (string-append
922 (cond ((package? package)
923 (package-full-name package "-"))
924 ((inferior-package? package)
925 (string-append (inferior-package-name package)
927 (inferior-package-version package)))
932 (define (wrapped-manifest-entry entry . args)
935 (item (apply wrapped-package
936 (manifest-entry-item entry)
937 (manifest-entry-output entry)
939 (dependencies (map (lambda (entry)
940 (apply wrapped-manifest-entry entry args))
941 (manifest-entry-dependencies entry)))))
945 ;;; Command-line options.
948 (define %default-options
949 ;; Alist of default option values.
951 (profile-name . "guix-profile")
952 (system . ,(%current-system))
956 (print-build-trace? . #t)
957 (print-extended-build-trace? . #t)
958 (multiplexed-build-output? . #t)
962 (compressor . ,(first %compressors))))
965 ;; Supported pack formats.
966 `((tarball . ,self-contained-tarball)
967 (squashfs . ,squashfs-image)
968 (docker . ,docker-image)))
970 (define (show-formats)
971 ;; Print the supported pack formats.
972 (display (G_ "The supported formats for 'guix pack' are:"))
975 tarball Self-contained tarball, ready to run on another machine"))
977 squashfs Squashfs image suitable for Singularity"))
979 docker Tarball ready for 'docker load'"))
983 ;; Specifications of the command-line options.
984 (cons* (option '(#\h "help") #f #f
988 (option '(#\V "version") #f #f
990 (show-version-and-exit "guix pack")))
992 (option '(#\n "dry-run") #f #f
993 (lambda (opt name arg result)
994 (alist-cons 'dry-run? #t result)))
995 (option '(#\d "derivation") #f #f
996 (lambda (opt name arg result)
997 (alist-cons 'derivation-only? #t result)))
999 (option '(#\f "format") #t #f
1000 (lambda (opt name arg result)
1001 (alist-cons 'format (string->symbol arg) result)))
1002 (option '("list-formats") #f #f
1006 (option '(#\R "relocatable") #f #f
1007 (lambda (opt name arg result)
1008 (match (assq-ref result 'relocatable?)
1010 (alist-cons 'relocatable? #t result))
1012 (alist-cons 'relocatable? 'proot
1013 (alist-delete 'relocatable? result))))))
1014 (option '(#\e "expression") #t #f
1015 (lambda (opt name arg result)
1016 (alist-cons 'expression arg result)))
1017 (option '(#\m "manifest") #t #f
1018 (lambda (opt name arg result)
1019 (alist-cons 'manifest arg result)))
1020 (option '(#\s "system") #t #f
1021 (lambda (opt name arg result)
1022 (alist-cons 'system arg
1023 (alist-delete 'system result eq?))))
1024 (option '("entry-point") #t #f
1025 (lambda (opt name arg result)
1026 (alist-cons 'entry-point arg result)))
1027 (option '("target") #t #f
1028 (lambda (opt name arg result)
1029 (alist-cons 'target arg
1030 (alist-delete 'target result eq?))))
1031 (option '(#\C "compression") #t #f
1032 (lambda (opt name arg result)
1033 (alist-cons 'compressor (lookup-compressor arg)
1035 (option '(#\S "symlink") #t #f
1036 (lambda (opt name arg result)
1037 ;; Note: Using 'string-split' allows us to handle empty
1038 ;; TARGET (as in "/opt/guile=", meaning that /opt/guile is
1039 ;; a symlink to the profile) correctly.
1040 (match (string-split arg (char-set #\=))
1042 (let ((symlinks (assoc-ref result 'symlinks)))
1043 (alist-cons 'symlinks
1044 `((,source -> ,target) ,@symlinks)
1045 (alist-delete 'symlinks result eq?))))
1047 (leave (G_ "~a: invalid symlink specification~%")
1049 (option '("save-provenance") #f #f
1050 (lambda (opt name arg result)
1051 (alist-cons 'save-provenance? #t result)))
1052 (option '("localstatedir") #f #f
1053 (lambda (opt name arg result)
1054 (alist-cons 'localstatedir? #t result)))
1055 (option '("profile-name") #t #f
1056 (lambda (opt name arg result)
1058 ((or "guix-profile" "current-guix")
1059 (alist-cons 'profile-name arg result))
1061 (leave (G_ "~a: unsupported profile name~%") arg)))))
1062 (option '(#\r "root") #t #f
1063 (lambda (opt name arg result)
1064 (alist-cons 'gc-root arg result)))
1066 (option '(#\v "verbosity") #t #f
1067 (lambda (opt name arg result)
1068 (let ((level (string->number* arg)))
1069 (alist-cons 'verbosity level
1070 (alist-delete 'verbosity result)))))
1071 (option '("bootstrap") #f #f
1072 (lambda (opt name arg result)
1073 (alist-cons 'bootstrap? #t result)))
1075 (append %transformation-options
1076 %standard-build-options)))
1079 (display (G_ "Usage: guix pack [OPTION]... PACKAGE...
1080 Create a bundle of PACKAGE.\n"))
1081 (show-build-options-help)
1083 (show-transformation-options-help)
1086 -f, --format=FORMAT build a pack in the given FORMAT"))
1088 --list-formats list the formats available"))
1090 -R, --relocatable produce relocatable executables"))
1092 -e, --expression=EXPR consider the package EXPR evaluates to"))
1094 -s, --system=SYSTEM attempt to build for SYSTEM--e.g., \"i686-linux\""))
1096 --target=TRIPLET cross-build for TRIPLET--e.g., \"armel-linux-gnu\""))
1098 -C, --compression=TOOL compress using TOOL--e.g., \"lzip\""))
1100 -S, --symlink=SPEC create symlinks to the profile according to SPEC"))
1102 -m, --manifest=FILE create a pack with the manifest from FILE"))
1104 --entry-point=PROGRAM
1105 use PROGRAM as the entry point of the pack"))
1107 --save-provenance save provenance information"))
1109 --localstatedir include /var/guix in the resulting pack"))
1112 populate /var/guix/profiles/.../NAME"))
1114 -r, --root=FILE make FILE a symlink to the result, and register it
1115 as a garbage collector root"))
1117 -d, --derivation return the derivation of the pack"))
1119 -v, --verbosity=LEVEL use the given verbosity LEVEL"))
1121 --bootstrap use the bootstrap binaries to build the pack"))
1124 -h, --help display this help and exit"))
1126 -V, --version display version information and exit"))
1128 (show-bug-report-information))
1135 (define-command (guix-pack . args)
1136 (category development)
1137 (synopsis "create application bundles")
1140 (parse-command-line args %options (list %default-options)))
1142 (define maybe-package-argument
1143 ;; Given an option pair, return a package, a package/output tuple, or #f.
1148 (specification->package+output spec))
1150 (('expression . exp)
1151 (read/eval-package-expression exp))
1154 (define (manifest-from-args store opts)
1155 (let* ((transform (options->transformation opts))
1156 (packages (map (match-lambda
1157 (((? package? package) output)
1158 (list (transform package) output))
1159 ((? package? package)
1160 (list (transform package) "out")))
1162 (filter-map maybe-package-argument opts))))
1163 (manifests (filter-map (match-lambda
1164 (('manifest . file) file)
1167 (define with-provenance
1168 (if (assoc-ref opts 'save-provenance?)
1170 (map-manifest-entries
1172 (let ((entry (manifest-entry-with-provenance entry)))
1173 (unless (assq 'provenance (manifest-entry-properties entry))
1174 (warning (G_ "could not determine provenance of package ~a~%")
1175 (manifest-entry-name entry)))
1182 ((and (not (null? manifests)) (not (null? packages)))
1183 (leave (G_ "both a manifest and a package list were given~%")))
1184 ((not (null? manifests))
1185 (concatenate-manifests
1187 (let ((user-module (make-user-module
1188 '((guix profiles) (gnu)))))
1189 (load* file user-module)))
1192 (packages->manifest packages))))))
1194 (with-error-handling
1196 (with-status-verbosity (assoc-ref opts 'verbosity)
1197 ;; Set the build options before we do anything else.
1198 (set-build-options-from-command-line store opts)
1200 (with-build-handler (build-notifier #:dry-run?
1201 (assoc-ref opts 'dry-run?)
1203 (assoc-ref opts 'verbosity)
1205 (assoc-ref opts 'substitutes?))
1206 (parameterize ((%graft? (assoc-ref opts 'graft?))
1207 (%guile-for-build (package-derivation
1209 (if (assoc-ref opts 'bootstrap?)
1212 (assoc-ref opts 'system)
1213 #:graft? (assoc-ref opts 'graft?))))
1214 (let* ((derivation? (assoc-ref opts 'derivation-only?))
1215 (relocatable? (assoc-ref opts 'relocatable?))
1216 (proot? (eq? relocatable? 'proot))
1217 (manifest (let ((manifest (manifest-from-args store opts)))
1218 ;; Note: We cannot honor '--bootstrap' here because
1219 ;; 'glibc-bootstrap' lacks 'libc.a'.
1221 (map-manifest-entries
1222 (cut wrapped-manifest-entry <> #:proot? proot?)
1225 (pack-format (assoc-ref opts 'format))
1226 (target (assoc-ref opts 'target))
1227 (bootstrap? (assoc-ref opts 'bootstrap?))
1228 (compressor (if bootstrap?
1230 (assoc-ref opts 'compressor)))
1231 (archiver (if (equal? pack-format 'squashfs)
1234 %bootstrap-coreutils&co
1236 (symlinks (assoc-ref opts 'symlinks))
1237 (build-image (match (assq-ref %formats pack-format)
1238 ((? procedure? proc) proc)
1240 (leave (G_ "~a: unknown pack format~%")
1242 (localstatedir? (assoc-ref opts 'localstatedir?))
1243 (entry-point (assoc-ref opts 'entry-point))
1244 (profile-name (assoc-ref opts 'profile-name))
1245 (gc-root (assoc-ref opts 'gc-root))
1249 ;; Always produce relative symlinks for
1251 ;; <https://bugs.gnu.org/34913>).
1254 (eq? 'squashfs pack-format)))
1256 (hooks (if bootstrap?
1258 %default-profile-hooks))
1259 (locales? (not bootstrap?))))
1260 (name (string-append (manifest->friendly-name manifest)
1261 "-" (symbol->string pack-format)
1263 (define (lookup-package package)
1264 (manifest-lookup manifest (manifest-pattern (name package))))
1266 (when (null? (manifest-entries manifest))
1267 (warning (G_ "no packages specified; building an empty pack~%")))
1269 (when (and (eq? pack-format 'squashfs)
1270 (not (any lookup-package '("bash" "bash-minimal"))))
1271 (warning (G_ "Singularity requires you to provide a shell~%"))
1272 (display-hint (G_ "Add @code{bash} or @code{bash-minimal} \
1273 to your package list.")))
1275 (run-with-store store
1276 (mlet* %store-monad ((drv (build-image name profile
1291 (mbegin %store-monad
1293 (return (format #t "~a~%"
1294 (derivation-file-name drv))))
1295 (munless derivation?
1296 (built-derivations (list drv))
1298 (register-root* (match (derivation->output-paths drv)
1299 (((names . items) ...)
1302 (return (format #t "~a~%"
1303 (derivation->output-path drv))))))
1305 #:system (assoc-ref opts 'system)))))))))