asdf.scm 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. ;;; GNU Guix --- Functional package management for GNU
  2. ;;; Copyright © 2016, 2017 Andy Patterson <ajpatter@uwaterloo.ca>
  3. ;;; Copyright © 2019, 2020 Guillaume Le Vaillant <glv@posteo.net>
  4. ;;;
  5. ;;; This file is part of GNU Guix.
  6. ;;;
  7. ;;; GNU Guix is free software; you can redistribute it and/or modify it
  8. ;;; under the terms of the GNU General Public License as published by
  9. ;;; the Free Software Foundation; either version 3 of the License, or (at
  10. ;;; your option) any later version.
  11. ;;;
  12. ;;; GNU Guix is distributed in the hope that it will be useful, but
  13. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  14. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. ;;; GNU General Public License for more details.
  16. ;;;
  17. ;;; You should have received a copy of the GNU General Public License
  18. ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
  19. (define-module (guix build-system asdf)
  20. #:use-module (guix store)
  21. #:use-module (guix utils)
  22. #:use-module (guix memoization)
  23. #:use-module (guix packages)
  24. #:use-module (guix derivations)
  25. #:use-module (guix search-paths)
  26. #:use-module ((guix build utils)
  27. #:select ((package-name->name+version
  28. . hyphen-separated-name->name+version)))
  29. #:use-module (guix build-system)
  30. #:use-module (guix build-system gnu)
  31. #:use-module (ice-9 match)
  32. #:use-module (ice-9 regex)
  33. #:use-module (srfi srfi-1)
  34. #:use-module (srfi srfi-26)
  35. #:use-module (gnu packages)
  36. #:export (%asdf-build-system-modules
  37. %asdf-build-modules
  38. asdf-build
  39. asdf-build-system/sbcl
  40. asdf-build-system/ecl
  41. asdf-build-system/source
  42. sbcl-package->cl-source-package
  43. sbcl-package->ecl-package))
  44. ;; Commentary:
  45. ;;
  46. ;; Standard build procedure for asdf packages. This is implemented as an
  47. ;; extension of 'gnu-build-system'.
  48. ;;
  49. ;; Code:
  50. (define %asdf-build-system-modules
  51. ;; Imported build-side modules
  52. `((guix build asdf-build-system)
  53. (guix build lisp-utils)
  54. (guix build union)
  55. ,@%gnu-build-system-modules))
  56. (define %asdf-build-modules
  57. ;; Used (visible) build-side modules
  58. '((guix build asdf-build-system)
  59. (guix build utils)
  60. (guix build union)
  61. (guix build lisp-utils)))
  62. (define (default-lisp implementation)
  63. "Return the default package for the lisp IMPLEMENTATION."
  64. ;; Lazily resolve the binding to avoid a circular dependency.
  65. (let ((lisp-module (resolve-interface '(gnu packages lisp))))
  66. (module-ref lisp-module implementation)))
  67. (define* (lower/source name
  68. #:key source inputs outputs native-inputs system target
  69. #:allow-other-keys
  70. #:rest arguments)
  71. "Return a bag for NAME"
  72. (define private-keywords
  73. '(#:target #:inputs #:native-inputs))
  74. (and (not target)
  75. (bag
  76. (name name)
  77. (system system)
  78. (host-inputs `(,@(if source
  79. `(("source" ,source))
  80. '())
  81. ,@inputs
  82. ,@(standard-packages)))
  83. (build-inputs native-inputs)
  84. (outputs outputs)
  85. (build asdf-build/source)
  86. (arguments (strip-keyword-arguments private-keywords arguments)))))
  87. (define* (asdf-build/source store name inputs
  88. #:key source outputs
  89. (phases '(@ (guix build asdf-build-system)
  90. %standard-phases/source))
  91. (search-paths '())
  92. (system (%current-system))
  93. (guile #f)
  94. (imported-modules %asdf-build-system-modules)
  95. (modules %asdf-build-modules))
  96. (define builder
  97. `(begin
  98. (use-modules ,@modules)
  99. (asdf-build/source #:name ,name
  100. #:source ,(match (assoc-ref inputs "source")
  101. (((? derivation? source))
  102. (derivation->output-path source))
  103. ((source) source)
  104. (source source))
  105. #:system ,system
  106. #:phases ,phases
  107. #:outputs %outputs
  108. #:search-paths ',(map search-path-specification->sexp
  109. search-paths)
  110. #:inputs %build-inputs)))
  111. (define guile-for-build
  112. (match guile
  113. ((? package?)
  114. (package-derivation store guile system #:graft? #f))
  115. (#f
  116. (let* ((distro (resolve-interface '(gnu packages commencement)))
  117. (guile (module-ref distro 'guile-final)))
  118. (package-derivation store guile system #:graft? #f)))))
  119. (build-expression->derivation store name builder
  120. #:inputs inputs
  121. #:system system
  122. #:modules imported-modules
  123. #:outputs outputs
  124. #:guile-for-build guile-for-build))
  125. (define* (package-with-build-system from-build-system to-build-system
  126. from-prefix to-prefix
  127. #:key variant-property
  128. phases-transformer)
  129. "Return a precedure which takes a package PKG which uses FROM-BUILD-SYSTEM,
  130. and returns one using TO-BUILD-SYSTEM. If PKG was prefixed by FROM-PREFIX,
  131. the resulting package will be prefixed by TO-PREFIX. Inputs of PKG are
  132. recursively transformed using the same rule. The result's #:phases argument
  133. will be modified by PHASES-TRANSFORMER, an S-expression which evaluates on the
  134. build side to a procedure of one argument.
  135. VARIANT-PROPERTY can be added to a package's properties to indicate that the
  136. corresponding package promise should be used as the result of this
  137. transformation. This allows the result to differ from what the transformation
  138. would otherwise produce.
  139. If TO-BUILD-SYSTEM is asdf-build-system/source, the resulting package will be
  140. set up using CL source package conventions."
  141. (define target-is-source? (eq? asdf-build-system/source to-build-system))
  142. (define (transform-package-name name)
  143. (if (string-prefix? from-prefix name)
  144. (let ((new-name (string-drop name (string-length from-prefix))))
  145. (if (string-prefix? to-prefix new-name)
  146. new-name
  147. (string-append to-prefix new-name)))
  148. name))
  149. (define (has-from-build-system? pkg)
  150. (eq? from-build-system (package-build-system pkg)))
  151. (define (find-input-package pkg)
  152. (let* ((name (package-name pkg))
  153. (new-name (transform-package-name name))
  154. (pkgs (find-packages-by-name new-name)))
  155. (if (null? pkgs) #f (list-ref pkgs 0))))
  156. (define transform
  157. (mlambda (pkg)
  158. (define rewrite
  159. (match-lambda
  160. ((name content . rest)
  161. (let* ((is-package? (package? content))
  162. (new-content (if is-package?
  163. (or (find-input-package content)
  164. (transform content))
  165. content)))
  166. `(,name ,new-content ,@rest)))))
  167. ;; Special considerations for source packages: CL inputs become
  168. ;; propagated, and un-handled arguments are removed.
  169. (define (new-propagated-inputs)
  170. (if target-is-source?
  171. (map rewrite
  172. (append
  173. (filter (match-lambda
  174. ((_ input . _)
  175. (has-from-build-system? input)))
  176. (append (package-inputs pkg)
  177. ;; The native inputs might be needed just
  178. ;; to load the system.
  179. (package-native-inputs pkg)))
  180. (package-propagated-inputs pkg)))
  181. (map rewrite (package-propagated-inputs pkg))))
  182. (define (new-inputs inputs-getter)
  183. (if target-is-source?
  184. (map rewrite
  185. (filter (match-lambda
  186. ((_ input . _)
  187. (not (has-from-build-system? input))))
  188. (inputs-getter pkg)))
  189. (map rewrite (inputs-getter pkg))))
  190. (define base-arguments
  191. (if target-is-source?
  192. (strip-keyword-arguments
  193. '(#:tests? #:asd-files #:lisp #:asd-systems #:test-asd-file)
  194. (package-arguments pkg))
  195. (package-arguments pkg)))
  196. (cond
  197. ((and variant-property
  198. (assoc-ref (package-properties pkg) variant-property))
  199. => force)
  200. ((has-from-build-system? pkg)
  201. (package
  202. (inherit pkg)
  203. (location (package-location pkg))
  204. (name (transform-package-name (package-name pkg)))
  205. (build-system to-build-system)
  206. (arguments
  207. (substitute-keyword-arguments base-arguments
  208. ((#:phases phases) (list phases-transformer phases))))
  209. (inputs (new-inputs package-inputs))
  210. (propagated-inputs (new-propagated-inputs))
  211. (native-inputs (append (if target-is-source?
  212. (list (list (package-name pkg) pkg))
  213. '())
  214. (new-inputs package-native-inputs)))
  215. (outputs (if target-is-source?
  216. '("out")
  217. (package-outputs pkg)))))
  218. (else pkg))))
  219. transform)
  220. (define (strip-variant-as-necessary variant pkg)
  221. (define properties (package-properties pkg))
  222. (if (assoc variant properties)
  223. (package
  224. (inherit pkg)
  225. (properties (alist-delete variant properties)))
  226. pkg))
  227. (define (lower lisp-type)
  228. (lambda* (name
  229. #:key source inputs outputs native-inputs system target
  230. (lisp (default-lisp (string->symbol lisp-type)))
  231. #:allow-other-keys
  232. #:rest arguments)
  233. "Return a bag for NAME"
  234. (define private-keywords
  235. '(#:target #:inputs #:native-inputs #:lisp))
  236. (and (not target)
  237. (bag
  238. (name name)
  239. (system system)
  240. (host-inputs `(,@(if source
  241. `(("source" ,source))
  242. '())
  243. ,@inputs
  244. ,@(standard-packages)))
  245. (build-inputs `((,lisp-type ,lisp)
  246. ,@native-inputs))
  247. (outputs outputs)
  248. (build (asdf-build lisp-type))
  249. (arguments (strip-keyword-arguments private-keywords arguments))))))
  250. (define (asdf-build lisp-type)
  251. (lambda* (store name inputs
  252. #:key source outputs
  253. (tests? #t)
  254. (asd-files ''())
  255. (asd-systems ''())
  256. (test-asd-file #f)
  257. (phases '(@ (guix build asdf-build-system)
  258. %standard-phases))
  259. (search-paths '())
  260. (system (%current-system))
  261. (guile #f)
  262. (imported-modules %asdf-build-system-modules)
  263. (modules %asdf-build-modules))
  264. ;; FIXME: The definition of 'systems' is pretty hacky.
  265. ;; Is there a more elegant way to do it?
  266. (define systems
  267. (if (null? (cadr asd-systems))
  268. `(quote
  269. ,(list
  270. (string-drop
  271. ;; NAME is the value returned from `package-full-name'.
  272. (hyphen-separated-name->name+version name)
  273. (1+ (string-length lisp-type))))) ; drop the "<lisp>-" prefix.
  274. asd-systems))
  275. (define builder
  276. `(begin
  277. (use-modules ,@modules)
  278. (parameterize ((%lisp (string-append
  279. (assoc-ref %build-inputs ,lisp-type)
  280. "/bin/" ,lisp-type))
  281. (%lisp-type ,lisp-type))
  282. (asdf-build #:name ,name
  283. #:source ,(match (assoc-ref inputs "source")
  284. (((? derivation? source))
  285. (derivation->output-path source))
  286. ((source) source)
  287. (source source))
  288. #:asd-files ,asd-files
  289. #:asd-systems ,systems
  290. #:test-asd-file ,test-asd-file
  291. #:system ,system
  292. #:tests? ,tests?
  293. #:phases ,phases
  294. #:outputs %outputs
  295. #:search-paths ',(map search-path-specification->sexp
  296. search-paths)
  297. #:inputs %build-inputs))))
  298. (define guile-for-build
  299. (match guile
  300. ((? package?)
  301. (package-derivation store guile system #:graft? #f))
  302. (#f
  303. (let* ((distro (resolve-interface '(gnu packages commencement)))
  304. (guile (module-ref distro 'guile-final)))
  305. (package-derivation store guile system #:graft? #f)))))
  306. (build-expression->derivation store name builder
  307. #:inputs inputs
  308. #:system system
  309. #:modules imported-modules
  310. #:outputs outputs
  311. #:guile-for-build guile-for-build)))
  312. (define asdf-build-system/sbcl
  313. (build-system
  314. (name 'asdf/sbcl)
  315. (description "The build system for ASDF binary packages using SBCL")
  316. (lower (lower "sbcl"))))
  317. (define asdf-build-system/ecl
  318. (build-system
  319. (name 'asdf/ecl)
  320. (description "The build system for ASDF binary packages using ECL")
  321. (lower (lower "ecl"))))
  322. (define asdf-build-system/source
  323. (build-system
  324. (name 'asdf/source)
  325. (description "The build system for ASDF source packages")
  326. (lower lower/source)))
  327. (define sbcl-package->cl-source-package
  328. (let* ((property 'cl-source-variant)
  329. (transformer
  330. (package-with-build-system asdf-build-system/sbcl
  331. asdf-build-system/source
  332. "sbcl-"
  333. "cl-"
  334. #:variant-property property
  335. #:phases-transformer
  336. '(const %standard-phases/source))))
  337. (lambda (pkg)
  338. (transformer
  339. (strip-variant-as-necessary property pkg)))))
  340. (define sbcl-package->ecl-package
  341. (let* ((property 'ecl-variant)
  342. (transformer
  343. (package-with-build-system asdf-build-system/sbcl
  344. asdf-build-system/ecl
  345. "sbcl-"
  346. "ecl-"
  347. #:variant-property property
  348. #:phases-transformer
  349. 'identity)))
  350. (lambda (pkg)
  351. (transformer
  352. (strip-variant-as-necessary property pkg)))))
  353. ;;; asdf.scm ends here