gexp.scm 81 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979
  1. ;;; GNU Guix --- Functional package management for GNU
  2. ;;; Copyright © 2014, 2015, 2016, 2017, 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org>
  3. ;;; Copyright © 2018 Clément Lassieur <clement@lassieur.org>
  4. ;;; Copyright © 2018 Jan Nieuwenhuizen <janneke@gnu.org>
  5. ;;; Copyright © 2019, 2020 Mathieu Othacehe <m.othacehe@gmail.com>
  6. ;;; Copyright © 2020 Maxim Cournoyer <maxim.cournoyer@gmail.com>
  7. ;;;
  8. ;;; This file is part of GNU Guix.
  9. ;;;
  10. ;;; GNU Guix is free software; you can redistribute it and/or modify it
  11. ;;; under the terms of the GNU General Public License as published by
  12. ;;; the Free Software Foundation; either version 3 of the License, or (at
  13. ;;; your option) any later version.
  14. ;;;
  15. ;;; GNU Guix is distributed in the hope that it will be useful, but
  16. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  17. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. ;;; GNU General Public License for more details.
  19. ;;;
  20. ;;; You should have received a copy of the GNU General Public License
  21. ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
  22. (define-module (guix gexp)
  23. #:use-module (guix store)
  24. #:use-module (guix monads)
  25. #:use-module (guix derivations)
  26. #:use-module (guix grafts)
  27. #:use-module (guix utils)
  28. #:use-module (guix diagnostics)
  29. #:use-module (guix i18n)
  30. #:use-module (rnrs bytevectors)
  31. #:use-module (srfi srfi-1)
  32. #:use-module (srfi srfi-9)
  33. #:use-module (srfi srfi-9 gnu)
  34. #:use-module (srfi srfi-26)
  35. #:use-module (srfi srfi-34)
  36. #:use-module (srfi srfi-35)
  37. #:use-module (ice-9 match)
  38. #:export (gexp
  39. gexp?
  40. with-imported-modules
  41. with-extensions
  42. let-system
  43. gexp-input
  44. gexp-input?
  45. gexp-input-thing
  46. gexp-input-output
  47. gexp-input-native?
  48. local-file
  49. local-file?
  50. local-file-file
  51. local-file-absolute-file-name
  52. local-file-name
  53. local-file-recursive?
  54. local-file-select?
  55. plain-file
  56. plain-file?
  57. plain-file-name
  58. plain-file-content
  59. computed-file
  60. computed-file?
  61. computed-file-name
  62. computed-file-gexp
  63. computed-file-options
  64. program-file
  65. program-file?
  66. program-file-name
  67. program-file-gexp
  68. program-file-guile
  69. program-file-module-path
  70. scheme-file
  71. scheme-file?
  72. scheme-file-name
  73. scheme-file-gexp
  74. file-append
  75. file-append?
  76. file-append-base
  77. file-append-suffix
  78. raw-derivation-file
  79. raw-derivation-file?
  80. with-parameters
  81. parameterized?
  82. load-path-expression
  83. gexp-modules
  84. lower-gexp
  85. lowered-gexp?
  86. lowered-gexp-sexp
  87. lowered-gexp-inputs
  88. lowered-gexp-sources
  89. lowered-gexp-guile
  90. lowered-gexp-load-path
  91. lowered-gexp-load-compiled-path
  92. gexp->derivation
  93. gexp->file
  94. gexp->script
  95. text-file*
  96. mixed-text-file
  97. file-union
  98. directory-union
  99. imported-files
  100. imported-modules
  101. compiled-modules
  102. define-gexp-compiler
  103. gexp-compiler?
  104. file-like?
  105. lower-object
  106. lower-inputs
  107. &gexp-error
  108. gexp-error?
  109. &gexp-input-error
  110. gexp-input-error?
  111. gexp-error-invalid-input))
  112. ;;; Commentary:
  113. ;;;
  114. ;;; This module implements "G-expressions", or "gexps". Gexps are like
  115. ;;; S-expressions (sexps), with two differences:
  116. ;;;
  117. ;;; 1. References (un-quotations) to derivations or packages in a gexp are
  118. ;;; replaced by the corresponding output file name; in addition, the
  119. ;;; 'ungexp-native' unquote-like form allows code to explicitly refer to
  120. ;;; the native code of a given package, in case of cross-compilation;
  121. ;;;
  122. ;;; 2. Gexps embed information about the derivations they refer to.
  123. ;;;
  124. ;;; Gexps make it easy to write to files Scheme code that refers to store
  125. ;;; items, or to write Scheme code to build derivations.
  126. ;;;
  127. ;;; Code:
  128. ;; "G expressions".
  129. (define-record-type <gexp>
  130. (make-gexp references modules extensions proc)
  131. gexp?
  132. (references gexp-references) ;list of <gexp-input>
  133. (modules gexp-self-modules) ;list of module names
  134. (extensions gexp-self-extensions) ;list of lowerable things
  135. (proc gexp-proc)) ;procedure
  136. (define (write-gexp gexp port)
  137. "Write GEXP on PORT."
  138. (display "#<gexp " port)
  139. ;; Try to write the underlying sexp. Now, this trick doesn't work when
  140. ;; doing things like (ungexp-splicing (gexp ())) because GEXP's procedure
  141. ;; tries to use 'append' on that, which fails with wrong-type-arg.
  142. (false-if-exception
  143. (write (apply (gexp-proc gexp)
  144. (gexp-references gexp))
  145. port))
  146. (format port " ~a>"
  147. (number->string (object-address gexp) 16)))
  148. (set-record-type-printer! <gexp> write-gexp)
  149. ;;;
  150. ;;; Methods.
  151. ;;;
  152. ;; Compiler for a type of objects that may be introduced in a gexp.
  153. (define-record-type <gexp-compiler>
  154. (gexp-compiler type lower expand)
  155. gexp-compiler?
  156. (type gexp-compiler-type) ;record type descriptor
  157. (lower gexp-compiler-lower)
  158. (expand gexp-compiler-expand)) ;#f | DRV -> sexp
  159. (define-condition-type &gexp-error &error
  160. gexp-error?)
  161. (define-condition-type &gexp-input-error &gexp-error
  162. gexp-input-error?
  163. (input gexp-error-invalid-input))
  164. (define %gexp-compilers
  165. ;; 'eq?' mapping of record type descriptor to <gexp-compiler>.
  166. (make-hash-table 20))
  167. (define (default-expander thing obj output)
  168. "This is the default expander for \"things\" that appear in gexps. It
  169. returns its output file name of OBJ's OUTPUT."
  170. (match obj
  171. ((? derivation? drv)
  172. (derivation->output-path drv output))
  173. ((? string? file)
  174. file)
  175. ((? self-quoting? obj)
  176. obj)))
  177. (define (register-compiler! compiler)
  178. "Register COMPILER as a gexp compiler."
  179. (hashq-set! %gexp-compilers
  180. (gexp-compiler-type compiler) compiler))
  181. (define (lookup-compiler object)
  182. "Search for a compiler for OBJECT. Upon success, return the three argument
  183. procedure to lower it; otherwise return #f."
  184. (and=> (hashq-ref %gexp-compilers (struct-vtable object))
  185. gexp-compiler-lower))
  186. (define (file-like? object)
  187. "Return #t if OBJECT leads to a file in the store once unquoted in a
  188. G-expression; otherwise return #f."
  189. (and (struct? object) (->bool (lookup-compiler object))))
  190. (define (lookup-expander object)
  191. "Search for an expander for OBJECT. Upon success, return the three argument
  192. procedure to expand it; otherwise return #f."
  193. (and=> (hashq-ref %gexp-compilers (struct-vtable object))
  194. gexp-compiler-expand))
  195. (define* (lower-object obj
  196. #:optional (system (%current-system))
  197. #:key (target 'current))
  198. "Return as a value in %STORE-MONAD the derivation or store item
  199. corresponding to OBJ for SYSTEM, cross-compiling for TARGET if TARGET is true.
  200. OBJ must be an object that has an associated gexp compiler, such as a
  201. <package>."
  202. (mlet %store-monad ((target (if (eq? target 'current)
  203. (current-target-system)
  204. (return target)))
  205. (graft? (grafting?)))
  206. (let loop ((obj obj))
  207. (match (lookup-compiler obj)
  208. (#f
  209. (raise (condition (&gexp-input-error (input obj)))))
  210. (lower
  211. ;; Cache in STORE the result of lowering OBJ.
  212. (mcached (mlet %store-monad ((lowered (lower obj system target)))
  213. (if (and (struct? lowered)
  214. (not (derivation? lowered)))
  215. (loop lowered)
  216. (return lowered)))
  217. obj
  218. system target graft?))))))
  219. (define* (lower+expand-object obj
  220. #:optional (system (%current-system))
  221. #:key target (output "out"))
  222. "Return as a value in %STORE-MONAD the output of object OBJ expands to for
  223. SYSTEM and TARGET. Object such as <package>, <file-append>, or <plain-file>
  224. expand to file names, but it's possible to expand to a plain data type."
  225. (let loop ((obj obj)
  226. (expand (and (struct? obj) (lookup-expander obj))))
  227. (match (lookup-compiler obj)
  228. (#f
  229. (raise (condition (&gexp-input-error (input obj)))))
  230. (lower
  231. (mlet* %store-monad ((graft? (grafting?))
  232. (lowered (mcached (lower obj system target)
  233. obj
  234. system target graft?)))
  235. ;; LOWER might return something that needs to be further
  236. ;; lowered.
  237. (if (struct? lowered)
  238. ;; If we lack an expander, delegate to that of LOWERED.
  239. (if (not expand)
  240. (loop lowered (lookup-expander lowered))
  241. (return (expand obj lowered output)))
  242. (if (not expand) ;self-quoting
  243. (return lowered)
  244. (return (expand obj lowered output)))))))))
  245. (define-syntax define-gexp-compiler
  246. (syntax-rules (=> compiler expander)
  247. "Define NAME as a compiler for objects matching PREDICATE encountered in
  248. gexps.
  249. In the simplest form of the macro, BODY must return (1) a derivation for
  250. a record of the specified type, for SYSTEM and TARGET (the latter of which is
  251. #f except when cross-compiling), (2) another record that can itself be
  252. compiled down to a derivation, or (3) an object of a primitive data type.
  253. The more elaborate form allows you to specify an expander:
  254. (define-gexp-compiler something-compiler <something>
  255. compiler => (lambda (param system target) ...)
  256. expander => (lambda (param drv output) ...))
  257. The expander specifies how an object is converted to its sexp representation."
  258. ((_ (name (param record-type) system target) body ...)
  259. (define-gexp-compiler name record-type
  260. compiler => (lambda (param system target) body ...)
  261. expander => default-expander))
  262. ((_ name record-type
  263. compiler => compile
  264. expander => expand)
  265. (begin
  266. (define name
  267. (gexp-compiler record-type compile expand))
  268. (register-compiler! name)))))
  269. (define-gexp-compiler (derivation-compiler (drv <derivation>) system target)
  270. ;; Derivations are the lowest-level representation, so this is the identity
  271. ;; compiler.
  272. (with-monad %store-monad
  273. (return drv)))
  274. ;; Expand to a raw ".drv" file for the lowerable object it wraps. In other
  275. ;; words, this gives the raw ".drv" file instead of its build result.
  276. (define-record-type <raw-derivation-file>
  277. (raw-derivation-file obj)
  278. raw-derivation-file?
  279. (obj raw-derivation-file-object)) ;lowerable object
  280. (define-gexp-compiler raw-derivation-file-compiler <raw-derivation-file>
  281. compiler => (lambda (obj system target)
  282. (mlet %store-monad ((obj (lower-object
  283. (raw-derivation-file-object obj)
  284. system #:target target)))
  285. ;; Returning the .drv file name instead of the <derivation>
  286. ;; record ensures that 'lower-gexp' will classify it as a
  287. ;; "source" and not as an "input".
  288. (return (if (derivation? obj)
  289. (derivation-file-name obj)
  290. obj))))
  291. expander => (lambda (obj lowered output)
  292. (if (derivation? lowered)
  293. (derivation-file-name lowered)
  294. lowered)))
  295. ;;;
  296. ;;; System dependencies.
  297. ;;;
  298. ;; Binding form for the current system and cross-compilation target.
  299. (define-record-type <system-binding>
  300. (system-binding proc)
  301. system-binding?
  302. (proc system-binding-proc))
  303. (define-syntax let-system
  304. (syntax-rules ()
  305. "Introduce a system binding in a gexp. The simplest form is:
  306. (let-system system
  307. (cond ((string=? system \"x86_64-linux\") ...)
  308. (else ...)))
  309. which binds SYSTEM to the currently targeted system. The second form is
  310. similar, but it also shows the cross-compilation target:
  311. (let-system (system target)
  312. ...)
  313. Here TARGET is bound to the cross-compilation triplet or #f."
  314. ((_ (system target) exp0 exp ...)
  315. (system-binding (lambda (system target)
  316. exp0 exp ...)))
  317. ((_ system exp0 exp ...)
  318. (system-binding (lambda (system target)
  319. exp0 exp ...)))))
  320. (define-gexp-compiler system-binding-compiler <system-binding>
  321. compiler => (lambda (binding system target)
  322. (match binding
  323. (($ <system-binding> proc)
  324. (with-monad %store-monad
  325. ;; PROC is expected to return a lowerable object.
  326. ;; 'lower-object' takes care of residualizing it to a
  327. ;; derivation or similar.
  328. (return (proc system target))))))
  329. ;; Delegate to the expander of the object returned by PROC.
  330. expander => #f)
  331. ;;;
  332. ;;; File declarations.
  333. ;;;
  334. ;; A local file name. FILE is the file name the user entered, which can be a
  335. ;; relative file name, and ABSOLUTE is a promise that computes its canonical
  336. ;; absolute file name. We keep it in a promise to compute it lazily and avoid
  337. ;; repeated 'stat' calls.
  338. (define-record-type <local-file>
  339. (%%local-file file absolute name recursive? select?)
  340. local-file?
  341. (file local-file-file) ;string
  342. (absolute %local-file-absolute-file-name) ;promise string
  343. (name local-file-name) ;string
  344. (recursive? local-file-recursive?) ;Boolean
  345. (select? local-file-select?)) ;string stat -> Boolean
  346. (define (true file stat) #t)
  347. (define* (%local-file file promise #:optional (name (basename file))
  348. #:key
  349. (literal? #t) location
  350. recursive? (select? true))
  351. ;; This intermediate procedure is part of our ABI, but the underlying
  352. ;; %%LOCAL-FILE is not.
  353. (when (and (not literal?) (not (string-prefix? "/" file)))
  354. (warning (and=> location source-properties->location)
  355. (G_ "resolving '~a' relative to current directory~%")
  356. file))
  357. (%%local-file file promise name recursive? select?))
  358. (define (absolute-file-name file directory)
  359. "Return the canonical absolute file name for FILE, which lives in the
  360. vicinity of DIRECTORY."
  361. (canonicalize-path
  362. (cond ((string-prefix? "/" file) file)
  363. ((not directory) file)
  364. ((string-prefix? "/" directory)
  365. (string-append directory "/" file))
  366. (else file))))
  367. (define-syntax local-file
  368. (lambda (s)
  369. "Return an object representing local file FILE to add to the store; this
  370. object can be used in a gexp. If FILE is a relative file name, it is looked
  371. up relative to the source file where this form appears. FILE will be added to
  372. the store under NAME--by default the base name of FILE.
  373. When RECURSIVE? is true, the contents of FILE are added recursively; if FILE
  374. designates a flat file and RECURSIVE? is true, its contents are added, and its
  375. permission bits are kept.
  376. When RECURSIVE? is true, call (SELECT? FILE STAT) for each directory entry,
  377. where FILE is the entry's absolute file name and STAT is the result of
  378. 'lstat'; exclude entries for which SELECT? does not return true.
  379. This is the declarative counterpart of the 'interned-file' monadic procedure.
  380. It is implemented as a macro to capture the current source directory where it
  381. appears."
  382. (syntax-case s ()
  383. ((_ file rest ...)
  384. (string? (syntax->datum #'file))
  385. ;; FILE is a literal, so resolve it relative to the source directory.
  386. #'(%local-file file
  387. (delay (absolute-file-name file (current-source-directory)))
  388. rest ...))
  389. ((_ file rest ...)
  390. ;; Resolve FILE relative to the current directory.
  391. (with-syntax ((location (datum->syntax s (syntax-source s))))
  392. #`(%local-file file
  393. (delay (absolute-file-name file (getcwd)))
  394. rest ...
  395. #:location 'location
  396. #:literal? #f)))
  397. ((_)
  398. #'(syntax-error "missing file name"))
  399. (id
  400. (identifier? #'id)
  401. ;; XXX: We could return #'(lambda (file . rest) ...). However,
  402. ;; (syntax-source #'id) is #f so (current-source-directory) would not
  403. ;; work. Thus, simply forbid this form.
  404. #'(syntax-error
  405. "'local-file' is a macro and cannot be used like this")))))
  406. (define (local-file-absolute-file-name file)
  407. "Return the absolute file name for FILE, a <local-file> instance. A
  408. 'system-error' exception is raised if FILE could not be found."
  409. (force (%local-file-absolute-file-name file)))
  410. (define-gexp-compiler (local-file-compiler (file <local-file>) system target)
  411. ;; "Compile" FILE by adding it to the store.
  412. (match file
  413. (($ <local-file> file (= force absolute) name recursive? select?)
  414. ;; Canonicalize FILE so that if it's a symlink, it is resolved. Failing
  415. ;; to do that, when RECURSIVE? is #t, we could end up creating a dangling
  416. ;; symlink in the store, and when RECURSIVE? is #f 'add-to-store' would
  417. ;; just throw an error, both of which are inconvenient.
  418. (interned-file absolute name
  419. #:recursive? recursive? #:select? select?))))
  420. (define-record-type <plain-file>
  421. (%plain-file name content references)
  422. plain-file?
  423. (name plain-file-name) ;string
  424. (content plain-file-content) ;string or bytevector
  425. (references plain-file-references)) ;list (currently unused)
  426. (define (plain-file name content)
  427. "Return an object representing a text file called NAME with the given
  428. CONTENT (a string) to be added to the store.
  429. This is the declarative counterpart of 'text-file'."
  430. ;; XXX: For now just ignore 'references' because it's not clear how to use
  431. ;; them in a declarative context.
  432. (%plain-file name content '()))
  433. (define-gexp-compiler (plain-file-compiler (file <plain-file>) system target)
  434. ;; "Compile" FILE by adding it to the store.
  435. (match file
  436. (($ <plain-file> name (and (? string?) content) references)
  437. (text-file name content references))
  438. (($ <plain-file> name (and (? bytevector?) content) references)
  439. (binary-file name content references))))
  440. (define-record-type <computed-file>
  441. (%computed-file name gexp guile options)
  442. computed-file?
  443. (name computed-file-name) ;string
  444. (gexp computed-file-gexp) ;gexp
  445. (guile computed-file-guile) ;<package>
  446. (options computed-file-options)) ;list of arguments
  447. (define* (computed-file name gexp
  448. #:key guile (local-build? #t) (options '()))
  449. "Return an object representing the store item NAME, a file or directory
  450. computed by GEXP. When LOCAL-BUILD? is #t (the default), it ensures the
  451. corresponding derivation is built locally. OPTIONS may be used to pass
  452. additional arguments to 'gexp->derivation'.
  453. This is the declarative counterpart of 'gexp->derivation'."
  454. (let ((options* `(#:local-build? ,local-build? ,@options)))
  455. (%computed-file name gexp guile options*)))
  456. (define-gexp-compiler (computed-file-compiler (file <computed-file>)
  457. system target)
  458. ;; Compile FILE by returning a derivation whose build expression is its
  459. ;; gexp.
  460. (match file
  461. (($ <computed-file> name gexp guile options)
  462. (if guile
  463. (mlet %store-monad ((guile (lower-object guile system
  464. #:target target)))
  465. (apply gexp->derivation name gexp #:guile-for-build guile
  466. #:system system #:target target options))
  467. (apply gexp->derivation name gexp
  468. #:system system #:target target options)))))
  469. (define-record-type <program-file>
  470. (%program-file name gexp guile path)
  471. program-file?
  472. (name program-file-name) ;string
  473. (gexp program-file-gexp) ;gexp
  474. (guile program-file-guile) ;package
  475. (path program-file-module-path)) ;list of strings
  476. (define* (program-file name gexp #:key (guile #f) (module-path %load-path))
  477. "Return an object representing the executable store item NAME that runs
  478. GEXP. GUILE is the Guile package used to execute that script. Imported
  479. modules of GEXP are looked up in MODULE-PATH.
  480. This is the declarative counterpart of 'gexp->script'."
  481. (%program-file name gexp guile module-path))
  482. (define-gexp-compiler (program-file-compiler (file <program-file>)
  483. system target)
  484. ;; Compile FILE by returning a derivation that builds the script.
  485. (match file
  486. (($ <program-file> name gexp guile module-path)
  487. (gexp->script name gexp
  488. #:module-path module-path
  489. #:guile (or guile (default-guile))
  490. #:system system
  491. #:target target))))
  492. (define-record-type <scheme-file>
  493. (%scheme-file name gexp splice? load-path?)
  494. scheme-file?
  495. (name scheme-file-name) ;string
  496. (gexp scheme-file-gexp) ;gexp
  497. (splice? scheme-file-splice?) ;Boolean
  498. (load-path? scheme-file-set-load-path?)) ;Boolean
  499. (define* (scheme-file name gexp #:key splice? (set-load-path? #t))
  500. "Return an object representing the Scheme file NAME that contains GEXP.
  501. This is the declarative counterpart of 'gexp->file'."
  502. (%scheme-file name gexp splice? set-load-path?))
  503. (define-gexp-compiler (scheme-file-compiler (file <scheme-file>)
  504. system target)
  505. ;; Compile FILE by returning a derivation that builds the file.
  506. (match file
  507. (($ <scheme-file> name gexp splice? set-load-path?)
  508. (gexp->file name gexp
  509. #:set-load-path? set-load-path?
  510. #:splice? splice?
  511. #:system system
  512. #:target target))))
  513. ;; Appending SUFFIX to BASE's output file name.
  514. (define-record-type <file-append>
  515. (%file-append base suffix)
  516. file-append?
  517. (base file-append-base) ;<package> | <derivation> | ...
  518. (suffix file-append-suffix)) ;list of strings
  519. (define (write-file-append file port)
  520. (match file
  521. (($ <file-append> base suffix)
  522. (format port "#<file-append ~s ~s>" base
  523. (string-join suffix)))))
  524. (set-record-type-printer! <file-append> write-file-append)
  525. (define (file-append base . suffix)
  526. "Return a <file-append> object that expands to the concatenation of BASE and
  527. SUFFIX."
  528. (%file-append base suffix))
  529. (define-gexp-compiler file-append-compiler <file-append>
  530. compiler => (lambda (obj system target)
  531. (match obj
  532. (($ <file-append> base _)
  533. (lower-object base system #:target target))))
  534. expander => (lambda (obj lowered output)
  535. (match obj
  536. (($ <file-append> base suffix)
  537. (let* ((expand (lookup-expander base))
  538. (base (expand base lowered output)))
  539. (string-append base (string-concatenate suffix)))))))
  540. ;; Representation of SRFI-39 parameter settings in the dynamic scope of an
  541. ;; object lowering.
  542. (define-record-type <parameterized>
  543. (parameterized bindings thunk)
  544. parameterized?
  545. (bindings parameterized-bindings) ;list of parameter/value pairs
  546. (thunk parameterized-thunk)) ;thunk
  547. (define-syntax-rule (with-parameters ((param value) ...) body ...)
  548. "Bind each PARAM to the corresponding VALUE for the extent during which BODY
  549. is lowered. Consider this example:
  550. (with-parameters ((%current-system \"x86_64-linux\"))
  551. coreutils)
  552. It returns a <parameterized> object that ensures %CURRENT-SYSTEM is set to
  553. x86_64-linux when COREUTILS is lowered."
  554. (parameterized (list (list param (lambda () value)) ...)
  555. (lambda ()
  556. body ...)))
  557. (define-gexp-compiler compile-parameterized <parameterized>
  558. compiler =>
  559. (lambda (parameterized system target)
  560. (match (parameterized-bindings parameterized)
  561. (((parameters values) ...)
  562. (let ((fluids (map parameter-fluid parameters))
  563. (thunk (parameterized-thunk parameterized)))
  564. ;; Install the PARAMETERS for the dynamic extent of THUNK.
  565. (with-fluids* fluids
  566. (map (lambda (thunk) (thunk)) values)
  567. (lambda ()
  568. ;; Special-case '%current-system' and '%current-target-system' to
  569. ;; make sure we get the desired effect.
  570. (let ((system (if (memq %current-system parameters)
  571. (%current-system)
  572. system))
  573. (target (if (memq %current-target-system parameters)
  574. (%current-target-system)
  575. target)))
  576. (lower-object (thunk) system #:target target))))))))
  577. expander => (lambda (parameterized lowered output)
  578. (match (parameterized-bindings parameterized)
  579. (((parameters values) ...)
  580. (let ((fluids (map parameter-fluid parameters))
  581. (thunk (parameterized-thunk parameterized)))
  582. ;; Install the PARAMETERS for the dynamic extent of THUNK.
  583. (with-fluids* fluids
  584. (map (lambda (thunk) (thunk)) values)
  585. (lambda ()
  586. ;; Delegate to the expander of the wrapped object.
  587. (let* ((base (thunk))
  588. (expand (lookup-expander base)))
  589. (expand base lowered output)))))))))
  590. ;;;
  591. ;;; Inputs & outputs.
  592. ;;;
  593. ;; The input of a gexp.
  594. (define-record-type <gexp-input>
  595. (%gexp-input thing output native?)
  596. gexp-input?
  597. (thing gexp-input-thing) ;<package> | <origin> | <derivation> | ...
  598. (output gexp-input-output) ;string
  599. (native? gexp-input-native?)) ;Boolean
  600. (define (write-gexp-input input port)
  601. (match input
  602. (($ <gexp-input> thing output #f)
  603. (format port "#<gexp-input ~s:~a>" thing output))
  604. (($ <gexp-input> thing output #t)
  605. (format port "#<gexp-input native ~s:~a>" thing output))))
  606. (set-record-type-printer! <gexp-input> write-gexp-input)
  607. (define* (gexp-input thing ;convenience procedure
  608. #:optional (output "out")
  609. #:key native?)
  610. "Return a new <gexp-input> for the OUTPUT of THING; NATIVE? determines
  611. whether this should be considered a \"native\" input or not."
  612. (%gexp-input thing output native?))
  613. ;; Reference to one of the derivation's outputs, for gexps used in
  614. ;; derivations.
  615. (define-record-type <gexp-output>
  616. (gexp-output name)
  617. gexp-output?
  618. (name gexp-output-name))
  619. (define (write-gexp-output output port)
  620. (match output
  621. (($ <gexp-output> name)
  622. (format port "#<gexp-output ~a>" name))))
  623. (set-record-type-printer! <gexp-output> write-gexp-output)
  624. (define* (gexp-attribute gexp self-attribute #:optional (equal? equal?))
  625. "Recurse on GEXP and the expressions it refers to, summing the items
  626. returned by SELF-ATTRIBUTE, a procedure that takes a gexp. Use EQUAL? as the
  627. second argument to 'delete-duplicates'."
  628. (if (gexp? gexp)
  629. (delete-duplicates
  630. (append (self-attribute gexp)
  631. (append-map (match-lambda
  632. (($ <gexp-input> (? gexp? exp))
  633. (gexp-attribute exp self-attribute))
  634. (($ <gexp-input> (lst ...))
  635. (append-map (lambda (item)
  636. (if (gexp? item)
  637. (gexp-attribute item
  638. self-attribute)
  639. '()))
  640. lst))
  641. (_
  642. '()))
  643. (gexp-references gexp)))
  644. equal?)
  645. '())) ;plain Scheme data type
  646. (define (gexp-modules gexp)
  647. "Return the list of Guile module names GEXP relies on. If (gexp? GEXP) is
  648. false, meaning that GEXP is a plain Scheme object, return the empty list."
  649. (define (module=? m1 m2)
  650. ;; Return #t when M1 equals M2. Special-case '=>' specs because their
  651. ;; right-hand side may not be comparable with 'equal?': it's typically a
  652. ;; file-like object that embeds a gexp, which in turn embeds closure;
  653. ;; those closures may be 'eq?' when running compiled code but are unlikely
  654. ;; to be 'eq?' when running on 'eval'. Ignore the right-hand side to
  655. ;; avoid this discrepancy.
  656. (match m1
  657. (((name1 ...) '=> _)
  658. (match m2
  659. (((name2 ...) '=> _) (equal? name1 name2))
  660. (_ #f)))
  661. (_
  662. (equal? m1 m2))))
  663. (gexp-attribute gexp gexp-self-modules module=?))
  664. (define (gexp-extensions gexp)
  665. "Return the list of Guile extensions (packages) GEXP relies on. If (gexp?
  666. GEXP) is false, meaning that GEXP is a plain Scheme object, return the empty
  667. list."
  668. (gexp-attribute gexp gexp-self-extensions))
  669. (define (self-quoting? x)
  670. (letrec-syntax ((one-of (syntax-rules ()
  671. ((_) #f)
  672. ((_ pred rest ...)
  673. (or (pred x)
  674. (one-of rest ...))))))
  675. (one-of symbol? string? keyword? pair? null? array?
  676. number? boolean? char?)))
  677. (define* (lower-inputs inputs
  678. #:key system target)
  679. "Turn any object from INPUTS into a derivation input for SYSTEM or a store
  680. item (a \"source\"); return the corresponding input list as a monadic value.
  681. When TARGET is true, use it as the cross-compilation target triplet."
  682. (define (store-item? obj)
  683. (and (string? obj) (store-path? obj)))
  684. (define filterm
  685. (lift1 (cut filter ->bool <>) %store-monad))
  686. (with-monad %store-monad
  687. (>>= (mapm/accumulate-builds
  688. (match-lambda
  689. (((? struct? thing) sub-drv ...)
  690. (mlet %store-monad ((obj (lower-object
  691. thing system #:target target)))
  692. (return (match obj
  693. ((? derivation? drv)
  694. (let ((outputs (if (null? sub-drv)
  695. '("out")
  696. sub-drv)))
  697. (derivation-input drv outputs)))
  698. ((? store-item? item)
  699. item)
  700. ((? self-quoting?)
  701. ;; Some inputs such as <system-binding> can lower to
  702. ;; a self-quoting object that FILTERM will filter
  703. ;; out.
  704. #f)))))
  705. (((? store-item? item))
  706. (return item)))
  707. inputs)
  708. filterm)))
  709. (define* (lower-reference-graphs graphs #:key system target)
  710. "Given GRAPHS, a list of (FILE-NAME INPUT ...) lists for use as a
  711. #:reference-graphs argument, lower it such that each INPUT is replaced by the
  712. corresponding <derivation-input> or store item."
  713. (match graphs
  714. (((file-names . inputs) ...)
  715. (mlet %store-monad ((inputs (lower-inputs inputs
  716. #:system system
  717. #:target target)))
  718. (return (map cons file-names inputs))))))
  719. (define* (lower-references lst #:key system target)
  720. "Based on LST, a list of output names and packages, return a list of output
  721. names and file names suitable for the #:allowed-references argument to
  722. 'derivation'."
  723. (with-monad %store-monad
  724. (define lower
  725. (match-lambda
  726. ((? string? output)
  727. (return output))
  728. (($ <gexp-input> thing output native?)
  729. (mlet %store-monad ((drv (lower-object thing system
  730. #:target (if native?
  731. #f target))))
  732. (return (derivation->output-path drv output))))
  733. (thing
  734. (mlet %store-monad ((drv (lower-object thing system
  735. #:target target)))
  736. (return (derivation->output-path drv))))))
  737. (mapm/accumulate-builds lower lst)))
  738. (define default-guile-derivation
  739. ;; Here we break the abstraction by talking to the higher-level layer.
  740. ;; Thus, do the resolution lazily to hide the circular dependency.
  741. (let ((proc (delay
  742. (let ((iface (resolve-interface '(guix packages))))
  743. (module-ref iface 'default-guile-derivation)))))
  744. (lambda (system)
  745. ((force proc) system))))
  746. ;; Representation of a gexp instantiated for a given target and system.
  747. ;; It's an intermediate representation between <gexp> and <derivation>.
  748. (define-record-type <lowered-gexp>
  749. (lowered-gexp sexp inputs sources guile load-path load-compiled-path)
  750. lowered-gexp?
  751. (sexp lowered-gexp-sexp) ;sexp
  752. (inputs lowered-gexp-inputs) ;list of <derivation-input>
  753. (sources lowered-gexp-sources) ;list of store items
  754. (guile lowered-gexp-guile) ;<derivation-input> | #f
  755. (load-path lowered-gexp-load-path) ;list of store items
  756. (load-compiled-path lowered-gexp-load-compiled-path)) ;list of store items
  757. (define* (imported+compiled-modules modules system
  758. #:key (extensions '())
  759. deprecation-warnings guile
  760. (module-path %load-path))
  761. "Return a pair where the first element is the imported MODULES and the
  762. second element is the derivation to compile them."
  763. (mcached equal?
  764. (mlet %store-monad ((modules (if (pair? modules)
  765. (imported-modules modules
  766. #:system system
  767. #:module-path module-path)
  768. (return #f)))
  769. (compiled (if (pair? modules)
  770. (compiled-modules modules
  771. #:system system
  772. #:module-path module-path
  773. #:extensions extensions
  774. #:guile guile
  775. #:deprecation-warnings
  776. deprecation-warnings)
  777. (return #f))))
  778. (return (cons modules compiled)))
  779. modules
  780. system extensions guile deprecation-warnings module-path))
  781. (define* (lower-gexp exp
  782. #:key
  783. (module-path %load-path)
  784. (system (%current-system))
  785. (target 'current)
  786. (graft? (%graft?))
  787. (guile-for-build (%guile-for-build))
  788. (effective-version "3.0")
  789. deprecation-warnings)
  790. "*Note: This API is subject to change; use at your own risk!*
  791. Lower EXP, a gexp, instantiating it for SYSTEM and TARGET. Return a
  792. <lowered-gexp> ready to be used.
  793. Lowered gexps are an intermediate representation that's useful for
  794. applications that deal with gexps outside in a way that is disconnected from
  795. derivations--e.g., code evaluated for its side effects."
  796. (define %modules
  797. (delete-duplicates (gexp-modules exp)))
  798. (define (search-path modules extensions suffix)
  799. (append (match modules
  800. ((? derivation? drv)
  801. (list (derivation->output-path drv)))
  802. (#f
  803. '())
  804. ((? store-path? item)
  805. (list item)))
  806. (map (lambda (extension)
  807. (string-append (match extension
  808. ((? derivation? drv)
  809. (derivation->output-path drv))
  810. ((? store-path? item)
  811. item))
  812. suffix))
  813. extensions)))
  814. (mlet* %store-monad ( ;; The following binding forces '%current-system' and
  815. ;; '%current-target-system' to be looked up at >>=
  816. ;; time.
  817. (graft? (set-grafting graft?))
  818. (system -> (or system (%current-system)))
  819. (target -> (if (eq? target 'current)
  820. (%current-target-system)
  821. target))
  822. (guile (if guile-for-build
  823. (return guile-for-build)
  824. (default-guile-derivation system)))
  825. (normals (lower-inputs (gexp-inputs exp)
  826. #:system system
  827. #:target target))
  828. (natives (lower-inputs (gexp-native-inputs exp)
  829. #:system system
  830. #:target #f))
  831. (inputs -> (append normals natives))
  832. (sexp (gexp->sexp exp
  833. #:system system
  834. #:target target))
  835. (extensions -> (gexp-extensions exp))
  836. (exts (mapm %store-monad
  837. (lambda (obj)
  838. (lower-object obj system
  839. #:target #f))
  840. extensions))
  841. (modules+compiled (imported+compiled-modules
  842. %modules system
  843. #:extensions extensions
  844. #:deprecation-warnings
  845. deprecation-warnings
  846. #:guile guile
  847. #:module-path module-path))
  848. (modules -> (car modules+compiled))
  849. (compiled -> (cdr modules+compiled)))
  850. (define load-path
  851. (search-path modules exts
  852. (string-append "/share/guile/site/" effective-version)))
  853. (define load-compiled-path
  854. (search-path compiled exts
  855. (string-append "/lib/guile/" effective-version
  856. "/site-ccache")))
  857. (mbegin %store-monad
  858. (set-grafting graft?) ;restore the initial setting
  859. (return (lowered-gexp sexp
  860. `(,@(if (derivation? modules)
  861. (list (derivation-input modules))
  862. '())
  863. ,@(if compiled
  864. (list (derivation-input compiled))
  865. '())
  866. ,@(map derivation-input exts)
  867. ,@(filter derivation-input? inputs))
  868. (filter string? (cons modules inputs))
  869. (derivation-input guile '("out"))
  870. load-path
  871. load-compiled-path)))))
  872. (define* (gexp->derivation name exp
  873. #:key
  874. system (target 'current)
  875. hash hash-algo recursive?
  876. (env-vars '())
  877. (modules '())
  878. (module-path %load-path)
  879. (guile-for-build (%guile-for-build))
  880. (effective-version "3.0")
  881. (graft? (%graft?))
  882. references-graphs
  883. allowed-references disallowed-references
  884. leaked-env-vars
  885. local-build? (substitutable? #t)
  886. (properties '())
  887. deprecation-warnings
  888. (script-name (string-append name "-builder")))
  889. "Return a derivation NAME that runs EXP (a gexp) with GUILE-FOR-BUILD (a
  890. derivation) on SYSTEM; EXP is stored in a file called SCRIPT-NAME. When
  891. TARGET is true, it is used as the cross-compilation target triplet for
  892. packages referred to by EXP.
  893. MODULES is deprecated in favor of 'with-imported-modules'. Its meaning is to
  894. make MODULES available in the evaluation context of EXP; MODULES is a list of
  895. names of Guile modules searched in MODULE-PATH to be copied in the store,
  896. compiled, and made available in the load path during the execution of
  897. EXP---e.g., '((guix build utils) (guix build gnu-build-system)).
  898. EFFECTIVE-VERSION determines the string to use when adding extensions of
  899. EXP (see 'with-extensions') to the search path---e.g., \"2.2\".
  900. GRAFT? determines whether packages referred to by EXP should be grafted when
  901. applicable.
  902. When REFERENCES-GRAPHS is true, it must be a list of tuples of one of the
  903. following forms:
  904. (FILE-NAME PACKAGE)
  905. (FILE-NAME PACKAGE OUTPUT)
  906. (FILE-NAME DERIVATION)
  907. (FILE-NAME DERIVATION OUTPUT)
  908. (FILE-NAME STORE-ITEM)
  909. The right-hand-side of each element of REFERENCES-GRAPHS is automatically made
  910. an input of the build process of EXP. In the build environment, each
  911. FILE-NAME contains the reference graph of the corresponding item, in a simple
  912. text format.
  913. ALLOWED-REFERENCES must be either #f or a list of output names and packages.
  914. In the latter case, the list denotes store items that the result is allowed to
  915. refer to. Any reference to another store item will lead to a build error.
  916. Similarly for DISALLOWED-REFERENCES, which can list items that must not be
  917. referenced by the outputs.
  918. DEPRECATION-WARNINGS determines whether to show deprecation warnings while
  919. compiling modules. It can be #f, #t, or 'detailed.
  920. The other arguments are as for 'derivation'."
  921. (define outputs (gexp-outputs exp))
  922. (define requested-graft? graft?)
  923. (define (graphs-file-names graphs)
  924. ;; Return a list of (FILE-NAME . STORE-PATH) pairs made from GRAPHS.
  925. (map (match-lambda
  926. ((file-name . (? derivation-input? input))
  927. (cons file-name (first (derivation-input-output-paths input))))
  928. ((file-name . (? string? item))
  929. (cons file-name item)))
  930. graphs))
  931. (define (add-modules exp modules)
  932. (if (null? modules)
  933. exp
  934. (make-gexp (gexp-references exp)
  935. (append modules (gexp-self-modules exp))
  936. (gexp-self-extensions exp)
  937. (gexp-proc exp))))
  938. (mlet* %store-monad ( ;; The following binding forces '%current-system' and
  939. ;; '%current-target-system' to be looked up at >>=
  940. ;; time.
  941. (graft? (set-grafting graft?))
  942. (system -> (or system (%current-system)))
  943. (target -> (if (eq? target 'current)
  944. (%current-target-system)
  945. target))
  946. (exp -> (add-modules exp modules))
  947. (lowered (lower-gexp exp
  948. #:module-path module-path
  949. #:system system
  950. #:target target
  951. #:graft? requested-graft?
  952. #:guile-for-build
  953. guile-for-build
  954. #:effective-version
  955. effective-version
  956. #:deprecation-warnings
  957. deprecation-warnings))
  958. (graphs (if references-graphs
  959. (lower-reference-graphs references-graphs
  960. #:system system
  961. #:target target)
  962. (return #f)))
  963. (allowed (if allowed-references
  964. (lower-references allowed-references
  965. #:system system
  966. #:target target)
  967. (return #f)))
  968. (disallowed (if disallowed-references
  969. (lower-references disallowed-references
  970. #:system system
  971. #:target target)
  972. (return #f)))
  973. (guile -> (lowered-gexp-guile lowered))
  974. (builder (text-file script-name
  975. (object->string
  976. (lowered-gexp-sexp lowered)))))
  977. (mbegin %store-monad
  978. (set-grafting graft?) ;restore the initial setting
  979. (raw-derivation name
  980. (string-append (derivation-input-output-path guile)
  981. "/bin/guile")
  982. `("--no-auto-compile"
  983. ,@(append-map (lambda (directory)
  984. `("-L" ,directory))
  985. (lowered-gexp-load-path lowered))
  986. ,@(append-map (lambda (directory)
  987. `("-C" ,directory))
  988. (lowered-gexp-load-compiled-path lowered))
  989. ,builder)
  990. #:outputs outputs
  991. #:env-vars env-vars
  992. #:system system
  993. #:inputs `(,guile
  994. ,@(lowered-gexp-inputs lowered)
  995. ,@(match graphs
  996. (((_ . inputs) ...)
  997. (filter derivation-input? inputs))
  998. (#f '())))
  999. #:sources `(,builder
  1000. ,@(if (and (string? modules)
  1001. (store-path? modules))
  1002. (list modules)
  1003. '())
  1004. ,@(lowered-gexp-sources lowered)
  1005. ,@(match graphs
  1006. (((_ . inputs) ...)
  1007. (filter string? inputs))
  1008. (#f '())))
  1009. #:hash hash #:hash-algo hash-algo #:recursive? recursive?
  1010. #:references-graphs (and=> graphs graphs-file-names)
  1011. #:allowed-references allowed
  1012. #:disallowed-references disallowed
  1013. #:leaked-env-vars leaked-env-vars
  1014. #:local-build? local-build?
  1015. #:substitutable? substitutable?
  1016. #:properties properties))))
  1017. (define* (gexp-inputs exp #:key native?)
  1018. "Return the input list for EXP. When NATIVE? is true, return only native
  1019. references; otherwise, return only non-native references."
  1020. ;; TODO: Return <gexp-input> records instead of tuples.
  1021. (define (add-reference-inputs ref result)
  1022. (match ref
  1023. (($ <gexp-input> (? gexp? exp) _ #t)
  1024. (if native?
  1025. (append (gexp-inputs exp)
  1026. (gexp-inputs exp #:native? #t)
  1027. result)
  1028. result))
  1029. (($ <gexp-input> (? gexp? exp) _ #f)
  1030. (append (gexp-inputs exp #:native? native?)
  1031. result))
  1032. (($ <gexp-input> (? string? str))
  1033. (if (direct-store-path? str)
  1034. (cons `(,str) result)
  1035. result))
  1036. (($ <gexp-input> (? struct? thing) output n?)
  1037. (if (and (eqv? n? native?) (lookup-compiler thing))
  1038. ;; THING is a derivation, or a package, or an origin, etc.
  1039. (cons `(,thing ,output) result)
  1040. result))
  1041. (($ <gexp-input> (lst ...) output n?)
  1042. (fold-right add-reference-inputs result
  1043. ;; XXX: For now, automatically convert LST to a list of
  1044. ;; gexp-inputs. Inherit N?.
  1045. (map (match-lambda
  1046. ((? gexp-input? x)
  1047. (%gexp-input (gexp-input-thing x)
  1048. (gexp-input-output x)
  1049. n?))
  1050. (x
  1051. (%gexp-input x "out" n?)))
  1052. lst)))
  1053. (_
  1054. ;; Ignore references to other kinds of objects.
  1055. result)))
  1056. (fold-right add-reference-inputs
  1057. '()
  1058. (gexp-references exp)))
  1059. (define gexp-native-inputs
  1060. (cut gexp-inputs <> #:native? #t))
  1061. (define (gexp-outputs exp)
  1062. "Return the outputs referred to by EXP as a list of strings."
  1063. (define (add-reference-output ref result)
  1064. (match ref
  1065. (($ <gexp-output> name)
  1066. (cons name result))
  1067. (($ <gexp-input> (? gexp? exp))
  1068. (append (gexp-outputs exp) result))
  1069. (($ <gexp-input> (lst ...) output native?)
  1070. ;; XXX: Automatically convert LST.
  1071. (add-reference-output (map (match-lambda
  1072. ((? gexp-input? x) x)
  1073. (x (%gexp-input x "out" native?)))
  1074. lst)
  1075. result))
  1076. ((lst ...)
  1077. (fold-right add-reference-output result lst))
  1078. (_
  1079. result)))
  1080. (delete-duplicates
  1081. (add-reference-output (gexp-references exp) '())))
  1082. (define* (gexp->sexp exp #:key
  1083. (system (%current-system))
  1084. (target (%current-target-system)))
  1085. "Return (monadically) the sexp corresponding to EXP for the given OUTPUT,
  1086. and in the current monad setting (system type, etc.)"
  1087. (define* (reference->sexp ref #:optional native?)
  1088. (with-monad %store-monad
  1089. (match ref
  1090. (($ <gexp-output> output)
  1091. ;; Output file names are not known in advance but the daemon defines
  1092. ;; an environment variable for each of them at build time, so use
  1093. ;; that trick.
  1094. (return `((@ (guile) getenv) ,output)))
  1095. (($ <gexp-input> (? gexp? exp) output n?)
  1096. (gexp->sexp exp
  1097. #:system system
  1098. #:target (if (or n? native?) #f target)))
  1099. (($ <gexp-input> (refs ...) output n?)
  1100. (mapm %store-monad
  1101. (lambda (ref)
  1102. ;; XXX: Automatically convert REF to an gexp-input.
  1103. (reference->sexp
  1104. (if (gexp-input? ref)
  1105. ref
  1106. (%gexp-input ref "out" n?))
  1107. (or n? native?)))
  1108. refs))
  1109. (($ <gexp-input> (? struct? thing) output n?)
  1110. (let ((target (if (or n? native?) #f target)))
  1111. (lower+expand-object thing system
  1112. #:target target
  1113. #:output output)))
  1114. (($ <gexp-input> (? self-quoting? x))
  1115. (return x))
  1116. (($ <gexp-input> x)
  1117. (raise (condition (&gexp-input-error (input x)))))
  1118. (x
  1119. (return x)))))
  1120. (mlet %store-monad
  1121. ((args (mapm %store-monad
  1122. reference->sexp (gexp-references exp))))
  1123. (return (apply (gexp-proc exp) args))))
  1124. (define-syntax-rule (define-syntax-parameter-once name proc)
  1125. ;; Like 'define-syntax-parameter' but ensure the top-level binding for NAME
  1126. ;; does not get redefined. This works around a race condition in a
  1127. ;; multi-threaded context with Guile <= 2.2.4: <https://bugs.gnu.org/27476>.
  1128. (eval-when (load eval expand compile)
  1129. (define name
  1130. (if (module-locally-bound? (current-module) 'name)
  1131. (module-ref (current-module) 'name)
  1132. (make-syntax-transformer 'name 'syntax-parameter
  1133. (list proc))))))
  1134. (define-syntax-parameter-once current-imported-modules
  1135. ;; Current list of imported modules.
  1136. (identifier-syntax '()))
  1137. (define-syntax-rule (with-imported-modules modules body ...)
  1138. "Mark the gexps defined in BODY... as requiring MODULES in their execution
  1139. environment."
  1140. (syntax-parameterize ((current-imported-modules
  1141. (identifier-syntax modules)))
  1142. body ...))
  1143. (define-syntax-parameter-once current-imported-extensions
  1144. ;; Current list of extensions.
  1145. (identifier-syntax '()))
  1146. (define-syntax-rule (with-extensions extensions body ...)
  1147. "Mark the gexps defined in BODY... as requiring EXTENSIONS in their
  1148. execution environment."
  1149. (syntax-parameterize ((current-imported-extensions
  1150. (identifier-syntax extensions)))
  1151. body ...))
  1152. (define-syntax gexp
  1153. (lambda (s)
  1154. (define (collect-escapes exp)
  1155. ;; Return all the 'ungexp' present in EXP.
  1156. (let loop ((exp exp)
  1157. (result '()))
  1158. (syntax-case exp (ungexp
  1159. ungexp-splicing
  1160. ungexp-native
  1161. ungexp-native-splicing)
  1162. ((ungexp _)
  1163. (cons exp result))
  1164. ((ungexp _ _)
  1165. (cons exp result))
  1166. ((ungexp-splicing _ ...)
  1167. (cons exp result))
  1168. ((ungexp-native _ ...)
  1169. (cons exp result))
  1170. ((ungexp-native-splicing _ ...)
  1171. (cons exp result))
  1172. ((exp0 . exp)
  1173. (let ((result (loop #'exp0 result)))
  1174. (loop #'exp result)))
  1175. (_
  1176. result))))
  1177. (define (escape->ref exp)
  1178. ;; Turn 'ungexp' form EXP into a "reference".
  1179. (syntax-case exp (ungexp ungexp-splicing
  1180. ungexp-native ungexp-native-splicing
  1181. output)
  1182. ((ungexp output)
  1183. #'(gexp-output "out"))
  1184. ((ungexp output name)
  1185. #'(gexp-output name))
  1186. ((ungexp thing)
  1187. #'(%gexp-input thing "out" #f))
  1188. ((ungexp drv-or-pkg out)
  1189. #'(%gexp-input drv-or-pkg out #f))
  1190. ((ungexp-splicing lst)
  1191. #'(%gexp-input lst "out" #f))
  1192. ((ungexp-native thing)
  1193. #'(%gexp-input thing "out" #t))
  1194. ((ungexp-native drv-or-pkg out)
  1195. #'(%gexp-input drv-or-pkg out #t))
  1196. ((ungexp-native-splicing lst)
  1197. #'(%gexp-input lst "out" #t))))
  1198. (define (substitute-ungexp exp substs)
  1199. ;; Given EXP, an 'ungexp' or 'ungexp-native' form, substitute it with
  1200. ;; the corresponding form in SUBSTS.
  1201. (match (assoc exp substs)
  1202. ((_ id)
  1203. id)
  1204. (_ ;internal error
  1205. (with-syntax ((exp exp))
  1206. #'(syntax-error "error: no 'ungexp' substitution" exp)))))
  1207. (define (substitute-ungexp-splicing exp substs)
  1208. (syntax-case exp ()
  1209. ((exp rest ...)
  1210. (match (assoc #'exp substs)
  1211. ((_ id)
  1212. (with-syntax ((id id))
  1213. #`(append id
  1214. #,(substitute-references #'(rest ...) substs))))
  1215. (_
  1216. #'(syntax-error "error: no 'ungexp-splicing' substitution"
  1217. exp))))))
  1218. (define (substitute-references exp substs)
  1219. ;; Return a variant of EXP where all the cars of SUBSTS have been
  1220. ;; replaced by the corresponding cdr.
  1221. (syntax-case exp (ungexp ungexp-native
  1222. ungexp-splicing ungexp-native-splicing)
  1223. ((ungexp _ ...)
  1224. (substitute-ungexp exp substs))
  1225. ((ungexp-native _ ...)
  1226. (substitute-ungexp exp substs))
  1227. (((ungexp-splicing _ ...) rest ...)
  1228. (substitute-ungexp-splicing exp substs))
  1229. (((ungexp-native-splicing _ ...) rest ...)
  1230. (substitute-ungexp-splicing exp substs))
  1231. ((exp0 . exp)
  1232. #`(cons #,(substitute-references #'exp0 substs)
  1233. #,(substitute-references #'exp substs)))
  1234. (x #''x)))
  1235. (syntax-case s (ungexp output)
  1236. ((_ exp)
  1237. (let* ((escapes (delete-duplicates (collect-escapes #'exp)))
  1238. (formals (generate-temporaries escapes))
  1239. (sexp (substitute-references #'exp (zip escapes formals)))
  1240. (refs (map escape->ref escapes)))
  1241. #`(make-gexp (list #,@refs)
  1242. current-imported-modules
  1243. current-imported-extensions
  1244. (lambda #,formals
  1245. #,sexp)))))))
  1246. ;;;
  1247. ;;; Module handling.
  1248. ;;;
  1249. (define %utils-module
  1250. ;; This file provides 'mkdir-p', needed to implement 'imported-files' and
  1251. ;; other primitives below. Note: We give the file name relative to this
  1252. ;; file you are currently reading; 'search-path' could return a file name
  1253. ;; relative to the current working directory.
  1254. (local-file "build/utils.scm"
  1255. "build-utils.scm"))
  1256. (define* (imported-files/derivation files
  1257. #:key (name "file-import")
  1258. (symlink? #f)
  1259. (system (%current-system))
  1260. (guile (%guile-for-build)))
  1261. "Return a derivation that imports FILES into STORE. FILES must be a list
  1262. of (FINAL-PATH . FILE) pairs. Each FILE is mapped to FINAL-PATH in the
  1263. resulting store path. FILE can be either a file name, or a file-like object,
  1264. as returned by 'local-file' for example. If SYMLINK? is true, create symlinks
  1265. to the source files instead of copying them."
  1266. (define file-pair
  1267. (match-lambda
  1268. ((final-path . (? string? file-name))
  1269. (mlet %store-monad ((file (interned-file file-name
  1270. (basename final-path))))
  1271. (return (list final-path file))))
  1272. ((final-path . file-like)
  1273. (mlet %store-monad ((file (lower-object file-like system)))
  1274. (return (list final-path file))))))
  1275. (mlet %store-monad ((files (mapm %store-monad file-pair files)))
  1276. (define build
  1277. (gexp
  1278. (begin
  1279. (primitive-load (ungexp %utils-module)) ;for 'mkdir-p'
  1280. (use-modules (ice-9 match))
  1281. (mkdir (ungexp output)) (chdir (ungexp output))
  1282. (for-each (match-lambda
  1283. ((final-path store-path)
  1284. (mkdir-p (dirname final-path))
  1285. ((ungexp (if symlink? 'symlink 'copy-file))
  1286. store-path final-path)))
  1287. '(ungexp files)))))
  1288. ;; TODO: Pass FILES as an environment variable so that BUILD remains
  1289. ;; exactly the same regardless of FILES: less disk space, and fewer
  1290. ;; 'add-to-store' RPCs.
  1291. (gexp->derivation name build
  1292. #:system system
  1293. #:guile-for-build guile
  1294. #:local-build? #t
  1295. #:substitutable? #f
  1296. ;; Avoid deprecation warnings about the use of the _IO*
  1297. ;; constants in (guix build utils).
  1298. #:env-vars
  1299. '(("GUILE_WARN_DEPRECATED" . "no")))))
  1300. (define* (imported-files files
  1301. #:key (name "file-import")
  1302. ;; The following parameters make sense when creating
  1303. ;; an actual derivation.
  1304. (system (%current-system))
  1305. (guile (%guile-for-build)))
  1306. "Import FILES into the store and return the resulting derivation or store
  1307. file name (a derivation is created if and only if some elements of FILES are
  1308. file-like objects and not local file names.) FILES must be a list
  1309. of (FINAL-PATH . FILE) pairs. Each FILE is mapped to FINAL-PATH in the
  1310. resulting store path. FILE can be either a file name, or a file-like object,
  1311. as returned by 'local-file' for example."
  1312. (if (any (match-lambda
  1313. ((_ . (? struct? source)) #t)
  1314. (_ #f))
  1315. files)
  1316. (imported-files/derivation files #:name name
  1317. #:symlink? derivation?
  1318. #:system system #:guile guile)
  1319. (interned-file-tree `(,name directory
  1320. ,@(file-mapping->tree files)))))
  1321. (define* (imported-modules modules
  1322. #:key (name "module-import")
  1323. (system (%current-system))
  1324. (guile (%guile-for-build))
  1325. (module-path %load-path))
  1326. "Return a derivation that contains the source files of MODULES, a list of
  1327. module names such as `(ice-9 q)'. All of MODULES must be either names of
  1328. modules to be found in the MODULE-PATH search path, or a module name followed
  1329. by an arrow followed by a file-like object. For example:
  1330. (imported-modules `((guix build utils)
  1331. (guix gcrypt)
  1332. ((guix config) => ,(scheme-file …))))
  1333. In this example, the first two modules are taken from MODULE-PATH, and the
  1334. last one is created from the given <scheme-file> object."
  1335. (let ((files (map (match-lambda
  1336. (((module ...) '=> file)
  1337. (cons (module->source-file-name module)
  1338. file))
  1339. ((module ...)
  1340. (let ((f (module->source-file-name module)))
  1341. (cons f (search-path* module-path f)))))
  1342. modules)))
  1343. (imported-files files #:name name
  1344. #:system system
  1345. #:guile guile)))
  1346. (define* (compiled-modules modules
  1347. #:key (name "module-import-compiled")
  1348. (system (%current-system))
  1349. target
  1350. (guile (%guile-for-build))
  1351. (module-path %load-path)
  1352. (extensions '())
  1353. (deprecation-warnings #f))
  1354. "Return a derivation that builds a tree containing the `.go' files
  1355. corresponding to MODULES. All the MODULES are built in a context where
  1356. they can refer to each other. When TARGET is true, cross-compile MODULES for
  1357. TARGET, a GNU triplet."
  1358. (define total (length modules))
  1359. (mlet %store-monad ((modules (imported-modules modules
  1360. #:system system
  1361. #:guile guile
  1362. #:module-path
  1363. module-path)))
  1364. (define build
  1365. (gexp
  1366. (begin
  1367. (primitive-load (ungexp %utils-module)) ;for 'mkdir-p'
  1368. (use-modules (ice-9 ftw)
  1369. (ice-9 format)
  1370. (srfi srfi-1)
  1371. (srfi srfi-26)
  1372. (system base target)
  1373. (system base compile))
  1374. (define (regular? file)
  1375. (not (member file '("." ".."))))
  1376. (define (process-entry entry output processed)
  1377. (if (file-is-directory? entry)
  1378. (let ((output (string-append output "/" (basename entry))))
  1379. (mkdir-p output)
  1380. (process-directory entry output processed))
  1381. (let* ((base (basename entry ".scm"))
  1382. (output (string-append output "/" base ".go")))
  1383. (format #t "[~2@a/~2@a] Compiling '~a'...~%"
  1384. (+ 1 processed (ungexp total))
  1385. (ungexp (* total 2))
  1386. entry)
  1387. (ungexp-splicing
  1388. (if target
  1389. (gexp ((with-target (ungexp target)
  1390. (lambda ()
  1391. (compile-file entry
  1392. #:output-file output
  1393. #:opts
  1394. %auto-compilation-options)))))
  1395. (gexp ((compile-file entry
  1396. #:output-file output
  1397. #:opts %auto-compilation-options)))))
  1398. (+ 1 processed))))
  1399. (define (process-directory directory output processed)
  1400. (let ((entries (map (cut string-append directory "/" <>)
  1401. (scandir directory regular?))))
  1402. (fold (cut process-entry <> output <>)
  1403. processed
  1404. entries)))
  1405. (define* (load-from-directory directory
  1406. #:optional (loaded 0))
  1407. "Load all the source files found in DIRECTORY."
  1408. ;; XXX: This works around <https://bugs.gnu.org/15602>.
  1409. (let ((entries (map (cut string-append directory "/" <>)
  1410. (scandir directory regular?))))
  1411. (fold (lambda (file loaded)
  1412. (if (file-is-directory? file)
  1413. (load-from-directory file loaded)
  1414. (begin
  1415. (format #t "[~2@a/~2@a] Loading '~a'...~%"
  1416. (+ 1 loaded) (ungexp (* 2 total))
  1417. file)
  1418. (save-module-excursion
  1419. (lambda ()
  1420. (primitive-load file)))
  1421. (+ 1 loaded))))
  1422. loaded
  1423. entries)))
  1424. (setvbuf (current-output-port)
  1425. (cond-expand (guile-2.2 'line) (else _IOLBF)))
  1426. (define mkdir-p
  1427. ;; Capture 'mkdir-p'.
  1428. (@ (guix build utils) mkdir-p))
  1429. ;; Add EXTENSIONS to the search path.
  1430. (set! %load-path
  1431. (append (map (lambda (extension)
  1432. (string-append extension
  1433. "/share/guile/site/"
  1434. (effective-version)))
  1435. '((ungexp-native-splicing extensions)))
  1436. %load-path))
  1437. (set! %load-compiled-path
  1438. (append (map (lambda (extension)
  1439. (string-append extension "/lib/guile/"
  1440. (effective-version)
  1441. "/site-ccache"))
  1442. '((ungexp-native-splicing extensions)))
  1443. %load-compiled-path))
  1444. (set! %load-path (cons (ungexp modules) %load-path))
  1445. ;; Above we loaded our own (guix build utils) but now we may need to
  1446. ;; load a compile a different one. Thus, force a reload.
  1447. (let ((utils (string-append (ungexp modules)
  1448. "/guix/build/utils.scm")))
  1449. (when (file-exists? utils)
  1450. (load utils)))
  1451. (mkdir (ungexp output))
  1452. (chdir (ungexp modules))
  1453. (load-from-directory ".")
  1454. (process-directory "." (ungexp output) 0))))
  1455. ;; TODO: Pass MODULES as an environment variable.
  1456. (gexp->derivation name build
  1457. #:system system
  1458. #:guile-for-build guile
  1459. #:local-build? #t
  1460. #:env-vars
  1461. (case deprecation-warnings
  1462. ((#f)
  1463. '(("GUILE_WARN_DEPRECATED" . "no")))
  1464. ((detailed)
  1465. '(("GUILE_WARN_DEPRECATED" . "detailed")))
  1466. (else
  1467. '())))))
  1468. ;;;
  1469. ;;; Convenience procedures.
  1470. ;;;
  1471. (define (default-guile)
  1472. ;; Lazily resolve 'guile-3.0' (not 'guile-final' because this is for
  1473. ;; programs returned by 'program-file' and we don't want to keep references
  1474. ;; to several Guile packages). This module must not refer to (gnu …)
  1475. ;; modules directly, to avoid circular dependencies, hence this hack.
  1476. (module-ref (resolve-interface '(gnu packages guile))
  1477. 'guile-3.0))
  1478. (define* (load-path-expression modules #:optional (path %load-path)
  1479. #:key (extensions '()) system target)
  1480. "Return as a monadic value a gexp that sets '%load-path' and
  1481. '%load-compiled-path' to point to MODULES, a list of module names. MODULES
  1482. are searched for in PATH. Return #f when MODULES and EXTENSIONS are empty."
  1483. (if (and (null? modules) (null? extensions))
  1484. (with-monad %store-monad
  1485. (return #f))
  1486. (mlet %store-monad ((modules (imported-modules modules
  1487. #:module-path path
  1488. #:system system))
  1489. (compiled (compiled-modules modules
  1490. #:extensions extensions
  1491. #:module-path path
  1492. #:system system
  1493. #:target target)))
  1494. (return
  1495. (gexp (eval-when (expand load eval)
  1496. ;; Augment the load paths and delete duplicates. Do that
  1497. ;; without loading (srfi srfi-1) or anything.
  1498. (let ((extensions '((ungexp-splicing extensions)))
  1499. (prepend (lambda (items lst)
  1500. ;; This is O(N²) but N is typically small.
  1501. (let loop ((items items)
  1502. (lst lst))
  1503. (if (null? items)
  1504. lst
  1505. (loop (cdr items)
  1506. (cons (car items)
  1507. (delete (car items) lst))))))))
  1508. (set! %load-path
  1509. (prepend (cons (ungexp modules)
  1510. (map (lambda (extension)
  1511. (string-append extension
  1512. "/share/guile/site/"
  1513. (effective-version)))
  1514. extensions))
  1515. %load-path))
  1516. (set! %load-compiled-path
  1517. (prepend (cons (ungexp compiled)
  1518. (map (lambda (extension)
  1519. (string-append extension
  1520. "/lib/guile/"
  1521. (effective-version)
  1522. "/site-ccache"))
  1523. extensions))
  1524. %load-compiled-path)))))))))
  1525. (define* (gexp->script name exp
  1526. #:key (guile (default-guile))
  1527. (module-path %load-path)
  1528. (system (%current-system))
  1529. (target 'current))
  1530. "Return an executable script NAME that runs EXP using GUILE, with EXP's
  1531. imported modules in its search path. Look up EXP's modules in MODULE-PATH."
  1532. (mlet* %store-monad ((target (if (eq? target 'current)
  1533. (current-target-system)
  1534. (return target)))
  1535. (set-load-path
  1536. (load-path-expression (gexp-modules exp)
  1537. module-path
  1538. #:extensions
  1539. (gexp-extensions exp)
  1540. #:system system
  1541. #:target target)))
  1542. (gexp->derivation name
  1543. (gexp
  1544. (call-with-output-file (ungexp output)
  1545. (lambda (port)
  1546. ;; Note: that makes a long shebang. When the store
  1547. ;; is /gnu/store, that fits within the 128-byte
  1548. ;; limit imposed by Linux, but that may go beyond
  1549. ;; when running tests.
  1550. (format port
  1551. "#!~a/bin/guile --no-auto-compile~%!#~%"
  1552. (ungexp guile))
  1553. (ungexp-splicing
  1554. (if set-load-path
  1555. (gexp ((write '(ungexp set-load-path) port)))
  1556. (gexp ())))
  1557. (write '(ungexp exp) port)
  1558. (chmod port #o555))))
  1559. #:system system
  1560. #:target target
  1561. #:module-path module-path
  1562. ;; These derivations are not worth offloading or
  1563. ;; substituting.
  1564. #:local-build? #t
  1565. #:substitutable? #f)))
  1566. (define* (gexp->file name exp #:key
  1567. (set-load-path? #t)
  1568. (module-path %load-path)
  1569. (splice? #f)
  1570. (system (%current-system))
  1571. (target 'current))
  1572. "Return a derivation that builds a file NAME containing EXP. When SPLICE?
  1573. is true, EXP is considered to be a list of expressions that will be spliced in
  1574. the resulting file.
  1575. When SET-LOAD-PATH? is true, emit code in the resulting file to set
  1576. '%load-path' and '%load-compiled-path' to honor EXP's imported modules.
  1577. Lookup EXP's modules in MODULE-PATH."
  1578. (define modules (gexp-modules exp))
  1579. (define extensions (gexp-extensions exp))
  1580. (mlet* %store-monad
  1581. ((target (if (eq? target 'current)
  1582. (current-target-system)
  1583. (return target)))
  1584. (no-load-path? -> (or (not set-load-path?)
  1585. (and (null? modules)
  1586. (null? extensions))))
  1587. (set-load-path
  1588. (load-path-expression modules module-path
  1589. #:extensions extensions
  1590. #:system system
  1591. #:target target)))
  1592. (if no-load-path?
  1593. (gexp->derivation name
  1594. (gexp
  1595. (call-with-output-file (ungexp output)
  1596. (lambda (port)
  1597. (for-each
  1598. (lambda (exp)
  1599. (write exp port))
  1600. '(ungexp (if splice?
  1601. exp
  1602. (gexp ((ungexp exp)))))))))
  1603. #:local-build? #t
  1604. #:substitutable? #f
  1605. #:system system
  1606. #:target target)
  1607. (gexp->derivation name
  1608. (gexp
  1609. (call-with-output-file (ungexp output)
  1610. (lambda (port)
  1611. (write '(ungexp set-load-path) port)
  1612. (for-each
  1613. (lambda (exp)
  1614. (write exp port))
  1615. '(ungexp (if splice?
  1616. exp
  1617. (gexp ((ungexp exp)))))))))
  1618. #:module-path module-path
  1619. #:local-build? #t
  1620. #:substitutable? #f
  1621. #:system system
  1622. #:target target))))
  1623. (define* (text-file* name #:rest text)
  1624. "Return as a monadic value a derivation that builds a text file containing
  1625. all of TEXT. TEXT may list, in addition to strings, objects of any type that
  1626. can be used in a gexp: packages, derivations, local file objects, etc. The
  1627. resulting store file holds references to all these."
  1628. (define builder
  1629. (gexp (call-with-output-file (ungexp output "out")
  1630. (lambda (port)
  1631. (display (string-append (ungexp-splicing text)) port)))))
  1632. (gexp->derivation name builder
  1633. #:local-build? #t
  1634. #:substitutable? #f))
  1635. (define* (mixed-text-file name #:rest text)
  1636. "Return an object representing store file NAME containing TEXT. TEXT is a
  1637. sequence of strings and file-like objects, as in:
  1638. (mixed-text-file \"profile\"
  1639. \"export PATH=\" coreutils \"/bin:\" grep \"/bin\")
  1640. This is the declarative counterpart of 'text-file*'."
  1641. (define build
  1642. (gexp (call-with-output-file (ungexp output "out")
  1643. (lambda (port)
  1644. (display (string-append (ungexp-splicing text)) port)))))
  1645. (computed-file name build))
  1646. (define (file-union name files)
  1647. "Return a <computed-file> that builds a directory containing all of FILES.
  1648. Each item in FILES must be a two-element list where the first element is the
  1649. file name to use in the new directory, and the second element is a gexp
  1650. denoting the target file. Here's an example:
  1651. (file-union \"etc\"
  1652. `((\"hosts\" ,(plain-file \"hosts\"
  1653. \"127.0.0.1 localhost\"))
  1654. (\"bashrc\" ,(plain-file \"bashrc\"
  1655. \"alias ls='ls --color'\"))
  1656. (\"libvirt/qemu.conf\" ,(plain-file \"qemu.conf\" \"\"))))
  1657. This yields an 'etc' directory containing these two files."
  1658. (computed-file name
  1659. (with-imported-modules '((guix build utils))
  1660. (gexp
  1661. (begin
  1662. (use-modules (guix build utils))
  1663. (mkdir (ungexp output))
  1664. (chdir (ungexp output))
  1665. (ungexp-splicing
  1666. (map (match-lambda
  1667. ((target source)
  1668. (gexp
  1669. (begin
  1670. ;; Stat the source to abort early if it does
  1671. ;; not exist.
  1672. (stat (ungexp source))
  1673. (mkdir-p (dirname (ungexp target)))
  1674. (symlink (ungexp source)
  1675. (ungexp target))))))
  1676. files)))))))
  1677. (define* (directory-union name things
  1678. #:key (copy? #f) (quiet? #f)
  1679. (resolve-collision 'warn-about-collision))
  1680. "Return a directory that is the union of THINGS, where THINGS is a list of
  1681. file-like objects denoting directories. For example:
  1682. (directory-union \"guile+emacs\" (list guile emacs))
  1683. yields a directory that is the union of the 'guile' and 'emacs' packages.
  1684. Call RESOLVE-COLLISION when several files collide, passing it the list of
  1685. colliding files. RESOLVE-COLLISION must return the chosen file or #f, in
  1686. which case the colliding entry is skipped altogether.
  1687. When HARD-LINKS? is true, create hard links instead of symlinks. When QUIET?
  1688. is true, the derivation will not print anything."
  1689. (define symlink
  1690. (if copy?
  1691. (gexp (lambda (old new)
  1692. (if (file-is-directory? old)
  1693. (symlink old new)
  1694. (copy-file old new))))
  1695. (gexp symlink)))
  1696. (define log-port
  1697. (if quiet?
  1698. (gexp (%make-void-port "w"))
  1699. (gexp (current-error-port))))
  1700. (match things
  1701. ((one)
  1702. ;; Only one thing; return it.
  1703. one)
  1704. (_
  1705. (computed-file name
  1706. (with-imported-modules '((guix build union))
  1707. (gexp (begin
  1708. (use-modules (guix build union)
  1709. (srfi srfi-1)) ;for 'first' and 'last'
  1710. (union-build (ungexp output)
  1711. '(ungexp things)
  1712. #:log-port (ungexp log-port)
  1713. #:symlink (ungexp symlink)
  1714. #:resolve-collision
  1715. (ungexp resolve-collision)))))))))
  1716. ;;;
  1717. ;;; Syntactic sugar.
  1718. ;;;
  1719. (eval-when (expand load eval)
  1720. (define* (read-ungexp chr port #:optional native?)
  1721. "Read an 'ungexp' or 'ungexp-splicing' form from PORT. When NATIVE? is
  1722. true, use 'ungexp-native' and 'ungexp-native-splicing' instead."
  1723. (define unquote-symbol
  1724. (match (peek-char port)
  1725. (#\@
  1726. (read-char port)
  1727. (if native?
  1728. 'ungexp-native-splicing
  1729. 'ungexp-splicing))
  1730. (_
  1731. (if native?
  1732. 'ungexp-native
  1733. 'ungexp))))
  1734. (match (read port)
  1735. ((? symbol? symbol)
  1736. (let ((str (symbol->string symbol)))
  1737. (match (string-index-right str #\:)
  1738. (#f
  1739. `(,unquote-symbol ,symbol))
  1740. (colon
  1741. (let ((name (string->symbol (substring str 0 colon)))
  1742. (output (substring str (+ colon 1))))
  1743. `(,unquote-symbol ,name ,output))))))
  1744. (x
  1745. `(,unquote-symbol ,x))))
  1746. (define (read-gexp chr port)
  1747. "Read a 'gexp' form from PORT."
  1748. `(gexp ,(read port)))
  1749. ;; Extend the reader
  1750. (read-hash-extend #\~ read-gexp)
  1751. (read-hash-extend #\$ read-ungexp)
  1752. (read-hash-extend #\+ (cut read-ungexp <> <> #t)))
  1753. ;;; gexp.scm ends here