pack.scm 74 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782
  1. ;;; GNU Guix --- Functional package management for GNU
  2. ;;; Copyright © 2015, 2017-2023 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, 2021, 2022, 2023 Maxim Cournoyer <maxim.cournoyer@gmail.com>
  9. ;;; Copyright © 2020 Eric Bavier <bavier@posteo.net>
  10. ;;; Copyright © 2022 Alex Griffin <a@ajgrf.com>
  11. ;;;
  12. ;;; This file is part of GNU Guix.
  13. ;;;
  14. ;;; GNU Guix is free software; you can redistribute it and/or modify it
  15. ;;; under the terms of the GNU General Public License as published by
  16. ;;; the Free Software Foundation; either version 3 of the License, or (at
  17. ;;; your option) any later version.
  18. ;;;
  19. ;;; GNU Guix is distributed in the hope that it will be useful, but
  20. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  21. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22. ;;; GNU General Public License for more details.
  23. ;;;
  24. ;;; You should have received a copy of the GNU General Public License
  25. ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
  26. (define-module (guix scripts pack)
  27. #:use-module (guix scripts)
  28. #:use-module (guix ui)
  29. #:use-module (guix gexp)
  30. #:use-module (guix utils)
  31. #:use-module (guix store)
  32. #:use-module ((guix status) #:select (with-status-verbosity))
  33. #:use-module ((guix self) #:select (make-config.scm))
  34. #:autoload (guix inferior) (inferior-package?
  35. inferior-package-name
  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 diagnostics)
  44. #:use-module (guix search-paths)
  45. #:use-module (guix build-system gnu)
  46. #:use-module (guix scripts build)
  47. #:use-module (guix transformations)
  48. #:use-module ((guix self) #:select (make-config.scm))
  49. #:use-module (gnu compression)
  50. #:use-module (gnu packages)
  51. #:use-module (gnu packages bootstrap)
  52. #:use-module ((gnu packages compression) #:hide (zip))
  53. #:use-module (gnu packages guile)
  54. #:use-module (gnu packages base)
  55. #:autoload (gnu packages gnupg) (guile-gcrypt)
  56. #:autoload (gnu packages guile) (guile2.0-json guile-json)
  57. #:use-module (srfi srfi-1)
  58. #:use-module (srfi srfi-9)
  59. #:use-module (srfi srfi-26)
  60. #:use-module (srfi srfi-35)
  61. #:use-module (srfi srfi-37)
  62. #:use-module (ice-9 match)
  63. #:export (symlink-spec-option-parser
  64. self-contained-tarball
  65. debian-archive
  66. rpm-archive
  67. docker-image
  68. squashfs-image
  69. %formats
  70. guix-pack))
  71. ;; This one is only for use in this module, so don't put it in %compressors.
  72. (define bootstrap-xz
  73. (compressor "bootstrap-xz" ".xz"
  74. #~(append (list #+(file-append %bootstrap-coreutils&co "/bin/xz")
  75. "-e")
  76. (%xz-parallel-args))))
  77. (define not-config?
  78. ;; Select (guix …) and (gnu …) modules, except (guix config).
  79. (match-lambda
  80. (('guix 'config) #f)
  81. (('guix _ ...) #t)
  82. (('gnu _ ...) #t)
  83. (_ #f)))
  84. (define gcrypt-sqlite3&co
  85. ;; Guile-Gcrypt, Guile-SQLite3, and their propagated inputs.
  86. (append-map (lambda (package)
  87. (cons package
  88. (match (package-transitive-propagated-inputs package)
  89. (((labels packages) ...)
  90. packages))))
  91. (list guile-gcrypt guile-sqlite3)))
  92. (define (store-database items)
  93. "Return a directory containing a store database where all of ITEMS and their
  94. dependencies are registered."
  95. (define schema
  96. (local-file (search-path %load-path
  97. "guix/store/schema.sql")))
  98. (define labels
  99. (map (lambda (n)
  100. (string-append "closure" (number->string n)))
  101. (iota (length items))))
  102. (define build
  103. (with-extensions gcrypt-sqlite3&co
  104. (with-imported-modules `(((guix config) => ,(make-config.scm))
  105. ,@(source-module-closure
  106. '((guix build store-copy)
  107. (guix store database))
  108. #:select? not-config?))
  109. #~(begin
  110. (use-modules (guix store database)
  111. (guix build store-copy)
  112. (srfi srfi-1))
  113. (define (read-closure closure)
  114. (call-with-input-file closure read-reference-graph))
  115. (define db-file
  116. (store-database-file #:state-directory #$output))
  117. ;; Make sure non-ASCII file names are properly handled.
  118. (setenv "GUIX_LOCPATH"
  119. #+(file-append glibc-utf8-locales "/lib/locale"))
  120. (setlocale LC_ALL "en_US.utf8")
  121. (sql-schema #$schema)
  122. (let ((items (append-map read-closure '#$labels)))
  123. (with-database db-file db
  124. (register-items db items
  125. #:registration-time %epoch)))))))
  126. (computed-file "store-database" build
  127. #:options `(#:references-graphs ,(zip labels items))))
  128. (define-syntax-rule (define-with-source (variable args ...) body body* ...)
  129. "Bind VARIABLE to a procedure accepting ARGS defined as BODY, also setting
  130. its source property."
  131. (begin
  132. (define (variable args ...)
  133. body body* ...)
  134. (eval-when (load eval)
  135. (set-procedure-property! variable 'source
  136. '(define (variable args ...) body body* ...)))))
  137. (define-with-source (manifest->friendly-name manifest)
  138. "Return a friendly name computed from the entries in MANIFEST, a
  139. <manifest> object."
  140. (let loop ((names (map manifest-entry-name
  141. (manifest-entries manifest))))
  142. (define str (string-join names "-"))
  143. (if (< (string-length str) 40)
  144. str
  145. (match names
  146. ((_) str)
  147. ((names ... _) (loop names))))))
  148. (define (symlink-spec-option-parser opt name arg result)
  149. "A SRFI-37 option parser for the --symlink option. The symlink spec accepts
  150. the link file name as its left-hand side value and its target as its
  151. right-hand side value. The target must be a relative link."
  152. ;; Note: Using 'string-split' allows us to handle empty
  153. ;; TARGET (as in "/opt/guile=", meaning that /opt/guile is
  154. ;; a symlink to the profile) correctly.
  155. (match (string-split arg #\=)
  156. ((source target)
  157. (when (string-prefix? "/" target)
  158. (raise-exception
  159. (make-compound-condition
  160. (formatted-message (G_ "symlink target is absolute: '~a'~%") target)
  161. (condition
  162. (&fix-hint (hint (format #f (G_ "The target of the symlink must be
  163. relative rather than absolute, as it is relative to the profile created.
  164. Perhaps the source and target components of the symlink spec were inverted?
  165. Below is a valid example, where the @file{/usr/bin/env} symbolic link is to
  166. target the profile's @file{bin/env} file:
  167. @example
  168. --symlink=/usr/bin/env=bin/env
  169. @end example"))))))))
  170. (let ((symlinks (assoc-ref result 'symlinks)))
  171. (alist-cons 'symlinks
  172. `((,source -> ,target) ,@symlinks)
  173. (alist-delete 'symlinks result eq?))))
  174. (x
  175. (leave (G_ "~a: invalid symlink specification~%")
  176. arg))))
  177. (define (set-utf8-locale profile)
  178. "Configure the environment to use the \"en_US.utf8\" locale provided by the
  179. GLIBC-UT8-LOCALES package."
  180. ;; Arrange to not depend on 'glibc-utf8-locales' when using '--bootstrap'.
  181. (and (or (not (profile? profile))
  182. (profile-locales? profile))
  183. #~(begin
  184. (setenv "GUIX_LOCPATH"
  185. #+(file-append glibc-utf8-locales "/lib/locale"))
  186. (setlocale LC_ALL "en_US.utf8"))))
  187. (define* (populate-profile-root profile
  188. #:key (profile-name "guix-profile")
  189. target
  190. localstatedir?
  191. deduplicate?
  192. (symlinks '()))
  193. "Populate the root profile directory with SYMLINKS and a Guix database, when
  194. LOCALSTATEDIR? is set. When DEDUPLICATE? is true, deduplicate the store
  195. items, which relies on hard links."
  196. (define database
  197. (and localstatedir?
  198. (file-append (store-database (list profile))
  199. "/db/db.sqlite")))
  200. (define bootstrap?
  201. ;; Whether a '--bootstrap' environment is needed, for testing purposes.
  202. ;; XXX: Infer that from available info.
  203. (and (not database) (not (profile-locales? profile))))
  204. (define (import-module? module)
  205. ;; Since we don't use deduplication support in 'populate-store', don't
  206. ;; import (guix store deduplication) and its dependencies, which includes
  207. ;; Guile-Gcrypt, unless DEDUPLICATE? is #t. This makes it possible to run
  208. ;; tests with '--bootstrap'.
  209. (and (not-config? module)
  210. (or deduplicate? (not (equal? '(guix store deduplication) module)))))
  211. (computed-file "profile-directory"
  212. (with-imported-modules (source-module-closure
  213. `((guix build pack)
  214. (guix build store-copy)
  215. (guix build utils)
  216. (guix build union)
  217. (gnu build install))
  218. #:select? import-module?)
  219. #~(begin
  220. (use-modules (guix build pack)
  221. (guix build store-copy)
  222. (guix build utils)
  223. ((guix build union) #:select (relative-file-name))
  224. (gnu build install)
  225. (srfi srfi-1)
  226. (srfi srfi-26)
  227. (ice-9 match))
  228. (define symlink->directives
  229. ;; Return "populate directives" to make the given symlink and its
  230. ;; parent directories.
  231. (match-lambda
  232. ((source '-> target)
  233. (let ((target (string-append #$profile "/" target))
  234. (parent (dirname source)))
  235. ;; Never add a 'directory' directive for "/" so as to
  236. ;; preserve its ownership when extracting the archive (see
  237. ;; below), and also because this would lead to adding the
  238. ;; same entries twice in the tarball.
  239. `(,@(if (string=? parent "/")
  240. '()
  241. `((directory ,parent)))
  242. ;; Use a relative file name for compatibility with
  243. ;; relocatable packs.
  244. (,source -> ,(relative-file-name parent target)))))))
  245. (define directives
  246. ;; Fully-qualified symlinks.
  247. (append-map symlink->directives '#$symlinks))
  248. ;; Make sure non-ASCII file names are properly handled.
  249. #+(set-utf8-locale profile)
  250. ;; Note: there is not much to gain here with deduplication and there
  251. ;; is the overhead of the '.links' directory, so turn it off by
  252. ;; default. Furthermore GNU tar < 1.30 sometimes fails to extract
  253. ;; tarballs with hard links:
  254. ;; <http://lists.gnu.org/archive/html/bug-tar/2017-11/msg00009.html>.
  255. (populate-store (list "profile") #$output
  256. #:deduplicate? #$deduplicate?)
  257. (when #+localstatedir?
  258. (install-database-and-gc-roots #$output #+database #$profile
  259. #:profile-name #$profile-name))
  260. ;; Create SYMLINKS.
  261. (for-each (cut evaluate-populate-directive <> #$output)
  262. directives)))
  263. #:local-build? #f
  264. #:guile (if bootstrap? %bootstrap-guile (default-guile))
  265. #:options (list #:references-graphs `(("profile" ,profile))
  266. #:target target)))
  267. ;;;
  268. ;;; Tarball format.
  269. ;;;
  270. (define* (self-contained-tarball/builder profile
  271. #:key (profile-name "guix-profile")
  272. target
  273. localstatedir?
  274. deduplicate?
  275. symlinks
  276. compressor
  277. archiver)
  278. "Return a GEXP that can build a self-contained tarball."
  279. (define root (populate-profile-root profile
  280. #:profile-name profile-name
  281. #:target target
  282. #:localstatedir? localstatedir?
  283. #:deduplicate? deduplicate?
  284. #:symlinks symlinks))
  285. (with-imported-modules (source-module-closure '((guix build pack)
  286. (guix build utils)))
  287. #~(begin
  288. (use-modules (guix build pack)
  289. (guix build utils))
  290. ;; Make sure non-ASCII file names are properly handled.
  291. #+(set-utf8-locale profile)
  292. (define tar #+(file-append archiver "/bin/tar"))
  293. (define %root (if #$localstatedir? "." #$root))
  294. (when #$localstatedir?
  295. ;; Fix the permission of the Guix database file, which was made
  296. ;; read-only when copied to the store in populate-profile-root.
  297. (copy-recursively #$root %root)
  298. (chmod (string-append %root "/var/guix/db/db.sqlite") #o644))
  299. (with-directory-excursion %root
  300. ;; GNU Tar recurses directories by default. Simply add the whole
  301. ;; current directory, which contains all the files to be archived.
  302. ;; This avoids creating duplicate files in the archives that would
  303. ;; be stored as hard links by GNU Tar.
  304. (apply invoke tar "-cvf" #$output "."
  305. (tar-base-options
  306. #:tar tar
  307. #:compressor #+(and=> compressor compressor-command)))))))
  308. (define* (self-contained-tarball name profile
  309. #:key target
  310. (profile-name "guix-profile")
  311. deduplicate?
  312. entry-point
  313. (compressor (first %compressors))
  314. localstatedir?
  315. (symlinks '())
  316. (archiver tar)
  317. (extra-options '()))
  318. "Return a self-contained tarball containing a store initialized with the
  319. closure of PROFILE, a derivation. The tarball contains /gnu/store; if
  320. LOCALSTATEDIR? is true, it also contains /var/guix, including /var/guix/db
  321. with a properly initialized store database.
  322. SYMLINKS must be a list of (SOURCE -> TARGET) tuples denoting symlinks to be
  323. added to the pack."
  324. (when entry-point
  325. (warning (G_ "entry point not supported in the '~a' format~%")
  326. 'tarball))
  327. (gexp->derivation (string-append name ".tar"
  328. (compressor-extension compressor))
  329. (self-contained-tarball/builder profile
  330. #:profile-name profile-name
  331. #:target target
  332. #:localstatedir? localstatedir?
  333. #:deduplicate? deduplicate?
  334. #:symlinks symlinks
  335. #:compressor compressor
  336. #:archiver archiver)))
  337. ;;;
  338. ;;; Singularity.
  339. ;;;
  340. (define (singularity-environment-file profile)
  341. "Return a shell script that defines the environment variables corresponding
  342. to the search paths of PROFILE."
  343. (define build
  344. (with-extensions (list guile-gcrypt)
  345. (with-imported-modules `(((guix config) => ,(make-config.scm))
  346. ,@(source-module-closure
  347. `((guix profiles)
  348. (guix search-paths))
  349. #:select? not-config?))
  350. #~(begin
  351. (use-modules (guix profiles) (guix search-paths)
  352. (ice-9 match))
  353. (call-with-output-file #$output
  354. (lambda (port)
  355. (for-each (match-lambda
  356. ((spec . value)
  357. (format port "~a=~a~%export ~a~%"
  358. (search-path-specification-variable spec)
  359. value
  360. (search-path-specification-variable spec))))
  361. (profile-search-paths #$profile))))))))
  362. (computed-file "singularity-environment.sh" build))
  363. ;;;
  364. ;;; SquashFS image format.
  365. ;;;
  366. (define* (squashfs-image name profile
  367. #:key target
  368. (profile-name "guix-profile")
  369. (compressor (first %compressors))
  370. entry-point
  371. localstatedir?
  372. (symlinks '())
  373. (archiver squashfs-tools)
  374. (extra-options '()))
  375. "Return a squashfs image containing a store initialized with the closure of
  376. PROFILE, a derivation. The image contains a subset of /gnu/store, empty mount
  377. points for virtual file systems (like procfs), and optional symlinks.
  378. SYMLINKS must be a list of (SOURCE -> TARGET) tuples denoting symlinks to be
  379. added to the pack."
  380. (define database
  381. (and localstatedir?
  382. (file-append (store-database (list profile))
  383. "/db/db.sqlite")))
  384. (define environment
  385. (singularity-environment-file profile))
  386. (define symlinks*
  387. ;; Singularity requires /bin (specifically /bin/sh), so ensure that
  388. ;; symlink is created.
  389. (if (find (match-lambda
  390. (("/bin" . _) #t)
  391. (_ #f))
  392. symlinks)
  393. symlinks
  394. `(("/bin" -> "bin") ,@symlinks)))
  395. (define build
  396. (with-extensions (list guile-gcrypt)
  397. (with-imported-modules (source-module-closure
  398. '((guix build utils)
  399. (guix build store-copy)
  400. (guix build union)
  401. (gnu build install))
  402. #:select? not-config?)
  403. #~(begin
  404. (use-modules (guix build utils)
  405. (guix build store-copy)
  406. ((guix build union) #:select (relative-file-name))
  407. (gnu build install)
  408. (srfi srfi-1)
  409. (srfi srfi-26)
  410. (ice-9 match))
  411. (define database #+database)
  412. (define entry-point #$entry-point)
  413. (define (mksquashfs args)
  414. (apply invoke "mksquashfs"
  415. `(,@args
  416. ;; Do not create a "recovery file" when appending to the
  417. ;; file system since it's useless in this case.
  418. "-no-recovery"
  419. ;; Do not attempt to store extended attributes.
  420. ;; See <https://bugs.gnu.org/40043>.
  421. "-no-xattrs"
  422. ;; Set file times and the file system creation time to
  423. ;; one second after the Epoch.
  424. "-all-time" "1" "-mkfs-time" "1"
  425. ;; Reset all UIDs and GIDs.
  426. "-force-uid" "0" "-force-gid" "0")))
  427. (setenv "PATH" #+(file-append archiver "/bin"))
  428. ;; We need an empty file in order to have a valid file argument when
  429. ;; we reparent the root file system. Read on for why that's
  430. ;; necessary.
  431. (with-output-to-file ".empty" (lambda () (display "")))
  432. ;; Create the squashfs image in several steps.
  433. ;; Add all store items. Unfortunately mksquashfs throws away all
  434. ;; ancestor directories and only keeps the basename. We fix this
  435. ;; in the following invocations of mksquashfs.
  436. (mksquashfs `(,@(map store-info-item
  437. (call-with-input-file "profile"
  438. read-reference-graph))
  439. #$environment
  440. ,#$output
  441. ;; Do not perform duplicate checking because we
  442. ;; don't have any dupes.
  443. "-no-duplicates"
  444. "-comp"
  445. ,#+(compressor-name compressor)))
  446. ;; Here we reparent the store items. For each sub-directory of
  447. ;; the store prefix we need one invocation of "mksquashfs".
  448. (for-each (lambda (dir)
  449. (mksquashfs `(".empty"
  450. ,#$output
  451. "-root-becomes" ,dir)))
  452. (reverse (string-tokenize (%store-directory)
  453. (char-set-complement (char-set #\/)))))
  454. ;; Add symlinks and mount points.
  455. (mksquashfs
  456. `(".empty"
  457. ,#$output
  458. ;; Create SYMLINKS via pseudo file definitions.
  459. ,@(append-map
  460. (match-lambda
  461. ((source '-> target)
  462. ;; Create relative symlinks to work around a bug in
  463. ;; Singularity 2.x:
  464. ;; https://bugs.gnu.org/34913
  465. ;; https://github.com/sylabs/singularity/issues/1487
  466. (let ((target (string-append #$profile "/" target)))
  467. (list "-p"
  468. (string-join
  469. ;; name s mode uid gid symlink
  470. (list source
  471. "s" "777" "0" "0"
  472. (relative-file-name (dirname source)
  473. target)))))))
  474. '#$symlinks*)
  475. "-p" "/.singularity.d d 555 0 0"
  476. ;; Create the environment file.
  477. "-p" "/.singularity.d/env d 555 0 0"
  478. "-p" ,(string-append
  479. "/.singularity.d/env/90-environment.sh s 777 0 0 "
  480. (relative-file-name "/.singularity.d/env"
  481. #$environment))
  482. ;; Create /.singularity.d/actions, and optionally the 'run'
  483. ;; script, used by 'singularity run'.
  484. "-p" "/.singularity.d/actions d 555 0 0"
  485. ,@(if entry-point
  486. `( ;; This one if for Singularity 2.x.
  487. "-p"
  488. ,(string-append
  489. "/.singularity.d/actions/run s 777 0 0 "
  490. (relative-file-name "/.singularity.d/actions"
  491. (string-append #$profile "/"
  492. entry-point)))
  493. ;; This one is for Singularity 3.x.
  494. "-p"
  495. ,(string-append
  496. "/.singularity.d/runscript s 777 0 0 "
  497. (relative-file-name "/.singularity.d"
  498. (string-append #$profile "/"
  499. entry-point))))
  500. '())
  501. ;; Create empty mount points.
  502. "-p" "/proc d 555 0 0"
  503. "-p" "/sys d 555 0 0"
  504. "-p" "/dev d 555 0 0"
  505. "-p" "/home d 555 0 0"))
  506. (when database
  507. ;; Initialize /var/guix.
  508. (install-database-and-gc-roots "var-etc" database #$profile)
  509. (mksquashfs `("var-etc" ,#$output)))))))
  510. (gexp->derivation (string-append name
  511. (compressor-extension compressor)
  512. ".squashfs")
  513. build
  514. #:target target
  515. #:references-graphs `(("profile" ,profile))))
  516. ;;;
  517. ;;; Docker image format.
  518. ;;;
  519. (define* (docker-image name profile
  520. #:key target
  521. (profile-name "guix-profile")
  522. (compressor (first %compressors))
  523. entry-point
  524. localstatedir?
  525. (symlinks '())
  526. (archiver tar)
  527. (extra-options '()))
  528. "Return a derivation to construct a Docker image of PROFILE. The
  529. image is a tarball conforming to the Docker Image Specification, compressed
  530. with COMPRESSOR. It can be passed to 'docker load'. If TARGET is true, it
  531. must a be a GNU triplet and it is used to derive the architecture metadata in
  532. the image."
  533. (define database
  534. (and localstatedir?
  535. (file-append (store-database (list profile))
  536. "/db/db.sqlite")))
  537. (define defmod 'define-module) ;trick Geiser
  538. (define build
  539. ;; Guile-JSON and Guile-Gcrypt are required by (guix docker).
  540. (with-extensions (list guile-json-3 guile-gcrypt)
  541. (with-imported-modules `(((guix config) => ,(make-config.scm))
  542. ,@(source-module-closure
  543. `((guix docker)
  544. (guix build store-copy)
  545. (guix build utils) ;for %xz-parallel-args
  546. (guix profiles)
  547. (guix search-paths))
  548. #:select? not-config?))
  549. #~(begin
  550. (use-modules (guix docker) (guix build store-copy)
  551. (guix build utils)
  552. (guix profiles) (guix search-paths)
  553. (srfi srfi-1) (srfi srfi-19)
  554. (ice-9 match))
  555. #$(procedure-source manifest->friendly-name)
  556. (define environment
  557. (map (match-lambda
  558. ((spec . value)
  559. (cons (search-path-specification-variable spec)
  560. value)))
  561. (profile-search-paths #$profile)))
  562. (define symlink->directives
  563. ;; Return "populate directives" to make the given symlink and its
  564. ;; parent directories.
  565. (match-lambda
  566. ((source '-> target)
  567. (let ((target (string-append #$profile "/" target))
  568. (parent (dirname source)))
  569. `((directory ,parent)
  570. (,source -> ,target))))))
  571. (define directives
  572. ;; Create a /tmp directory, as some programs expect it, and
  573. ;; create SYMLINKS.
  574. `((directory "/tmp" ,(getuid) ,(getgid) #o1777)
  575. ,@(append-map symlink->directives '#$symlinks)))
  576. (setenv "PATH" #+(file-append archiver "/bin"))
  577. (build-docker-image #$output
  578. (map store-info-item
  579. (call-with-input-file "profile"
  580. read-reference-graph))
  581. #$profile
  582. #:repository (manifest->friendly-name
  583. (profile-manifest #$profile))
  584. #:database #+database
  585. #:system (or #$target %host-type)
  586. #:environment environment
  587. #:entry-point
  588. #$(and entry-point
  589. #~(list (string-append #$profile "/"
  590. #$entry-point)))
  591. #:extra-files directives
  592. #:compressor #+(compressor-command compressor)
  593. #:creation-time (make-time time-utc 0 1))))))
  594. (gexp->derivation (string-append name ".tar"
  595. (compressor-extension compressor))
  596. build
  597. #:target target
  598. #:references-graphs `(("profile" ,profile))))
  599. ;;;
  600. ;;; Debian archive format.
  601. ;;;
  602. ;;; TODO: When relocatable option is selected, install to a unique prefix.
  603. ;;; This would enable installation of multiple deb packs with conflicting
  604. ;;; files at the same time.
  605. (define* (debian-archive name profile
  606. #:key target
  607. (profile-name "guix-profile")
  608. deduplicate?
  609. entry-point
  610. (compressor (first %compressors))
  611. localstatedir?
  612. (symlinks '())
  613. (archiver tar)
  614. (extra-options '()))
  615. "Return a Debian archive (.deb) containing a store initialized with the
  616. closure of PROFILE, a derivation. The archive contains /gnu/store; if
  617. LOCALSTATEDIR? is true, it also contains /var/guix, including /var/guix/db
  618. with a properly initialized store database. The supported compressors are
  619. \"none\", \"gz\" or \"xz\".
  620. SYMLINKS must be a list of (SOURCE -> TARGET) tuples denoting symlinks to be
  621. added to the pack. EXTRA-OPTIONS may contain the CONFIG-FILE, POSTINST-FILE
  622. or TRIGGERS-FILE keyword arguments."
  623. ;; For simplicity, limit the supported compressors to the superset of
  624. ;; compressors able to compress both the control file (gz or xz) and the
  625. ;; data tarball (gz, bz2 or xz).
  626. (define %valid-compressors '("gzip" "xz" "none"))
  627. (let ((compressor-name (compressor-name compressor)))
  628. (unless (member compressor-name %valid-compressors)
  629. (leave (G_ "~a is not a valid Debian archive compressor. \
  630. Valid compressors are: ~a~%") compressor-name %valid-compressors)))
  631. (when entry-point
  632. (warning (G_ "entry point not supported in the '~a' format~%")
  633. 'deb))
  634. (define data-tarball
  635. (computed-file (string-append "data.tar" (compressor-extension
  636. compressor))
  637. (self-contained-tarball/builder profile
  638. #:target target
  639. #:profile-name profile-name
  640. #:localstatedir? localstatedir?
  641. #:deduplicate? deduplicate?
  642. #:symlinks symlinks
  643. #:compressor compressor
  644. #:archiver archiver)
  645. #:local-build? #f ;allow offloading
  646. #:options (list #:references-graphs `(("profile" ,profile))
  647. #:target target)))
  648. (define build
  649. (with-extensions (list guile-gcrypt)
  650. (with-imported-modules `(((guix config) => ,(make-config.scm))
  651. ,@(source-module-closure
  652. `((guix build pack)
  653. (guix build utils)
  654. (guix profiles))
  655. #:select? not-config?))
  656. #~(begin
  657. (use-modules (guix build pack)
  658. (guix build utils)
  659. (guix profiles)
  660. (ice-9 match)
  661. (ice-9 optargs)
  662. (srfi srfi-1))
  663. (define machine-type
  664. ;; Extract the machine type from the specified target, else from the
  665. ;; current system.
  666. (and=> (or #$target %host-type)
  667. (lambda (triplet)
  668. (first (string-split triplet #\-)))))
  669. (define (gnu-machine-type->debian-machine-type type)
  670. "Translate machine TYPE from the GNU to Debian terminology."
  671. ;; Debian has its own jargon, different from the one used in GNU, for
  672. ;; machine types (see data/cputable in the sources of dpkg).
  673. (match type
  674. ("i486" "i386")
  675. ("i586" "i386")
  676. ("i686" "i386")
  677. ("x86_64" "amd64")
  678. ("aarch64" "arm64")
  679. ("mipsisa32r6" "mipsr6")
  680. ("mipsisa32r6el" "mipsr6el")
  681. ("mipsisa64r6" "mips64r6")
  682. ("mipsisa64r6el" "mips64r6el")
  683. ("powerpcle" "powerpcel")
  684. ("powerpc64" "ppc64")
  685. ("powerpc64le" "ppc64el")
  686. (machine machine)))
  687. (define architecture
  688. (gnu-machine-type->debian-machine-type machine-type))
  689. #$(procedure-source manifest->friendly-name)
  690. (define manifest (profile-manifest #$profile))
  691. (define single-entry ;manifest entry
  692. (match (manifest-entries manifest)
  693. ((entry)
  694. entry)
  695. (_ #f)))
  696. (define package-name (or (and=> single-entry manifest-entry-name)
  697. (manifest->friendly-name manifest)))
  698. (define package-version
  699. (or (and=> single-entry manifest-entry-version)
  700. "0.0.0"))
  701. (define debian-format-version "2.0")
  702. ;; Generate the debian-binary file.
  703. (call-with-output-file "debian-binary"
  704. (lambda (port)
  705. (format port "~a~%" debian-format-version)))
  706. (define data-tarball-file-name (strip-store-file-name
  707. #+data-tarball))
  708. (copy-file #+data-tarball data-tarball-file-name)
  709. ;; Generate the control archive.
  710. (let-keywords '#$extra-options #f
  711. ((control-file #f)
  712. (postinst-file #f)
  713. (triggers-file #f))
  714. (define control-tarball-file-name
  715. (string-append "control.tar"
  716. #$(compressor-extension compressor)))
  717. ;; Write the compressed control tarball. Only the control file is
  718. ;; mandatory (see: 'man deb' and 'man deb-control').
  719. (if control-file
  720. (copy-file control-file "control")
  721. (call-with-output-file "control"
  722. (lambda (port)
  723. (format port "\
  724. Package: ~a
  725. Version: ~a
  726. Description: Debian archive generated by GNU Guix.
  727. Maintainer: GNU Guix
  728. Architecture: ~a
  729. Priority: optional
  730. Section: misc
  731. ~%" package-name package-version architecture))))
  732. (when postinst-file
  733. (copy-file postinst-file "postinst")
  734. (chmod "postinst" #o755))
  735. (when triggers-file
  736. (copy-file triggers-file "triggers"))
  737. (define tar (string-append #+archiver "/bin/tar"))
  738. (apply invoke tar
  739. `(,@(tar-base-options
  740. #:tar tar
  741. #:compressor #+(and=> compressor compressor-command))
  742. "-cvf" ,control-tarball-file-name
  743. "control"
  744. ,@(if postinst-file '("postinst") '())
  745. ,@(if triggers-file '("triggers") '())))
  746. ;; Create the .deb archive using GNU ar.
  747. (invoke (string-append #+binutils "/bin/ar") "-rv" #$output
  748. "debian-binary"
  749. control-tarball-file-name data-tarball-file-name))))))
  750. (gexp->derivation (string-append name ".deb") build))
  751. ;;;
  752. ;;; RPM archive format.
  753. ;;;
  754. (define* (rpm-archive name profile
  755. #:key target
  756. (profile-name "guix-profile")
  757. entry-point
  758. (compressor (first %compressors))
  759. deduplicate?
  760. localstatedir?
  761. (symlinks '())
  762. archiver
  763. (extra-options '()))
  764. "Return a RPM archive (.rpm) containing a store initialized with the closure
  765. of PROFILE, a derivation. The archive contains /gnu/store. SYMLINKS must be
  766. a list of (SOURCE -> TARGET) tuples denoting symlinks to be added to the pack.
  767. ARCHIVER and ENTRY-POINT are not used. RELOCATABLE?, PREIN-FILE, POSTIN-FILE,
  768. PREUN-FILE and POSTUN-FILE can be provided via EXTRA-OPTIONS."
  769. (when entry-point
  770. (warning (G_ "entry point not supported in the '~a' format~%") 'rpm))
  771. (define root (populate-profile-root profile
  772. #:profile-name profile-name
  773. #:target target
  774. #:localstatedir? localstatedir?
  775. #:deduplicate? deduplicate?
  776. #:symlinks symlinks))
  777. (define payload
  778. (let* ((raw-cpio-file-name "payload.cpio")
  779. (compressed-cpio-file-name (string-append raw-cpio-file-name
  780. (compressor-extension
  781. compressor))))
  782. (computed-file compressed-cpio-file-name
  783. (with-imported-modules (source-module-closure
  784. '((guix build utils)
  785. (guix cpio)
  786. (guix rpm)))
  787. #~(begin
  788. (use-modules (guix build utils)
  789. (guix cpio)
  790. (guix rpm)
  791. (srfi srfi-1))
  792. ;; Make sure non-ASCII file names are properly handled.
  793. #+(set-utf8-locale profile)
  794. (define %root (if #$localstatedir? "." #$root))
  795. (when #$localstatedir?
  796. ;; Fix the permission of the Guix database file, which was made
  797. ;; read-only when copied to the store in populate-profile-root.
  798. (copy-recursively #$root %root)
  799. (chmod (string-append %root "/var/guix/db/db.sqlite") #o644))
  800. (call-with-output-file #$raw-cpio-file-name
  801. (lambda (port)
  802. (with-directory-excursion %root
  803. ;; The first "." entry is discarded.
  804. (write-cpio-archive
  805. (remove fhs-directory?
  806. (cdr (find-files "." #:directories? #t)))
  807. port))))
  808. (when #+(compressor-command compressor)
  809. (apply invoke (append #+(compressor-command compressor)
  810. (list #$raw-cpio-file-name))))
  811. (copy-file #$compressed-cpio-file-name #$output)))
  812. #:local-build? #f))) ;allow offloading
  813. (define build
  814. (with-extensions (list guile-gcrypt)
  815. (with-imported-modules `(((guix config) => ,(make-config.scm))
  816. ,@(source-module-closure
  817. `((gcrypt hash)
  818. (guix build utils)
  819. (guix profiles)
  820. (guix rpm))
  821. #:select? not-config?))
  822. #~(begin
  823. (use-modules (gcrypt hash)
  824. (guix build utils)
  825. (guix profiles)
  826. (guix rpm)
  827. (ice-9 binary-ports)
  828. (ice-9 match) ;for manifest->friendly-name
  829. (ice-9 optargs)
  830. (rnrs bytevectors)
  831. (srfi srfi-1))
  832. ;; Make sure non-ASCII file names are properly handled.
  833. #+(set-utf8-locale profile)
  834. (define machine-type
  835. (and=> (or #$target %host-type)
  836. (lambda (triplet)
  837. (first (string-split triplet #\-)))))
  838. #$(procedure-source manifest->friendly-name)
  839. (define manifest (profile-manifest #$profile))
  840. (define single-entry ;manifest entry
  841. (match (manifest-entries manifest)
  842. ((entry)
  843. entry)
  844. (_ #f)))
  845. (define name
  846. (or (and=> single-entry manifest-entry-name)
  847. (manifest->friendly-name manifest)))
  848. (define version
  849. (or (and=> single-entry manifest-entry-version) "0.0.0"))
  850. (define lead
  851. (generate-lead (string-append name "-" version)
  852. #:target (or #$target %host-type)))
  853. (define payload-digest
  854. (bytevector->hex-string (file-sha256 #$payload)))
  855. (let-keywords '#$extra-options #f ((relocatable? #f)
  856. (prein-file #f)
  857. (postin-file #f)
  858. (preun-file #f)
  859. (postun-file #f))
  860. (let ((header (generate-header name version
  861. payload-digest
  862. #$root
  863. #$(compressor-name compressor)
  864. #:target (or #$target %host-type)
  865. #:relocatable? relocatable?
  866. #:prein-file prein-file
  867. #:postin-file postin-file
  868. #:preun-file preun-file
  869. #:postun-file postun-file)))
  870. (define header-sha256
  871. (bytevector->hex-string (sha256 (u8-list->bytevector header))))
  872. (define payload-size (stat:size (stat #$payload)))
  873. (define header+compressed-payload-size
  874. (+ (length header) payload-size))
  875. (define signature
  876. (generate-signature header-sha256
  877. header+compressed-payload-size))
  878. ;; Serialize the archive components to a file.
  879. (call-with-input-file #$payload
  880. (lambda (in)
  881. (call-with-output-file #$output
  882. (lambda (out)
  883. (put-bytevector out (assemble-rpm-metadata lead
  884. signature
  885. header))
  886. (sendfile out in payload-size)))))))))))
  887. (gexp->derivation (string-append name ".rpm") build))
  888. ;;;
  889. ;;; Compiling C programs.
  890. ;;;
  891. ;; A C compiler. That lowers to a single program that can be passed typical C
  892. ;; compiler flags, and it makes sure the whole toolchain is available.
  893. (define-record-type <c-compiler>
  894. (%c-compiler toolchain guile)
  895. c-compiler?
  896. (toolchain c-compiler-toolchain)
  897. (guile c-compiler-guile))
  898. (define* (c-compiler #:optional inputs
  899. #:key (guile (default-guile)))
  900. (%c-compiler inputs guile))
  901. (define (bootstrap-c-compiler)
  902. "Return the C compiler that uses the bootstrap toolchain. This is used only
  903. by '--bootstrap', for testing purposes."
  904. (define bootstrap-toolchain
  905. (list (first (assoc-ref (%bootstrap-inputs) "gcc"))
  906. (first (assoc-ref (%bootstrap-inputs) "binutils"))
  907. (first (assoc-ref (%bootstrap-inputs) "libc"))))
  908. (c-compiler bootstrap-toolchain
  909. #:guile %bootstrap-guile))
  910. (define-gexp-compiler (c-compiler-compiler (compiler <c-compiler>) system target)
  911. "Lower COMPILER to a single script that does the right thing."
  912. (define toolchain
  913. (or (c-compiler-toolchain compiler)
  914. (list (first (assoc-ref (standard-packages) "gcc"))
  915. (first (assoc-ref (standard-packages) "ld-wrapper"))
  916. (first (assoc-ref (standard-packages) "binutils"))
  917. (first (assoc-ref (standard-packages) "libc"))
  918. (gexp-input (first (assoc-ref (standard-packages) "libc"))
  919. "static"))))
  920. (define inputs
  921. (match (append-map package-propagated-inputs
  922. (filter package? toolchain))
  923. (((labels things . _) ...)
  924. (append toolchain things))))
  925. (define search-paths
  926. (cons $PATH
  927. (append-map package-native-search-paths
  928. (filter package? inputs))))
  929. (define run
  930. (with-imported-modules (source-module-closure
  931. '((guix build utils)
  932. (guix search-paths)))
  933. #~(begin
  934. (use-modules (guix build utils) (guix search-paths)
  935. (ice-9 match))
  936. (define (output-file args)
  937. (let loop ((args args))
  938. (match args
  939. (() "a.out")
  940. (("-o" file _ ...) file)
  941. ((head rest ...) (loop rest)))))
  942. (set-search-paths (map sexp->search-path-specification
  943. '#$(map search-path-specification->sexp
  944. search-paths))
  945. '#$inputs)
  946. (let ((output (output-file (command-line))))
  947. (apply invoke "gcc" (cdr (command-line)))
  948. (invoke "strip" output)))))
  949. (when target
  950. ;; TODO: Yep, we'll have to do it someday!
  951. (leave (G_ "cross-compilation not implemented here;
  952. please email '~a'~%")
  953. (@ (guix config) %guix-bug-report-address)))
  954. (gexp->script "c-compiler" run
  955. #:guile (c-compiler-guile compiler)))
  956. ;;;
  957. ;;; Wrapped package.
  958. ;;;
  959. (define* (wrapped-package package
  960. #:optional
  961. (output* "out")
  962. (compiler (c-compiler))
  963. #:key proot?)
  964. "Return the OUTPUT of PACKAGE with its binaries wrapped such that they are
  965. relocatable. When PROOT? is true, include PRoot in the result and use it as a
  966. last resort for relocation."
  967. (define runner
  968. (local-file (search-auxiliary-file "run-in-namespace.c")))
  969. (define audit-source
  970. (local-file (search-auxiliary-file "pack-audit.c")))
  971. (define (proot)
  972. (specification->package "proot-static"))
  973. (define (fakechroot-library)
  974. (computed-file "libfakechroot.so"
  975. #~(copy-file #$(file-append
  976. (specification->package "fakechroot")
  977. "/lib/fakechroot/libfakechroot.so")
  978. #$output)))
  979. (define (audit-module)
  980. ;; Return an ld.so audit module for use by the 'fakechroot' execution
  981. ;; engine that translates file names of all the files ld.so loads.
  982. (computed-file "pack-audit.so"
  983. (with-imported-modules '((guix build utils))
  984. #~(begin
  985. (use-modules (guix build utils))
  986. (copy-file #$audit-source "audit.c")
  987. (substitute* "audit.c"
  988. (("@STORE_DIRECTORY@")
  989. (%store-directory)))
  990. (invoke #$compiler "-std=gnu99"
  991. "-shared" "-fPIC" "-Os" "-g0"
  992. "-Wall" "audit.c" "-o" #$output)))))
  993. (define build
  994. (with-imported-modules (source-module-closure
  995. '((guix build utils)
  996. (guix build union)
  997. (guix build gremlin)
  998. (guix elf)))
  999. #~(begin
  1000. (use-modules (guix build utils)
  1001. ((guix build union) #:select (symlink-relative))
  1002. (guix elf)
  1003. (guix build gremlin)
  1004. (ice-9 binary-ports)
  1005. (ice-9 ftw)
  1006. (ice-9 match)
  1007. (ice-9 receive)
  1008. (srfi srfi-1)
  1009. (rnrs bytevectors))
  1010. (define input
  1011. ;; The OUTPUT* output of PACKAGE.
  1012. (ungexp package output*))
  1013. (define target
  1014. ;; The output we are producing.
  1015. (ungexp output output*))
  1016. (define (strip-store-prefix file)
  1017. ;; Given a file name like "/gnu/store/…-foo-1.2/bin/foo", return
  1018. ;; "/bin/foo".
  1019. (let* ((len (string-length (%store-directory)))
  1020. (base (string-drop file (+ 1 len))))
  1021. (match (string-index base #\/)
  1022. (#f base)
  1023. (index (string-drop base index)))))
  1024. (define (elf-interpreter elf)
  1025. ;; Return the interpreter of ELF as a string, or #f if ELF has no
  1026. ;; interpreter segment.
  1027. (match (find (lambda (segment)
  1028. (= (elf-segment-type segment) PT_INTERP))
  1029. (elf-segments elf))
  1030. (#f #f) ;maybe a .so
  1031. (segment
  1032. (let ((bv (make-bytevector (- (elf-segment-memsz segment) 1))))
  1033. (bytevector-copy! (elf-bytes elf)
  1034. (elf-segment-offset segment)
  1035. bv 0 (bytevector-length bv))
  1036. (utf8->string bv)))))
  1037. (define (runpath file)
  1038. ;; Return the "recursive" RUNPATH of FILE as a list of
  1039. ;; directories.
  1040. (delete-duplicates
  1041. (map dirname (file-needed/recursive file))))
  1042. (define (elf-loader-compile-flags program)
  1043. ;; Return the cpp flags defining macros for the ld.so/fakechroot
  1044. ;; wrapper of PROGRAM.
  1045. ;; TODO: Handle scripts by wrapping their interpreter.
  1046. (if (elf-file? program)
  1047. (let* ((bv (call-with-input-file program
  1048. get-bytevector-all))
  1049. (elf (parse-elf bv))
  1050. (interp (elf-interpreter elf))
  1051. (gconv (and interp
  1052. (string-append (dirname interp)
  1053. "/gconv"))))
  1054. (if interp
  1055. (list (string-append "-DPROGRAM_INTERPRETER=\""
  1056. interp "\"")
  1057. (string-append "-DFAKECHROOT_LIBRARY=\""
  1058. #$(fakechroot-library) "\"")
  1059. (string-append "-DLOADER_AUDIT_MODULE=\""
  1060. #$(audit-module) "\"")
  1061. ;; XXX: Normally (runpath #$(audit-module)) is
  1062. ;; enough. However, to work around
  1063. ;; <https://sourceware.org/bugzilla/show_bug.cgi?id=26634>
  1064. ;; (glibc <= 2.32), pass the whole search path of
  1065. ;; PROGRAM, which presumably is a superset of that
  1066. ;; of the audit module.
  1067. (string-append "-DLOADER_AUDIT_RUNPATH={ "
  1068. (string-join
  1069. (map object->string
  1070. (runpath program))
  1071. ", " 'suffix)
  1072. "NULL }")
  1073. (if gconv
  1074. (string-append "-DGCONV_DIRECTORY=\""
  1075. gconv "\"")
  1076. "-UGCONV_DIRECTORY"))
  1077. '()))
  1078. '()))
  1079. (define (build-wrapper program)
  1080. ;; Build a user-namespace wrapper for PROGRAM.
  1081. (format #t "building wrapper for '~a'...~%" program)
  1082. (copy-file #$runner "run.c")
  1083. (substitute* "run.c"
  1084. (("@WRAPPED_PROGRAM@") program)
  1085. (("@STORE_DIRECTORY@") (%store-directory)))
  1086. (let* ((base (strip-store-prefix program))
  1087. (result (string-append target base))
  1088. (proot #$(and proot?
  1089. #~(string-drop
  1090. #$(file-append (proot) "/bin/proot")
  1091. (+ (string-length (%store-directory))
  1092. 1)))))
  1093. (mkdir-p (dirname result))
  1094. (apply invoke #$compiler "-std=gnu99" "-static" "-Os" "-g0" "-Wall"
  1095. "run.c" "-o" result
  1096. (string-append "-DWRAPPER_PROGRAM=\""
  1097. (canonicalize-path (dirname result)) "/"
  1098. (basename result) "\"")
  1099. (append (if proot
  1100. (list (string-append "-DPROOT_PROGRAM=\""
  1101. proot "\""))
  1102. '())
  1103. (elf-loader-compile-flags program)))
  1104. (delete-file "run.c")))
  1105. (setvbuf (current-output-port) 'line)
  1106. ;; Link the top-level files of PACKAGE so that search paths are
  1107. ;; properly defined in PROFILE/etc/profile.
  1108. (mkdir target)
  1109. (for-each (lambda (file)
  1110. (unless (member file '("." ".." "bin" "sbin" "libexec"))
  1111. (symlink-relative (string-append input "/" file)
  1112. (string-append target "/" file))))
  1113. (scandir input))
  1114. (receive (executables others)
  1115. (partition executable-file?
  1116. ;; Note: Trailing slash in case these are symlinks.
  1117. (append (find-files (string-append input "/bin/"))
  1118. (find-files (string-append input "/sbin/"))
  1119. (find-files (string-append input "/libexec/"))))
  1120. ;; Wrap only executables, since the wrapper will eventually need
  1121. ;; to execve them. E.g. git's "libexec" directory contains many
  1122. ;; shell scripts that are source'd from elsewhere, which fails if
  1123. ;; they are wrapped.
  1124. (for-each build-wrapper executables)
  1125. ;; Link any other non-executable files
  1126. (for-each (lambda (old)
  1127. (let ((new (string-append target (strip-store-prefix old))))
  1128. (mkdir-p (dirname new))
  1129. (symlink-relative old new)))
  1130. others)))))
  1131. (computed-file (string-append
  1132. (cond ((package? package)
  1133. (package-full-name package "-"))
  1134. ((inferior-package? package)
  1135. (string-append (inferior-package-name package)
  1136. "-"
  1137. (inferior-package-version package)))
  1138. (else "wrapper"))
  1139. "R")
  1140. build))
  1141. (define (wrapped-manifest-entry entry . args)
  1142. (manifest-entry
  1143. (inherit entry)
  1144. (item (apply wrapped-package
  1145. (manifest-entry-item entry)
  1146. (manifest-entry-output entry)
  1147. args))
  1148. (dependencies (map (lambda (entry)
  1149. (apply wrapped-manifest-entry entry args))
  1150. (manifest-entry-dependencies entry)))))
  1151. ;;;
  1152. ;;; Command-line options.
  1153. ;;;
  1154. (define %default-options
  1155. ;; Alist of default option values.
  1156. `((format . tarball)
  1157. (profile-name . "guix-profile")
  1158. (system . ,(%current-system))
  1159. (substitutes? . #t)
  1160. (offload? . #t)
  1161. (graft? . #t)
  1162. (print-build-trace? . #t)
  1163. (print-extended-build-trace? . #t)
  1164. (multiplexed-build-output? . #t)
  1165. (debug . 0)
  1166. (verbosity . 1)
  1167. (symlinks . ())
  1168. (compressor . ,(first %compressors))))
  1169. (define %formats
  1170. ;; Supported pack formats.
  1171. `((tarball . ,self-contained-tarball)
  1172. (squashfs . ,squashfs-image)
  1173. (docker . ,docker-image)
  1174. (deb . ,debian-archive)
  1175. (rpm . ,rpm-archive)))
  1176. (define (show-formats)
  1177. ;; Print the supported pack formats.
  1178. (display (G_ "The supported formats for 'guix pack' are:"))
  1179. (newline)
  1180. (display (G_ "
  1181. tarball Self-contained tarball, ready to run on another machine"))
  1182. (display (G_ "
  1183. squashfs Squashfs image suitable for Singularity"))
  1184. (display (G_ "
  1185. docker Tarball ready for 'docker load'"))
  1186. (display (G_ "
  1187. deb Debian archive installable via dpkg/apt"))
  1188. (display (G_ "
  1189. rpm RPM archive installable via rpm/yum"))
  1190. (newline))
  1191. (define (required-option symbol)
  1192. "Return an SYMBOL option that requires a value."
  1193. (option (list (symbol->string symbol)) #t #f
  1194. (lambda (opt name arg result . rest)
  1195. (apply values
  1196. (alist-cons symbol arg result)
  1197. rest))))
  1198. (define %deb-format-options
  1199. (list (required-option 'control-file)
  1200. (required-option 'postinst-file)
  1201. (required-option 'triggers-file)))
  1202. (define (show-deb-format-options)
  1203. (display (G_ "
  1204. --help-deb-format list options specific to the deb format")))
  1205. (define (show-deb-format-options/detailed)
  1206. (display (G_ "
  1207. --control-file=FILE
  1208. Embed the provided control FILE"))
  1209. (display (G_ "
  1210. --postinst-file=FILE
  1211. Embed the provided postinst script"))
  1212. (display (G_ "
  1213. --triggers-file=FILE
  1214. Embed the provided triggers FILE"))
  1215. (newline)
  1216. (exit 0))
  1217. (define %rpm-format-options
  1218. (list (required-option 'prein-file)
  1219. (required-option 'postin-file)
  1220. (required-option 'preun-file)
  1221. (required-option 'postun-file)))
  1222. (define (show-rpm-format-options)
  1223. (display (G_ "
  1224. --help-rpm-format list options specific to the RPM format")))
  1225. (define (show-rpm-format-options/detailed)
  1226. (display (G_ "
  1227. --prein-file=FILE
  1228. Embed the provided prein script"))
  1229. (display (G_ "
  1230. --postin-file=FILE
  1231. Embed the provided postin script"))
  1232. (display (G_ "
  1233. --preun-file=FILE
  1234. Embed the provided preun script"))
  1235. (display (G_ "
  1236. --postun-file=FILE
  1237. Embed the provided postun script"))
  1238. (newline)
  1239. (exit 0))
  1240. (define %options
  1241. ;; Specifications of the command-line options.
  1242. (cons* (option '(#\h "help") #f #f
  1243. (lambda args
  1244. (show-help)
  1245. (exit 0)))
  1246. (option '(#\V "version") #f #f
  1247. (lambda args
  1248. (show-version-and-exit "guix pack")))
  1249. (option '(#\n "dry-run") #f #f
  1250. (lambda (opt name arg result)
  1251. (alist-cons 'dry-run? #t result)))
  1252. (option '(#\d "derivation") #f #f
  1253. (lambda (opt name arg result)
  1254. (alist-cons 'derivation-only? #t result)))
  1255. (option '(#\f "format") #t #f
  1256. (lambda (opt name arg result)
  1257. (alist-cons 'format (string->symbol arg) result)))
  1258. (option '("list-formats") #f #f
  1259. (lambda args
  1260. (show-formats)
  1261. (exit 0)))
  1262. (option '(#\R "relocatable") #f #f
  1263. (lambda (opt name arg result)
  1264. (match (assq-ref result 'relocatable?)
  1265. (#f
  1266. (alist-cons 'relocatable? #t result))
  1267. (_
  1268. (alist-cons 'relocatable? 'proot
  1269. (alist-delete 'relocatable? result))))))
  1270. (option '(#\e "expression") #t #f
  1271. (lambda (opt name arg result)
  1272. (alist-cons 'expression arg result)))
  1273. (option '(#\m "manifest") #t #f
  1274. (lambda (opt name arg result)
  1275. (alist-cons 'manifest arg result)))
  1276. (option '("entry-point") #t #f
  1277. (lambda (opt name arg result)
  1278. (alist-cons 'entry-point arg result)))
  1279. (option '(#\C "compression") #t #f
  1280. (lambda (opt name arg result)
  1281. (alist-cons 'compressor (lookup-compressor arg)
  1282. result)))
  1283. (option '(#\S "symlink") #t #f symlink-spec-option-parser)
  1284. (option '("save-provenance") #f #f
  1285. (lambda (opt name arg result)
  1286. (alist-cons 'save-provenance? #t result)))
  1287. (option '("localstatedir") #f #f
  1288. (lambda (opt name arg result)
  1289. (alist-cons 'localstatedir? #t result)))
  1290. (option '("profile-name") #t #f
  1291. (lambda (opt name arg result)
  1292. (match arg
  1293. ((or "guix-profile" "current-guix")
  1294. (alist-cons 'profile-name arg result))
  1295. (_
  1296. (leave (G_ "~a: unsupported profile name~%") arg)))))
  1297. (option '(#\r "root") #t #f
  1298. (lambda (opt name arg result)
  1299. (alist-cons 'gc-root arg result)))
  1300. (option '(#\v "verbosity") #t #f
  1301. (lambda (opt name arg result)
  1302. (let ((level (string->number* arg)))
  1303. (alist-cons 'verbosity level
  1304. (alist-delete 'verbosity result)))))
  1305. (option '("bootstrap") #f #f
  1306. (lambda (opt name arg result)
  1307. (alist-cons 'bootstrap? #t result)))
  1308. (option '("help-deb-format") #f #f
  1309. (lambda args
  1310. (show-deb-format-options/detailed)))
  1311. (option '("help-rpm-format") #f #f
  1312. (lambda args
  1313. (show-rpm-format-options/detailed)))
  1314. (append %deb-format-options
  1315. %rpm-format-options
  1316. %transformation-options
  1317. %standard-build-options
  1318. %standard-cross-build-options
  1319. %standard-native-build-options)))
  1320. (define (show-help)
  1321. (display (G_ "Usage: guix pack [OPTION]... PACKAGE...
  1322. Create a bundle of PACKAGE.\n"))
  1323. (show-build-options-help)
  1324. (newline)
  1325. (show-cross-build-options-help)
  1326. (newline)
  1327. (show-native-build-options-help)
  1328. (newline)
  1329. (show-transformation-options-help)
  1330. (newline)
  1331. (show-deb-format-options)
  1332. (show-rpm-format-options)
  1333. (newline)
  1334. (display (G_ "
  1335. -f, --format=FORMAT build a pack in the given FORMAT"))
  1336. (display (G_ "
  1337. --list-formats list the formats available"))
  1338. (display (G_ "
  1339. -R, --relocatable produce relocatable executables"))
  1340. (display (G_ "
  1341. -e, --expression=EXPR consider the package EXPR evaluates to"))
  1342. (display (G_ "
  1343. -C, --compression=TOOL compress using TOOL--e.g., \"lzip\""))
  1344. (display (G_ "
  1345. -S, --symlink=SPEC create symlinks to the profile according to SPEC"))
  1346. (display (G_ "
  1347. -m, --manifest=FILE create a pack with the manifest from FILE"))
  1348. (display (G_ "
  1349. --entry-point=PROGRAM
  1350. use PROGRAM as the entry point of the pack"))
  1351. (display (G_ "
  1352. --save-provenance save provenance information"))
  1353. (display (G_ "
  1354. --localstatedir include /var/guix in the resulting pack"))
  1355. (display (G_ "
  1356. --profile-name=NAME
  1357. populate /var/guix/profiles/.../NAME"))
  1358. (display (G_ "
  1359. -r, --root=FILE make FILE a symlink to the result, and register it
  1360. as a garbage collector root"))
  1361. (display (G_ "
  1362. -d, --derivation return the derivation of the pack"))
  1363. (display (G_ "
  1364. -v, --verbosity=LEVEL use the given verbosity LEVEL"))
  1365. (display (G_ "
  1366. --bootstrap use the bootstrap binaries to build the pack"))
  1367. (newline)
  1368. (display (G_ "
  1369. -h, --help display this help and exit"))
  1370. (display (G_ "
  1371. -V, --version display version information and exit"))
  1372. (newline)
  1373. (show-bug-report-information))
  1374. ;;;
  1375. ;;; Entry point.
  1376. ;;;
  1377. (define-command (guix-pack . args)
  1378. (category development)
  1379. (synopsis "create application bundles")
  1380. (with-error-handling
  1381. (define opts
  1382. (parse-command-line args %options (list %default-options)))
  1383. (define maybe-package-argument
  1384. ;; Given an option pair, return a package, a package/output tuple, or #f.
  1385. (match-lambda
  1386. (('argument . spec)
  1387. (call-with-values
  1388. (lambda ()
  1389. (specification->package+output spec))
  1390. list))
  1391. (('expression . exp)
  1392. (read/eval-package-expression exp))
  1393. (x #f)))
  1394. (define (manifest-from-args store opts)
  1395. (let* ((transform (options->transformation opts))
  1396. (packages (map (match-lambda
  1397. (((? package? package) output)
  1398. (list (transform package) output))
  1399. ((? package? package)
  1400. (list (transform package) "out")))
  1401. (reverse
  1402. (filter-map maybe-package-argument opts))))
  1403. (manifests (filter-map (match-lambda
  1404. (('manifest . file) file)
  1405. (_ #f))
  1406. opts)))
  1407. (define with-provenance
  1408. (if (assoc-ref opts 'save-provenance?)
  1409. (lambda (manifest)
  1410. (map-manifest-entries
  1411. (lambda (entry)
  1412. (let ((entry (manifest-entry-with-provenance entry)))
  1413. (unless (assq 'provenance (manifest-entry-properties entry))
  1414. (warning (G_ "could not determine provenance of package ~a~%")
  1415. (manifest-entry-name entry)))
  1416. entry))
  1417. manifest))
  1418. identity))
  1419. (with-provenance
  1420. (cond
  1421. ((and (not (null? manifests)) (not (null? packages)))
  1422. (leave (G_ "both a manifest and a package list were given~%")))
  1423. ((not (null? manifests))
  1424. (concatenate-manifests
  1425. (map (lambda (file)
  1426. (let ((user-module (make-user-module
  1427. '((guix profiles) (gnu)))))
  1428. (load* file user-module)))
  1429. manifests)))
  1430. (else
  1431. (packages->manifest packages))))))
  1432. (define (process-file-arg opts name)
  1433. ;; Validate that the file exists and return it as a <local-file> object,
  1434. ;; else #f.
  1435. (let ((value (assoc-ref opts name)))
  1436. (match value
  1437. ((and (? string?) (not (? file-exists?)))
  1438. (leave (G_ "file provided with option ~a does not exist: ~a~%")
  1439. (string-append "--" (symbol->string name)) value))
  1440. ((? string?)
  1441. (local-file value))
  1442. (#f #f))))
  1443. (with-store store
  1444. (with-status-verbosity (assoc-ref opts 'verbosity)
  1445. ;; Set the build options before we do anything else.
  1446. (set-build-options-from-command-line store opts)
  1447. (with-build-handler (build-notifier #:dry-run?
  1448. (assoc-ref opts 'dry-run?)
  1449. #:verbosity
  1450. (assoc-ref opts 'verbosity)
  1451. #:use-substitutes?
  1452. (assoc-ref opts 'substitutes?))
  1453. (parameterize ((%graft? (assoc-ref opts 'graft?))
  1454. (%guile-for-build (package-derivation
  1455. store
  1456. (if (assoc-ref opts 'bootstrap?)
  1457. %bootstrap-guile
  1458. (default-guile))
  1459. (assoc-ref opts 'system)
  1460. #:graft? (assoc-ref opts 'graft?))))
  1461. (let* ((derivation? (assoc-ref opts 'derivation-only?))
  1462. (relocatable? (assoc-ref opts 'relocatable?))
  1463. (proot? (eq? relocatable? 'proot))
  1464. (manifest (let ((manifest (manifest-from-args store opts)))
  1465. ;; Note: We cannot honor '--bootstrap' here because
  1466. ;; 'glibc-bootstrap' lacks 'libc.a'.
  1467. (if relocatable?
  1468. (map-manifest-entries
  1469. (cut wrapped-manifest-entry <> #:proot? proot?)
  1470. manifest)
  1471. manifest)))
  1472. (pack-format (assoc-ref opts 'format))
  1473. (extra-options (match pack-format
  1474. ('deb
  1475. (list #:control-file
  1476. (process-file-arg opts 'control-file)
  1477. #:postinst-file
  1478. (process-file-arg opts 'postinst-file)
  1479. #:triggers-file
  1480. (process-file-arg opts 'triggers-file)))
  1481. ('rpm
  1482. (list #:relocatable? relocatable?
  1483. #:prein-file
  1484. (process-file-arg opts 'prein-file)
  1485. #:postin-file
  1486. (process-file-arg opts 'postin-file)
  1487. #:preun-file
  1488. (process-file-arg opts 'preun-file)
  1489. #:postun-file
  1490. (process-file-arg opts 'postun-file)))
  1491. (_ '())))
  1492. (target (assoc-ref opts 'target))
  1493. (bootstrap? (assoc-ref opts 'bootstrap?))
  1494. (compressor (if bootstrap?
  1495. bootstrap-xz
  1496. (assoc-ref opts 'compressor)))
  1497. (archiver (if (equal? pack-format 'squashfs)
  1498. squashfs-tools
  1499. (if bootstrap?
  1500. %bootstrap-coreutils&co
  1501. tar)))
  1502. (symlinks (assoc-ref opts 'symlinks))
  1503. (build-image (match (assq-ref %formats pack-format)
  1504. ((? procedure? proc) proc)
  1505. (#f
  1506. (leave (G_ "~a: unknown pack format~%")
  1507. pack-format))))
  1508. (localstatedir? (assoc-ref opts 'localstatedir?))
  1509. (entry-point (assoc-ref opts 'entry-point))
  1510. (profile-name (assoc-ref opts 'profile-name))
  1511. (gc-root (assoc-ref opts 'gc-root))
  1512. (profile (profile
  1513. (content manifest)
  1514. ;; Always produce relative symlinks for
  1515. ;; Singularity (see
  1516. ;; <https://bugs.gnu.org/34913>).
  1517. (relative-symlinks?
  1518. (or relocatable?
  1519. (eq? 'squashfs pack-format)))
  1520. (hooks (if bootstrap?
  1521. '()
  1522. %default-profile-hooks))
  1523. (locales? (not bootstrap?))))
  1524. (name (string-append (manifest->friendly-name manifest)
  1525. "-" (symbol->string pack-format)
  1526. "-pack")))
  1527. (define (lookup-package package)
  1528. (manifest-lookup manifest (manifest-pattern (name package))))
  1529. (when (null? (manifest-entries manifest))
  1530. (warning (G_ "no packages specified; building an empty pack~%")))
  1531. (when (and (eq? pack-format 'squashfs)
  1532. (not (any lookup-package '("bash" "bash-minimal"))))
  1533. (warning (G_ "Singularity requires you to provide a shell~%"))
  1534. (display-hint (G_ "Add @code{bash} or @code{bash-minimal} \
  1535. to your package list.")))
  1536. (run-with-store store
  1537. (mlet* %store-monad ((drv (build-image name profile
  1538. #:target
  1539. target
  1540. #:compressor
  1541. compressor
  1542. #:symlinks
  1543. symlinks
  1544. #:localstatedir?
  1545. localstatedir?
  1546. #:entry-point
  1547. entry-point
  1548. #:profile-name
  1549. profile-name
  1550. #:archiver
  1551. archiver
  1552. #:extra-options
  1553. extra-options)))
  1554. (mbegin %store-monad
  1555. (mwhen derivation?
  1556. (return (format #t "~a~%"
  1557. (derivation-file-name drv))))
  1558. (munless derivation?
  1559. (built-derivations (list drv))
  1560. (mwhen gc-root
  1561. (register-root* (match (derivation->output-paths drv)
  1562. (((names . items) ...)
  1563. items))
  1564. gc-root))
  1565. (return (format #t "~a~%"
  1566. (derivation->output-path drv))))))
  1567. #:target target
  1568. #:system (assoc-ref opts 'system)))))))))