asdf.scm 14 KB

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