self.scm 52 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254
  1. ;;; GNU Guix --- Functional package management for GNU
  2. ;;; Copyright © 2017, 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org>
  3. ;;;
  4. ;;; This file is part of GNU Guix.
  5. ;;;
  6. ;;; GNU Guix is free software; you can redistribute it and/or modify it
  7. ;;; under the terms of the GNU General Public License as published by
  8. ;;; the Free Software Foundation; either version 3 of the License, or (at
  9. ;;; your option) any later version.
  10. ;;;
  11. ;;; GNU Guix is distributed in the hope that it will be useful, but
  12. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  13. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. ;;; GNU General Public License for more details.
  15. ;;;
  16. ;;; You should have received a copy of the GNU General Public License
  17. ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
  18. (define-module (guix self)
  19. #:use-module (guix config)
  20. #:use-module (guix i18n)
  21. #:use-module (guix modules)
  22. #:use-module (guix gexp)
  23. #:use-module (guix store)
  24. #:use-module (guix monads)
  25. #:use-module (guix discovery)
  26. #:use-module (guix packages)
  27. #:use-module (guix sets)
  28. #:use-module (guix modules)
  29. #:use-module ((guix utils) #:select (version-major+minor))
  30. #:use-module ((guix build utils) #:select (find-files))
  31. #:use-module (srfi srfi-1)
  32. #:use-module (srfi srfi-9)
  33. #:use-module (srfi srfi-35)
  34. #:use-module (ice-9 match)
  35. #:export (make-config.scm
  36. whole-package ;for internal use in 'guix pull'
  37. compiled-guix
  38. guix-derivation))
  39. ;;;
  40. ;;; Dependency handling.
  41. ;;;
  42. (define specification->package
  43. ;; Use our own variant of that procedure because that of (gnu packages)
  44. ;; would traverse all the .scm files, which is wasteful.
  45. (let ((ref (lambda (module variable)
  46. (module-ref (resolve-interface module) variable))))
  47. (match-lambda
  48. ("guile" (ref '(gnu packages guile) 'guile-3.0/libgc-7))
  49. ("guile-json" (ref '(gnu packages guile) 'guile-json-4))
  50. ("guile-ssh" (ref '(gnu packages ssh) 'guile-ssh))
  51. ("guile-git" (ref '(gnu packages guile) 'guile-git))
  52. ("guile-sqlite3" (ref '(gnu packages guile) 'guile-sqlite3))
  53. ("guile-zlib" (ref '(gnu packages guile) 'guile-zlib))
  54. ("guile-lzlib" (ref '(gnu packages guile) 'guile-lzlib))
  55. ("guile-gcrypt" (ref '(gnu packages gnupg) 'guile-gcrypt))
  56. ("gnutls" (ref '(gnu packages tls) 'gnutls))
  57. ("gzip" (ref '(gnu packages compression) 'gzip))
  58. ("bzip2" (ref '(gnu packages compression) 'bzip2))
  59. ("xz" (ref '(gnu packages compression) 'xz))
  60. ("po4a" (ref '(gnu packages gettext) 'po4a))
  61. ("gettext" (ref '(gnu packages gettext) 'gettext-minimal))
  62. ("gcc-toolchain" (ref '(gnu packages commencement) 'gcc-toolchain))
  63. (_ #f)))) ;no such package
  64. ;;;
  65. ;;; Derivations.
  66. ;;;
  67. ;; Node in a DAG of build tasks. Each node maps to a derivation, but it's
  68. ;; easier to express things this way.
  69. (define-record-type <node>
  70. (node name modules source dependencies compiled)
  71. node?
  72. (name node-name) ;string
  73. (modules node-modules) ;list of module names
  74. (source node-source) ;list of source files
  75. (dependencies node-dependencies) ;list of nodes
  76. (compiled node-compiled)) ;node -> lowerable object
  77. ;; File mappings are essentially an alist as passed to 'imported-files'.
  78. (define-record-type <file-mapping>
  79. (file-mapping name alist)
  80. file-mapping?
  81. (name file-mapping-name)
  82. (alist file-mapping-alist))
  83. (define-gexp-compiler (file-mapping-compiler (mapping <file-mapping>)
  84. system target)
  85. ;; Here we use 'imported-files', which can arrange to directly import all
  86. ;; the files instead of creating a derivation, when possible.
  87. (imported-files (map (match-lambda
  88. ((destination (? local-file? file))
  89. (cons destination
  90. (local-file-absolute-file-name file)))
  91. ((destination source)
  92. (cons destination source))) ;silliness
  93. (file-mapping-alist mapping))
  94. #:name (file-mapping-name mapping)
  95. #:system system))
  96. (define (node-source+compiled node)
  97. "Return a \"bundle\" containing both the source code and object files for
  98. NODE's modules, under their FHS directories: share/guile/site and lib/guile."
  99. (define build
  100. (with-imported-modules '((guix build utils))
  101. #~(begin
  102. (use-modules (guix build utils))
  103. (define source
  104. (string-append #$output "/share/guile/site/"
  105. (effective-version)))
  106. (define object
  107. (string-append #$output "/lib/guile/" (effective-version)
  108. "/site-ccache"))
  109. (mkdir-p (dirname source))
  110. (symlink #$(node-source node) source)
  111. (mkdir-p (dirname object))
  112. (symlink #$(node-compiled node) object))))
  113. (computed-file (string-append (node-name node) "-modules")
  114. build
  115. #:options '(#:local-build? #t
  116. ;; "Building" it locally is faster.
  117. #:substitutable? #f)))
  118. (define (node-fold proc init nodes)
  119. (let loop ((nodes nodes)
  120. (visited (setq))
  121. (result init))
  122. (match nodes
  123. (() result)
  124. ((head tail ...)
  125. (if (set-contains? visited head)
  126. (loop tail visited result)
  127. (loop tail (set-insert head visited)
  128. (proc head result)))))))
  129. (define (node-modules/recursive nodes)
  130. (node-fold (lambda (node modules)
  131. (append (node-modules node) modules))
  132. '()
  133. nodes))
  134. (define* (closure modules #:optional (except '()))
  135. (source-module-closure modules
  136. #:select?
  137. (match-lambda
  138. (('guix 'config)
  139. #f)
  140. ((and module
  141. (or ('guix _ ...) ('gnu _ ...)))
  142. (not (member module except)))
  143. (rest #f))))
  144. (define module->import
  145. ;; Return a file-name/file-like object pair for the specified module and
  146. ;; suitable for 'imported-files'.
  147. (match-lambda
  148. ((module '=> thing)
  149. (let ((file (module-name->file-name module)))
  150. (list file thing)))
  151. (module
  152. (let ((file (module-name->file-name module)))
  153. (list file
  154. (local-file (search-path %load-path file)))))))
  155. (define* (scheme-node name modules #:optional (dependencies '())
  156. #:key (extra-modules '()) (extra-files '())
  157. (extensions '())
  158. parallel? guile-for-build)
  159. "Return a node that builds the given Scheme MODULES, and depends on
  160. DEPENDENCIES (a list of nodes). EXTRA-MODULES is a list of additional modules
  161. added to the source, and EXTRA-FILES is a list of additional files.
  162. EXTENSIONS is a set of full-blown Guile packages (e.g., 'guile-json') that
  163. must be present in the search path."
  164. (let* ((modules (append extra-modules
  165. (closure modules
  166. (node-modules/recursive dependencies))))
  167. (module-files (map module->import modules))
  168. (source (file-mapping (string-append name "-source")
  169. (append module-files extra-files))))
  170. (node name modules source dependencies
  171. (compiled-modules name source
  172. (map car module-files)
  173. (map node-source dependencies)
  174. (map node-compiled dependencies)
  175. #:extensions extensions
  176. #:parallel? parallel?
  177. #:guile-for-build guile-for-build))))
  178. (define (file-imports directory sub-directory pred)
  179. "List all the files matching PRED under DIRECTORY/SUB-DIRECTORY. Return a
  180. list of file-name/file-like objects suitable as inputs to 'imported-files'."
  181. (map (lambda (file)
  182. (list (string-drop file (+ 1 (string-length directory)))
  183. (local-file file #:recursive? #t)))
  184. (find-files (string-append directory "/" sub-directory) pred)))
  185. (define* (file-append* item file #:key (recursive? #t))
  186. "Return FILE within ITEM, which may be a file name or a file-like object.
  187. When ITEM is a plain file name (a string), simply return a 'local-file'
  188. record with the new file name."
  189. (match item
  190. ((? string?)
  191. ;; This is the optimal case: we return a new "source". Thus, a
  192. ;; derivation that depends on this sub-directory does not depend on ITEM
  193. ;; itself.
  194. (local-file (string-append item "/" file)
  195. #:recursive? recursive?))
  196. ((? local-file? base)
  197. ;; Likewise, but with a <local-file>.
  198. (if (local-file-recursive? base)
  199. (local-file (string-append (local-file-absolute-file-name base)
  200. "/" file)
  201. (basename file)
  202. #:recursive? recursive?
  203. #:select? (local-file-select? base))
  204. (file-append base file)))
  205. (_
  206. ;; In this case, anything that refers to the result also depends on ITEM,
  207. ;; which isn't great.
  208. (file-append item "/" file))))
  209. (define* (locale-data source domain
  210. #:optional (directory domain))
  211. "Return the locale data from 'po/DIRECTORY' in SOURCE, corresponding to
  212. DOMAIN, a gettext domain."
  213. (define gettext
  214. (module-ref (resolve-interface '(gnu packages gettext))
  215. 'gettext-minimal))
  216. (define build
  217. (with-imported-modules '((guix build utils))
  218. #~(begin
  219. (use-modules (guix build utils)
  220. (srfi srfi-26)
  221. (ice-9 match) (ice-9 ftw))
  222. (define po-directory
  223. #+(file-append* source (string-append "po/" directory)))
  224. (define (compile language)
  225. (let ((gmo (string-append #$output "/" language "/LC_MESSAGES/"
  226. #$domain ".mo")))
  227. (mkdir-p (dirname gmo))
  228. (invoke #+(file-append gettext "/bin/msgfmt")
  229. "-c" "--statistics" "--verbose"
  230. "-o" gmo
  231. (string-append po-directory "/" language ".po"))))
  232. (define (linguas)
  233. ;; Return the list of languages. Note: don't read 'LINGUAS'
  234. ;; because it contains things like 'en@boldquot' that do not have
  235. ;; a corresponding .po file.
  236. (map (cut basename <> ".po")
  237. (scandir po-directory
  238. (cut string-suffix? ".po" <>))))
  239. (for-each compile (linguas)))))
  240. (computed-file (string-append "guix-locale-" domain)
  241. build))
  242. (define (translate-texi-manuals source)
  243. "Return the translated texinfo manuals built from SOURCE."
  244. (define po4a
  245. (specification->package "po4a"))
  246. (define gettext
  247. (specification->package "gettext"))
  248. (define glibc-utf8-locales
  249. (module-ref (resolve-interface '(gnu packages base))
  250. 'glibc-utf8-locales))
  251. (define documentation
  252. (file-append* source "doc"))
  253. (define documentation-po
  254. (file-append* source "po/doc"))
  255. (define build
  256. (with-imported-modules '((guix build utils) (guix build po))
  257. #~(begin
  258. (use-modules (guix build utils) (guix build po)
  259. (ice-9 match) (ice-9 regex) (ice-9 textual-ports)
  260. (ice-9 vlist) (ice-9 threads)
  261. (srfi srfi-1))
  262. (define (translate-tmp-texi po source output)
  263. "Translate Texinfo file SOURCE using messages from PO, and write
  264. the result to OUTPUT."
  265. (invoke #+(file-append po4a "/bin/po4a-translate")
  266. "-M" "UTF-8" "-L" "UTF-8" "-k" "0" "-f" "texinfo"
  267. "-m" source "-p" po "-l" output))
  268. (define (canonicalize-whitespace str)
  269. ;; Change whitespace (newlines, etc.) in STR to #\space.
  270. (string-map (lambda (chr)
  271. (if (char-set-contains? char-set:whitespace chr)
  272. #\space
  273. chr))
  274. str))
  275. (define xref-regexp
  276. ;; Texinfo cross-reference regexp.
  277. (make-regexp "@(px|x)?ref\\{([^,}]+)"))
  278. (define (translate-cross-references texi translations)
  279. ;; Translate the cross-references that appear in TEXI, a Texinfo
  280. ;; file, using the msgid/msgstr pairs from TRANSLATIONS.
  281. (define content
  282. (call-with-input-file texi get-string-all))
  283. (define matches
  284. (list-matches xref-regexp content))
  285. (define translation-map
  286. (fold (match-lambda*
  287. (((msgid . str) result)
  288. (vhash-cons msgid str result)))
  289. vlist-null
  290. translations))
  291. (define translated
  292. ;; Iterate over MATCHES and replace cross-references with their
  293. ;; translation found in TRANSLATION-MAP. (We can't use
  294. ;; 'substitute*' because matches can span multiple lines.)
  295. (let loop ((matches matches)
  296. (offset 0)
  297. (result '()))
  298. (match matches
  299. (()
  300. (string-concatenate-reverse
  301. (cons (string-drop content offset) result)))
  302. ((head . tail)
  303. (let ((prefix (match:substring head 1))
  304. (ref (canonicalize-whitespace (match:substring head 2))))
  305. (define translated
  306. (string-append "@" (or prefix "")
  307. "ref{"
  308. (match (vhash-assoc ref translation-map)
  309. (#f ref)
  310. ((_ . str) str))))
  311. (loop tail
  312. (match:end head)
  313. (append (list translated
  314. (string-take
  315. (string-drop content offset)
  316. (- (match:start head) offset)))
  317. result)))))))
  318. (format (current-error-port)
  319. "translated ~a cross-references in '~a'~%"
  320. (length matches) texi)
  321. (call-with-output-file texi
  322. (lambda (port)
  323. (display translated port))))
  324. (define* (translate-texi prefix po lang
  325. #:key (extras '()))
  326. "Translate the manual for one language LANG using the PO file.
  327. PREFIX must be the prefix of the manual, 'guix' or 'guix-cookbook'. EXTRAS is
  328. a list of extra files, such as '(\"contributing\")."
  329. (let ((translations (call-with-input-file po read-po-file)))
  330. (for-each (lambda (file)
  331. (translate-tmp-texi po (string-append file ".texi")
  332. (string-append file "." lang
  333. ".texi.tmp")))
  334. (cons prefix extras))
  335. (for-each (lambda (file)
  336. (let* ((texi (string-append file "." lang ".texi"))
  337. (tmp (string-append texi ".tmp")))
  338. (copy-file tmp texi)
  339. (translate-cross-references texi
  340. translations)))
  341. (cons prefix extras))))
  342. (define (available-translations directory domain)
  343. ;; Return the list of available translations under DIRECTORY for
  344. ;; DOMAIN, a gettext domain such as "guix-manual". The result is
  345. ;; a list of language/PO file pairs.
  346. (filter-map (lambda (po)
  347. (let ((base (basename po)))
  348. (and (string-prefix? (string-append domain ".")
  349. base)
  350. (match (string-split base #\.)
  351. ((_ ... lang "po")
  352. (cons lang po))))))
  353. (find-files directory
  354. "\\.[a-z]{2}(_[A-Z]{2})?\\.po$")))
  355. (mkdir #$output)
  356. (copy-recursively #$documentation "."
  357. #:log (%make-void-port "w"))
  358. (for-each
  359. (lambda (file)
  360. (copy-file file (basename file)))
  361. (find-files #$documentation-po ".*.po$"))
  362. (setenv "GUIX_LOCPATH"
  363. #+(file-append glibc-utf8-locales "/lib/locale"))
  364. (setenv "PATH" #+(file-append gettext "/bin"))
  365. (setenv "LC_ALL" "en_US.UTF-8")
  366. (setlocale LC_ALL "en_US.UTF-8")
  367. (n-par-for-each (parallel-job-count)
  368. (match-lambda
  369. ((language . po)
  370. (translate-texi "guix" po language
  371. #:extras '("contributing"))))
  372. (available-translations "." "guix-manual"))
  373. (n-par-for-each (parallel-job-count)
  374. (match-lambda
  375. ((language . po)
  376. (translate-texi "guix-cookbook" po language)))
  377. (available-translations "." "guix-cookbook"))
  378. (for-each (lambda (file)
  379. (install-file file #$output))
  380. (append
  381. (find-files "." "contributing\\..*\\.texi$")
  382. (find-files "." "guix\\..*\\.texi$")
  383. (find-files "." "guix-cookbook\\..*\\.texi$"))))))
  384. (computed-file "guix-translated-texinfo" build))
  385. (define (info-manual source)
  386. "Return the Info manual built from SOURCE."
  387. (define texinfo
  388. (module-ref (resolve-interface '(gnu packages texinfo))
  389. 'texinfo))
  390. (define graphviz
  391. (module-ref (resolve-interface '(gnu packages graphviz))
  392. 'graphviz))
  393. (define glibc-utf8-locales
  394. (module-ref (resolve-interface '(gnu packages base))
  395. 'glibc-utf8-locales))
  396. (define documentation
  397. (file-append* source "doc"))
  398. (define examples
  399. (file-append* source "gnu/system/examples"))
  400. (define build
  401. (with-imported-modules '((guix build utils))
  402. #~(begin
  403. (use-modules (guix build utils)
  404. (ice-9 match))
  405. (mkdir #$output)
  406. ;; Create 'version.texi'.
  407. ;; XXX: Can we use a more meaningful version string yet one that
  408. ;; doesn't change at each commit?
  409. (call-with-output-file "version.texi"
  410. (lambda (port)
  411. (let ((version "0.0-git"))
  412. (format port "
  413. @set UPDATED 1 January 1970
  414. @set UPDATED-MONTH January 1970
  415. @set EDITION ~a
  416. @set VERSION ~a\n" version version))))
  417. ;; Copy configuration templates that the manual includes.
  418. (for-each (lambda (template)
  419. (copy-file template
  420. (string-append
  421. "os-config-"
  422. (basename template ".tmpl")
  423. ".texi")))
  424. (find-files #$examples "\\.tmpl$"))
  425. ;; Build graphs.
  426. (mkdir-p (string-append #$output "/images"))
  427. (for-each (lambda (dot-file)
  428. (invoke #+(file-append graphviz "/bin/dot")
  429. "-Tpng" "-Gratio=.9" "-Gnodesep=.005"
  430. "-Granksep=.00005" "-Nfontsize=9"
  431. "-Nheight=.1" "-Nwidth=.1"
  432. "-o" (string-append #$output "/images/"
  433. (basename dot-file ".dot")
  434. ".png")
  435. dot-file))
  436. (find-files (string-append #$documentation "/images")
  437. "\\.dot$"))
  438. ;; Copy other PNGs.
  439. (for-each (lambda (png-file)
  440. (install-file png-file
  441. (string-append #$output "/images")))
  442. (find-files (string-append #$documentation "/images")
  443. "\\.png$"))
  444. ;; Finally build the manual. Copy it the Texinfo files to $PWD and
  445. ;; add a symlink to the 'images' directory so that 'makeinfo' can
  446. ;; see those images and produce image references in the Info output.
  447. (copy-recursively #$documentation "."
  448. #:log (%make-void-port "w"))
  449. (copy-recursively #+(translate-texi-manuals source) "."
  450. #:log (%make-void-port "w"))
  451. (delete-file-recursively "images")
  452. (symlink (string-append #$output "/images") "images")
  453. ;; Provide UTF-8 locales needed by the 'xspara.c' code in makeinfo.
  454. (setenv "GUIX_LOCPATH"
  455. #+(file-append glibc-utf8-locales "/lib/locale"))
  456. (for-each (lambda (texi)
  457. (match (string-split (basename texi) #\.)
  458. (("guix" language "texi")
  459. ;; Create 'version-LL.texi'.
  460. (symlink "version.texi"
  461. (string-append "version-" language
  462. ".texi")))
  463. (_ #f))
  464. (invoke #+(file-append texinfo "/bin/makeinfo")
  465. texi "-I" #$documentation
  466. "-I" "."
  467. "-o" (string-append #$output "/"
  468. (basename texi ".texi")
  469. ".info")))
  470. (cons "guix.texi"
  471. (append (find-files "."
  472. "^guix\\.[a-z]{2}(_[A-Z]{2})?\\.texi$")
  473. (find-files "."
  474. "^guix-cookbook.*\\.texi$"))))
  475. ;; Compress Info files.
  476. (setenv "PATH"
  477. #+(file-append (specification->package "gzip") "/bin"))
  478. (for-each (lambda (file)
  479. (invoke "gzip" "-9n" file))
  480. (find-files #$output "\\.info(-[0-9]+)?$")))))
  481. (computed-file "guix-manual" build))
  482. (define-syntax-rule (prevent-inlining! identifier ...)
  483. (begin (set! identifier identifier) ...))
  484. ;; XXX: These procedures are actually used by 'doc/build.scm'. Protect them
  485. ;; from inlining on Guile 3.
  486. (prevent-inlining! file-append* translate-texi-manuals info-manual)
  487. (define* (guile-module-union things #:key (name "guix-module-union"))
  488. "Return the union of the subset of THINGS (packages, computed files, etc.)
  489. that provide Guile modules."
  490. (define build
  491. (with-imported-modules '((guix build union))
  492. #~(begin
  493. (use-modules (guix build union))
  494. (define (modules directory)
  495. (string-append directory "/share/guile/site"))
  496. (define (objects directory)
  497. (string-append directory "/lib/guile"))
  498. (union-build #$output
  499. (filter (lambda (directory)
  500. (or (file-exists? (modules directory))
  501. (file-exists? (objects directory))))
  502. '#$things)
  503. #:log-port (%make-void-port "w")))))
  504. (computed-file name build))
  505. (define (quiet-guile guile)
  506. "Return a wrapper that does the same as the 'guile' executable of GUILE,
  507. except that it does not complain about locales and falls back to 'en_US.utf8'
  508. instead of 'C'."
  509. (define gcc
  510. (specification->package "gcc-toolchain"))
  511. (define source
  512. (search-path %load-path
  513. "gnu/packages/aux-files/guile-launcher.c"))
  514. (define effective
  515. (version-major+minor (package-version guile)))
  516. (define build
  517. ;; XXX: Reuse <c-compiler> from (guix scripts pack) instead?
  518. (with-imported-modules '((guix build utils))
  519. #~(begin
  520. (use-modules (guix build utils)
  521. (srfi srfi-26))
  522. (mkdir-p (string-append #$output "/bin"))
  523. (setenv "PATH" #$(file-append gcc "/bin"))
  524. (setenv "C_INCLUDE_PATH"
  525. (string-join
  526. (map (cut string-append <> "/include")
  527. '#$(match (bag-transitive-build-inputs
  528. (package->bag guile))
  529. (((labels packages . _) ...)
  530. (filter package? packages))))
  531. ":"))
  532. (setenv "LIBRARY_PATH" #$(file-append gcc "/lib"))
  533. (invoke "gcc" #$(local-file source) "-Wall" "-g0" "-O2"
  534. "-I" #$(file-append guile "/include/guile/" effective)
  535. "-L" #$(file-append guile "/lib")
  536. #$(string-append "-lguile-" effective)
  537. "-o" (string-append #$output "/bin/guile")))))
  538. (computed-file "guile-wrapper" build))
  539. (define* (guix-command modules
  540. #:key source (dependencies '())
  541. guile (guile-version (effective-version)))
  542. "Return the 'guix' command such that it adds MODULES and DEPENDENCIES in its
  543. load path."
  544. (define glibc-utf8-locales
  545. (module-ref (resolve-interface '(gnu packages base))
  546. 'glibc-utf8-locales))
  547. (define module-directory
  548. ;; To minimize the number of 'stat' calls needed to locate a module,
  549. ;; create the union of all the module directories.
  550. (guile-module-union (cons modules dependencies)))
  551. (program-file "guix-command"
  552. #~(begin
  553. (set! %load-path
  554. (cons (string-append #$module-directory
  555. "/share/guile/site/"
  556. (effective-version))
  557. %load-path))
  558. (set! %load-compiled-path
  559. (cons (string-append #$module-directory
  560. "/lib/guile/"
  561. (effective-version)
  562. "/site-ccache")
  563. %load-compiled-path))
  564. ;; To maximize the chances that locales are set up right
  565. ;; out-of-the-box, bundle "common" UTF-8 locales.
  566. (let ((locpath (getenv "GUIX_LOCPATH")))
  567. (setenv "GUIX_LOCPATH"
  568. (string-append (if locpath
  569. (string-append locpath ":")
  570. "")
  571. #$(file-append glibc-utf8-locales
  572. "/lib/locale"))))
  573. (let ((guix-main (module-ref (resolve-interface '(guix ui))
  574. 'guix-main)))
  575. #$(if source
  576. #~(begin
  577. (bindtextdomain "guix"
  578. #$(locale-data source "guix"))
  579. (bindtextdomain "guix-packages"
  580. #$(locale-data source
  581. "guix-packages"
  582. "packages")))
  583. #t)
  584. ;; XXX: It would be more convenient to change it to:
  585. ;; (exit (apply guix-main (command-line)))
  586. (apply guix-main (command-line))))
  587. ;; Use a 'guile' variant that doesn't complain about locales.
  588. #:guile (quiet-guile guile)))
  589. (define (miscellaneous-files source)
  590. "Return data files taken from SOURCE."
  591. (file-mapping "guix-misc"
  592. `(("etc/bash_completion.d/guix"
  593. ,(file-append* source "/etc/completion/bash/guix"))
  594. ("etc/bash_completion.d/guix-daemon"
  595. ,(file-append* source "/etc/completion/bash/guix-daemon"))
  596. ("share/zsh/site-functions/_guix"
  597. ,(file-append* source "/etc/completion/zsh/_guix"))
  598. ("share/fish/vendor_completions.d/guix.fish"
  599. ,(file-append* source "/etc/completion/fish/guix.fish"))
  600. ("share/guix/berlin.guix.gnu.org.pub"
  601. ,(file-append* source
  602. "/etc/substitutes/berlin.guix.gnu.org.pub"))
  603. ("share/guix/ci.guix.gnu.org.pub" ;alias
  604. ,(file-append* source "/etc/substitutes/berlin.guix.gnu.org.pub"))
  605. ("share/guix/ci.guix.info.pub" ;alias
  606. ,(file-append* source "/etc/substitutes/berlin.guix.gnu.org.pub")))))
  607. (define* (whole-package name modules dependencies
  608. #:key
  609. (guile-version (effective-version))
  610. info daemon miscellany
  611. guile
  612. (command (guix-command modules
  613. #:dependencies dependencies
  614. #:guile guile
  615. #:guile-version guile-version)))
  616. "Return the whole Guix package NAME that uses MODULES, a derivation of all
  617. the modules (under share/guile/site and lib/guile), and DEPENDENCIES, a list
  618. of packages depended on. COMMAND is the 'guix' program to use; INFO is the
  619. Info manual."
  620. (define (wrap daemon)
  621. (program-file "guix-daemon"
  622. #~(begin
  623. ;; Refer to the right 'guix' command for 'guix
  624. ;; substitute' & co.
  625. (setenv "GUIX" #$command)
  626. ;; Honor the user's settings rather than those hardcoded
  627. ;; in the 'guix-daemon' package.
  628. (unless (getenv "GUIX_STATE_DIRECTORY")
  629. (setenv "GUIX_STATE_DIRECTORY"
  630. #$(string-append %localstatedir "/guix")))
  631. (unless (getenv "GUIX_CONFIGURATION_DIRECTORY")
  632. (setenv "GUIX_CONFIGURATION_DIRECTORY"
  633. #$(string-append %sysconfdir "/guix")))
  634. (unless (getenv "NIX_STORE_DIR")
  635. (setenv "NIX_STORE_DIR" #$%storedir))
  636. (apply execl #$(file-append daemon "/bin/guix-daemon")
  637. "guix-daemon" (cdr (command-line))))))
  638. (computed-file name
  639. (with-imported-modules '((guix build utils))
  640. #~(begin
  641. (use-modules (guix build utils))
  642. (define daemon
  643. #$(and daemon (wrap daemon)))
  644. (mkdir-p (string-append #$output "/bin"))
  645. (symlink #$command
  646. (string-append #$output "/bin/guix"))
  647. (when daemon
  648. (symlink daemon
  649. (string-append #$output "/bin/guix-daemon")))
  650. (let ((share (string-append #$output "/share"))
  651. (lib (string-append #$output "/lib"))
  652. (info #$info))
  653. (mkdir-p share)
  654. (symlink #$(file-append modules "/share/guile")
  655. (string-append share "/guile"))
  656. (when info
  657. (symlink #$info (string-append share "/info")))
  658. (mkdir-p lib)
  659. (symlink #$(file-append modules "/lib/guile")
  660. (string-append lib "/guile")))
  661. (when #$miscellany
  662. (copy-recursively #$miscellany #$output
  663. #:log (%make-void-port "w")))))))
  664. (define* (compiled-guix source #:key (version %guix-version)
  665. (pull-version 1)
  666. (name (string-append "guix-" version))
  667. (guile-version (effective-version))
  668. (guile-for-build (default-guile))
  669. (gzip (specification->package "gzip"))
  670. (bzip2 (specification->package "bzip2"))
  671. (xz (specification->package "xz"))
  672. (guix (specification->package "guix")))
  673. "Return a file-like object that contains a compiled Guix."
  674. (define guile-json
  675. (specification->package "guile-json"))
  676. (define guile-ssh
  677. (specification->package "guile-ssh"))
  678. (define guile-git
  679. (specification->package "guile-git"))
  680. (define guile-sqlite3
  681. (specification->package "guile-sqlite3"))
  682. (define guile-zlib
  683. (specification->package "guile-zlib"))
  684. (define guile-lzlib
  685. (specification->package "guile-lzlib"))
  686. (define guile-gcrypt
  687. (specification->package "guile-gcrypt"))
  688. (define gnutls
  689. (specification->package "gnutls"))
  690. (define dependencies
  691. (match (append-map (lambda (package)
  692. (cons (list "x" package)
  693. (package-transitive-propagated-inputs package)))
  694. (list guile-gcrypt gnutls guile-git guile-json
  695. guile-ssh guile-sqlite3 guile-zlib guile-lzlib))
  696. (((labels packages _ ...) ...)
  697. packages)))
  698. (define *core-modules*
  699. (scheme-node "guix-core"
  700. '((guix)
  701. (guix monad-repl)
  702. (guix packages)
  703. (guix download)
  704. (guix discovery)
  705. (guix profiles)
  706. (guix build-system gnu)
  707. (guix build-system trivial)
  708. (guix build profiles)
  709. (guix build gnu-build-system))
  710. ;; Provide a dummy (guix config) with the default version
  711. ;; number, storedir, etc. This is so that "guix-core" is the
  712. ;; same across all installations and doesn't need to be
  713. ;; rebuilt when the version changes, which in turn means we
  714. ;; can have substitutes for it.
  715. #:extra-modules
  716. `(((guix config) => ,(make-config.scm)))
  717. ;; (guix man-db) is needed at build-time by (guix profiles)
  718. ;; but we don't need to compile it; not compiling it allows
  719. ;; us to avoid an extra dependency on guile-gdbm-ffi.
  720. #:extra-files
  721. `(("guix/man-db.scm" ,(local-file "../guix/man-db.scm"))
  722. ("guix/build/po.scm" ,(local-file "../guix/build/po.scm"))
  723. ("guix/store/schema.sql"
  724. ,(local-file "../guix/store/schema.sql")))
  725. #:extensions (list guile-gcrypt)
  726. #:guile-for-build guile-for-build))
  727. (define *extra-modules*
  728. (scheme-node "guix-extra"
  729. (filter-map (match-lambda
  730. (('guix 'scripts _ ..1) #f)
  731. (('guix 'man-db) #f)
  732. (('guix 'tests _ ...) #f)
  733. (name name))
  734. (scheme-modules* source "guix"))
  735. (list *core-modules*)
  736. #:extensions dependencies
  737. #:guile-for-build guile-for-build))
  738. (define *core-package-modules*
  739. (scheme-node "guix-packages-base"
  740. `((gnu packages)
  741. (gnu packages base))
  742. (list *core-modules* *extra-modules*)
  743. #:extensions dependencies
  744. ;; Add all the non-Scheme files here. We must do it here so
  745. ;; that 'search-patches' & co. can find them. Ideally we'd
  746. ;; keep them next to the .scm files that use them but it's
  747. ;; difficult to do (XXX).
  748. #:extra-files
  749. (file-imports source "gnu/packages"
  750. (lambda (file stat)
  751. (and (eq? 'regular (stat:type stat))
  752. (not (string-suffix? ".scm" file))
  753. (not (string-suffix? ".go" file))
  754. (not (string-prefix? ".#" file))
  755. (not (string-suffix? "~" file)))))
  756. #:guile-for-build guile-for-build))
  757. (define *package-modules*
  758. (scheme-node "guix-packages"
  759. (scheme-modules* source "gnu/packages")
  760. (list *core-modules* *extra-modules* *core-package-modules*)
  761. #:extensions dependencies
  762. #:guile-for-build guile-for-build))
  763. (define *system-modules*
  764. (scheme-node "guix-system"
  765. `((gnu system)
  766. (gnu services)
  767. ,@(scheme-modules* source "gnu/bootloader")
  768. ,@(scheme-modules* source "gnu/system")
  769. ,@(scheme-modules* source "gnu/services")
  770. ,@(scheme-modules* source "gnu/machine"))
  771. (list *core-package-modules* *package-modules*
  772. *extra-modules* *core-modules*)
  773. #:extensions dependencies
  774. #:extra-files
  775. (append (file-imports source "gnu/system/examples"
  776. (const #t))
  777. ;; All the installer code is on the build-side.
  778. (file-imports source "gnu/installer/"
  779. (const #t))
  780. ;; Build-side code that we don't build. Some of
  781. ;; these depend on guile-rsvg, the Shepherd, etc.
  782. (file-imports source "gnu/build" (const #t)))
  783. #:guile-for-build
  784. guile-for-build))
  785. (define *cli-modules*
  786. (scheme-node "guix-cli"
  787. (append (scheme-modules* source "/guix/scripts")
  788. `((gnu ci)))
  789. (list *core-modules* *extra-modules*
  790. *core-package-modules* *package-modules*
  791. *system-modules*)
  792. #:extensions dependencies
  793. #:guile-for-build guile-for-build))
  794. (define *system-test-modules*
  795. ;; Ship these modules mostly so (gnu ci) can discover them.
  796. (scheme-node "guix-system-tests"
  797. `((gnu tests)
  798. ,@(scheme-modules* source "gnu/tests"))
  799. (list *core-package-modules* *package-modules*
  800. *extra-modules* *system-modules* *core-modules*
  801. *cli-modules*) ;for (guix scripts pack), etc.
  802. #:extensions dependencies
  803. #:guile-for-build guile-for-build))
  804. (define *config*
  805. (scheme-node "guix-config"
  806. '()
  807. #:extra-modules
  808. `(((guix config)
  809. => ,(make-config.scm #:gzip gzip
  810. #:bzip2 bzip2
  811. #:xz xz
  812. #:package-name
  813. %guix-package-name
  814. #:package-version
  815. version
  816. #:bug-report-address
  817. %guix-bug-report-address
  818. #:home-page-url
  819. %guix-home-page-url)))
  820. #:guile-for-build guile-for-build))
  821. (define (built-modules node-subset)
  822. (directory-union (string-append name "-modules")
  823. (append-map node-subset
  824. ;; Note: *CONFIG* comes first so that it
  825. ;; overrides the (guix config) module that
  826. ;; comes with *CORE-MODULES*.
  827. (list *config*
  828. *cli-modules*
  829. *system-test-modules*
  830. *system-modules*
  831. *package-modules*
  832. *core-package-modules*
  833. *extra-modules*
  834. *core-modules*))
  835. ;; Silently choose the first entry upon collision so that
  836. ;; we choose *CONFIG*.
  837. #:resolve-collision 'first
  838. ;; When we do (add-to-store "utils.scm"), "utils.scm" must
  839. ;; be a regular file, not a symlink. Thus, arrange so that
  840. ;; regular files appear as regular files in the final
  841. ;; output.
  842. #:copy? #t
  843. #:quiet? #t))
  844. ;; Version 0 of 'guix pull' meant we'd just return Scheme modules.
  845. ;; Version 1 is when we return the full package.
  846. (cond ((= 1 pull-version)
  847. ;; The whole package, with a standard file hierarchy.
  848. (let* ((modules (built-modules (compose list node-source+compiled)))
  849. (command (guix-command modules
  850. #:source source
  851. #:dependencies dependencies
  852. #:guile guile-for-build
  853. #:guile-version guile-version)))
  854. (whole-package name modules dependencies
  855. #:command command
  856. #:guile guile-for-build
  857. ;; Include 'guix-daemon'. XXX: Here we inject an
  858. ;; older snapshot of guix-daemon, but that's a good
  859. ;; enough approximation for now.
  860. #:daemon (module-ref (resolve-interface
  861. '(gnu packages
  862. package-management))
  863. 'guix-daemon)
  864. #:info (info-manual source)
  865. #:miscellany (miscellaneous-files source)
  866. #:guile-version guile-version)))
  867. ((= 0 pull-version)
  868. ;; Legacy 'guix pull': return the .scm and .go files as one
  869. ;; directory.
  870. (built-modules (lambda (node)
  871. (list (node-source node)
  872. (node-compiled node)))))
  873. (else
  874. ;; Unsupported 'guix pull' version.
  875. #f)))
  876. ;;;
  877. ;;; Generating (guix config).
  878. ;;;
  879. (define %persona-variables
  880. ;; (guix config) variables that define Guix's persona.
  881. '(%guix-package-name
  882. %guix-version
  883. %guix-bug-report-address
  884. %guix-home-page-url))
  885. (define %config-variables
  886. ;; (guix config) variables corresponding to Guix configuration.
  887. (letrec-syntax ((variables (syntax-rules ()
  888. ((_)
  889. '())
  890. ((_ variable rest ...)
  891. (cons `(variable . ,variable)
  892. (variables rest ...))))))
  893. (variables %localstatedir %storedir %sysconfdir)))
  894. (define* (make-config.scm #:key gzip xz bzip2
  895. (package-name "GNU Guix")
  896. (package-version "0")
  897. (bug-report-address "bug-guix@gnu.org")
  898. (home-page-url "https://guix.gnu.org"))
  899. ;; Hack so that Geiser is not confused.
  900. (define defmod 'define-module)
  901. (scheme-file "config.scm"
  902. #~(;; The following expressions get spliced.
  903. (#$defmod (guix config)
  904. #:export (%guix-package-name
  905. %guix-version
  906. %guix-bug-report-address
  907. %guix-home-page-url
  908. %system
  909. %store-directory
  910. %state-directory
  911. %store-database-directory
  912. %config-directory
  913. %gzip
  914. %bzip2
  915. %xz))
  916. (define %system
  917. #$(%current-system))
  918. #$@(map (match-lambda
  919. ((name . value)
  920. #~(define-public #$name #$value)))
  921. %config-variables)
  922. (define %store-directory
  923. (or (and=> (getenv "NIX_STORE_DIR") canonicalize-path)
  924. %storedir))
  925. (define %state-directory
  926. ;; This must match `NIX_STATE_DIR' as defined in
  927. ;; `nix/local.mk'.
  928. (or (getenv "GUIX_STATE_DIRECTORY")
  929. (string-append %localstatedir "/guix")))
  930. (define %store-database-directory
  931. (or (getenv "GUIX_DATABASE_DIRECTORY")
  932. (string-append %state-directory "/db")))
  933. (define %config-directory
  934. ;; This must match `GUIX_CONFIGURATION_DIRECTORY' as
  935. ;; defined in `nix/local.mk'.
  936. (or (getenv "GUIX_CONFIGURATION_DIRECTORY")
  937. (string-append %sysconfdir "/guix")))
  938. (define %guix-package-name #$package-name)
  939. (define %guix-version #$package-version)
  940. (define %guix-bug-report-address #$bug-report-address)
  941. (define %guix-home-page-url #$home-page-url)
  942. (define %gzip
  943. #+(and gzip (file-append gzip "/bin/gzip")))
  944. (define %bzip2
  945. #+(and bzip2 (file-append bzip2 "/bin/bzip2")))
  946. (define %xz
  947. #+(and xz (file-append xz "/bin/xz"))))
  948. ;; Guile 2.0 *requires* the 'define-module' to be at the
  949. ;; top-level or the 'toplevel-ref' in the resulting .go file are
  950. ;; made relative to a nonexistent anonymous module.
  951. #:splice? #t))
  952. ;;;
  953. ;;; Building.
  954. ;;;
  955. (define* (compiled-modules name module-tree module-files
  956. #:optional
  957. (dependencies '())
  958. (dependencies-compiled '())
  959. #:key
  960. (extensions '()) ;full-blown Guile packages
  961. parallel?
  962. guile-for-build)
  963. "Build all the MODULE-FILES from MODULE-TREE. MODULE-FILES must be a list
  964. like '(\"guix/foo.scm\" \"gnu/bar.scm\") and MODULE-TREE is the directory
  965. containing MODULE-FILES and possibly other files as well."
  966. ;; This is a non-monadic, enhanced version of 'compiled-file' from (guix
  967. ;; gexp).
  968. (define build
  969. (with-imported-modules (source-module-closure
  970. '((guix build compile)
  971. (guix build utils)))
  972. #~(begin
  973. (use-modules (srfi srfi-26)
  974. (ice-9 match)
  975. (ice-9 format)
  976. (ice-9 threads)
  977. (guix build compile)
  978. (guix build utils))
  979. (define (regular? file)
  980. (not (member file '("." ".."))))
  981. (define (report-load file total completed)
  982. (display #\cr)
  983. (format #t
  984. "[~3@a/~3@a] loading...\t~5,1f% of ~d files"
  985. ;; Note: Multiply TOTAL by two to account for the
  986. ;; compilation phase that follows.
  987. completed (* total 2)
  988. (* 100. (/ completed total)) total)
  989. (force-output))
  990. (define (report-compilation file total completed)
  991. (display #\cr)
  992. (format #t "[~3@a/~3@a] compiling...\t~5,1f% of ~d files"
  993. ;; Add TOTAL to account for the load phase that came
  994. ;; before.
  995. (+ total completed) (* total 2)
  996. (* 100. (/ completed total)) total)
  997. (force-output))
  998. (define (process-directory directory files output)
  999. ;; Hide compilation warnings.
  1000. (parameterize ((current-warning-port (%make-void-port "w")))
  1001. (compile-files directory #$output files
  1002. #:workers (parallel-job-count)
  1003. #:report-load report-load
  1004. #:report-compilation report-compilation)))
  1005. (setvbuf (current-output-port) 'line)
  1006. (setvbuf (current-error-port) 'line)
  1007. (set! %load-path (cons #+module-tree %load-path))
  1008. (set! %load-path
  1009. (append '#+dependencies
  1010. (map (lambda (extension)
  1011. (string-append extension "/share/guile/site/"
  1012. (effective-version)))
  1013. '#+extensions)
  1014. %load-path))
  1015. (set! %load-compiled-path
  1016. (append '#+dependencies-compiled
  1017. (map (lambda (extension)
  1018. (string-append extension "/lib/guile/"
  1019. (effective-version)
  1020. "/site-ccache"))
  1021. '#+extensions)
  1022. %load-compiled-path))
  1023. ;; Load the compiler modules upfront.
  1024. (compile #f)
  1025. (mkdir #$output)
  1026. (chdir #+module-tree)
  1027. (process-directory "." '#+module-files #$output)
  1028. (newline))))
  1029. (computed-file name build
  1030. #:guile guile-for-build
  1031. #:options
  1032. `(#:local-build? #f ;allow substitutes
  1033. ;; Don't annoy people about _IONBF deprecation.
  1034. ;; Initialize 'terminal-width' in (system repl debug)
  1035. ;; to a large-enough value to make backtrace more
  1036. ;; verbose.
  1037. #:env-vars (("GUILE_WARN_DEPRECATED" . "no")
  1038. ("COLUMNS" . "200")))))
  1039. ;;;
  1040. ;;; Building.
  1041. ;;;
  1042. (define* (guix-derivation source version
  1043. #:optional (guile-version (effective-version))
  1044. #:key (pull-version 0))
  1045. "Return, as a monadic value, the derivation to build the Guix from SOURCE
  1046. for GUILE-VERSION. Use VERSION as the version string. PULL-VERSION specifies
  1047. the version of the 'guix pull' protocol. Return #f if this PULL-VERSION value
  1048. is not supported."
  1049. (define (shorten version)
  1050. (if (and (string-every char-set:hex-digit version)
  1051. (> (string-length version) 9))
  1052. (string-take version 9) ;Git commit
  1053. version))
  1054. (define guile
  1055. ;; When PULL-VERSION >= 1, produce a self-contained Guix and use the
  1056. ;; current Guile unconditionally.
  1057. (specification->package "guile"))
  1058. (when (and (< pull-version 1)
  1059. (not (string=? (package-version guile) guile-version)))
  1060. ;; Guix < 0.15.0 has PULL-VERSION = 0, where the host Guile is reused and
  1061. ;; can be any version. When that happens and Guile is not current (e.g.,
  1062. ;; it's Guile 2.0), just bail out.
  1063. (raise (condition
  1064. (&message
  1065. (message "Guix is too old and cannot be upgraded")))))
  1066. (mbegin %store-monad
  1067. (set-guile-for-build guile)
  1068. (let ((guix (compiled-guix source
  1069. #:version version
  1070. #:name (string-append "guix-"
  1071. (shorten version))
  1072. #:pull-version pull-version
  1073. #:guile-version (if (>= pull-version 1)
  1074. "3.0" guile-version)
  1075. #:guile-for-build guile)))
  1076. (if guix
  1077. (lower-object guix)
  1078. (return #f)))))