asdf.scm 14 KB

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