Add more (ice-9 format) imports.
[jackhill/guix/guix.git] / guix / build-system / ocaml.scm
CommitLineData
e6876cb9 1;;; GNU Guix --- Functional package management for GNU
564cf93f 2;;; Copyright © 2016, 2017, 2018 Julien Lepiller <julien@lepiller.eu>
c6cfec42 3;;; Copyright © 2017 Ben Woodcroft <donttrustben@gmail.com>
e6876cb9
JL
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/>.
e6876cb9
JL
19(define-module (guix build-system ocaml)
20 #:use-module (guix store)
21 #:use-module (guix utils)
22 #:use-module (guix derivations)
23 #:use-module (guix search-paths)
24 #:use-module (guix build-system)
25 #:use-module (guix build-system gnu)
26 #:use-module (guix packages)
27 #:use-module (ice-9 match)
c6cfec42 28 #:use-module (srfi srfi-1)
e6876cb9 29 #:export (%ocaml-build-system-modules
092f8157
JL
30 package-with-ocaml4.07
31 strip-ocaml4.07-variant
6e8986c8
JL
32 default-findlib
33 default-ocaml
34 lower
e6876cb9
JL
35 ocaml-build
36 ocaml-build-system))
37
38;; Commentary:
39;;
40;; Standard build procedure for packages using ocaml. This is implemented as an
41;; extension of `gnu-build-system'.
42;;
43;; OCaml packages don't use a single standard for their build system. Some use
44;; autotools, other use custom configure scripts with Makefiles, others use
45;; oasis to generate the configure script and Makefile and lastly, some use
46;; custom ocaml scripts.
47;;
48;; Each phase in the build system will try to figure out what the build system
49;; is for that package. Most packages come with a custom configure script and
50;; a Makefile that in turn call custom build tools. Packages built with oasis
51;; will have a `setup.ml' file in the top directory, that can be used for all
52;; phases. In that case the Makefile is here only to call that script. In case
53;; the setup.ml do not work as expected, the @var{use-make} argument can be
54;; used to ignore the setup.ml file and run make instead.
55;;
56;; Some packages use their own custom scripts, `pkg/pkg.ml' or
57;; `pkg/build.ml'. They can be used here too.
58;;
59;; Code:
60
61(define %ocaml-build-system-modules
62 ;; Build-side modules imported by default.
63 `((guix build ocaml-build-system)
64 ,@%gnu-build-system-modules))
65
66(define (default-ocaml)
67 "Return the default OCaml package."
68
69 ;; Do not use `@' to avoid introducing circular dependencies.
70 (let ((module (resolve-interface '(gnu packages ocaml))))
71 (module-ref module 'ocaml)))
72
73(define (default-findlib)
74 "Return the default OCaml-findlib package."
75
76 ;; Do not use `@' to avoid introducing circular dependencies.
77 (let ((module (resolve-interface '(gnu packages ocaml))))
78 (module-ref module 'ocaml-findlib)))
79
6e8986c8
JL
80(define (default-dune-build-system)
81 "Return the dune-build-system."
82
83 ;; Do not use `@' to avoid introducing circular dependencies.
84 (let ((module (resolve-interface '(guix build-system dune))))
85 (module-ref module 'dune-build-system)))
86
092f8157 87(define (default-ocaml4.07)
c6cfec42 88 (let ((ocaml (resolve-interface '(gnu packages ocaml))))
092f8157 89 (module-ref ocaml 'ocaml-4.07)))
c6cfec42 90
092f8157 91(define (default-ocaml4.07-findlib)
c6cfec42 92 (let ((module (resolve-interface '(gnu packages ocaml))))
092f8157 93 (module-ref module 'ocaml4.07-findlib)))
c6cfec42 94
1e8da4cd
JL
95(define (default-ocaml4.07-dune)
96 (let ((module (resolve-interface '(gnu packages ocaml))))
97 (module-ref module 'ocaml4.07-dune)))
98
99(define* (package-with-explicit-ocaml ocaml findlib dune old-prefix new-prefix
c6cfec42
BW
100 #:key variant-property)
101 "Return a procedure of one argument, P. The procedure creates a package
102with the same fields as P, which is assumed to use OCAML-BUILD-SYSTEM, such
103that it is compiled with OCAML and FINDLIB instead. The inputs are changed
104recursively accordingly. If the name of P starts with OLD-PREFIX, this is
105replaced by NEW-PREFIX; otherwise, NEW-PREFIX is prepended to the name.
106
1e8da4cd
JL
107When the package uses the DUNE-BUILD-SYSTEM, the procedure creates a package
108with the same fields as P, such that it is compiled with OCAML, FINDLIB and DUNE
109instead.
110
c6cfec42
BW
111When VARIANT-PROPERTY is present, it is used as a key to search for
112pre-defined variants of this transformation recorded in the 'properties' field
113of packages. The property value must be the promise of a package. This is a
114convenient way for package writers to force the transformation to use
115pre-defined variants."
116 (define package-variant
117 (if variant-property
118 (lambda (package)
119 (assq-ref (package-properties package)
120 variant-property))
121 (const #f)))
122
123 (define (transform p)
124 (cond
125 ;; If VARIANT-PROPERTY is present, use that.
126 ((package-variant p)
127 => force)
128
129 ;; Otherwise build the new package object graph.
6e8986c8
JL
130 ((or (eq? (package-build-system p) ocaml-build-system)
131 (eq? (package-build-system p) (default-dune-build-system)))
c6cfec42
BW
132 (package
133 (inherit p)
134 (location (package-location p))
135 (name (let ((name (package-name p)))
136 (string-append new-prefix
137 (if (string-prefix? old-prefix name)
138 (substring name
139 (string-length old-prefix))
140 name))))
141 (arguments
142 (let ((ocaml (if (promise? ocaml) (force ocaml) ocaml))
1e8da4cd
JL
143 (findlib (if (promise? findlib) (force findlib) findlib))
144 (dune (if (promise? dune) (force dune) dune)))
c6cfec42
BW
145 (ensure-keyword-arguments (package-arguments p)
146 `(#:ocaml ,ocaml
1e8da4cd
JL
147 #:findlib ,findlib
148 ,@(if (eq? (package-build-system p)
149 (default-dune-build-system))
150 `(#:dune ,dune)
151 '())))))))
c6cfec42
BW
152 (else p)))
153
154 (define (cut? p)
6e8986c8
JL
155 (or (not (or (eq? (package-build-system p) ocaml-build-system)
156 (eq? (package-build-system p) (default-dune-build-system))))
c6cfec42
BW
157 (package-variant p)))
158
159 (package-mapping transform cut?))
160
092f8157
JL
161(define package-with-ocaml4.07
162 (package-with-explicit-ocaml (delay (default-ocaml4.07))
163 (delay (default-ocaml4.07-findlib))
1e8da4cd 164 (delay (default-ocaml4.07-dune))
092f8157
JL
165 "ocaml-" "ocaml4.07-"
166 #:variant-property 'ocaml4.07-variant))
c6cfec42 167
092f8157
JL
168(define (strip-ocaml4.07-variant p)
169 "Remove the 'ocaml4.07-variant' property from P."
c6cfec42
BW
170 (package
171 (inherit p)
092f8157 172 (properties (alist-delete 'ocaml4.07-variant (package-properties p)))))
c6cfec42 173
e6876cb9
JL
174(define* (lower name
175 #:key source inputs native-inputs outputs system target
176 (ocaml (default-ocaml))
177 (findlib (default-findlib))
178 #:allow-other-keys
179 #:rest arguments)
180 "Return a bag for NAME."
181 (define private-keywords
182 '(#:source #:target #:ocaml #:findlib #:inputs #:native-inputs))
183
184 (and (not target) ;XXX: no cross-compilation
185 (bag
186 (name name)
187 (system system)
188 (host-inputs `(,@(if source
189 `(("source" ,source))
190 '())
191 ,@inputs
192
193 ;; Keep the standard inputs of 'gnu-build-system'.
194 ,@(standard-packages)))
195 (build-inputs `(("ocaml" ,ocaml)
196 ("findlib" ,findlib)
197 ,@native-inputs))
198 (outputs outputs)
199 (build ocaml-build)
200 (arguments (strip-keyword-arguments private-keywords arguments)))))
201
202(define* (ocaml-build store name inputs
203 #:key (guile #f)
204 (outputs '("out")) (configure-flags ''())
205 (search-paths '())
206 (make-flags ''())
207 (build-flags ''())
208 (out-of-source? #t)
209 (use-make? #f)
210 (tests? #t)
211 (test-flags ''("--enable-tests"))
212 (test-target "test")
213 (install-target "install")
214 (validate-runpath? #t)
215 (patch-shebangs? #t)
216 (strip-binaries? #t)
217 (strip-flags ''("--strip-debug"))
218 (strip-directories ''("lib" "lib64" "libexec"
219 "bin" "sbin"))
220 (phases '(@ (guix build ocaml-build-system)
221 %standard-phases))
222 (system (%current-system))
223 (imported-modules %ocaml-build-system-modules)
224 (modules '((guix build ocaml-build-system)
225 (guix build utils))))
226 "Build SOURCE using OCAML, and with INPUTS. This assumes that SOURCE
227provides a 'setup.ml' file as its build system."
228 (define builder
229 `(begin
230 (use-modules ,@modules)
231 (ocaml-build #:source ,(match (assoc-ref inputs "source")
232 (((? derivation? source))
233 (derivation->output-path source))
234 ((source)
235 source)
236 (source
237 source))
238 #:system ,system
239 #:outputs %outputs
240 #:inputs %build-inputs
241 #:search-paths ',(map search-path-specification->sexp
242 search-paths)
243 #:phases ,phases
244 #:configure-flags ,configure-flags
245 #:test-flags ,test-flags
246 #:make-flags ,make-flags
247 #:build-flags ,build-flags
248 #:out-of-source? ,out-of-source?
249 #:use-make? ,use-make?
250 #:tests? ,tests?
251 #:test-target ,test-target
252 #:install-target ,install-target
253 #:validate-runpath? ,validate-runpath?
254 #:patch-shebangs? ,patch-shebangs?
255 #:strip-binaries? ,strip-binaries?
256 #:strip-flags ,strip-flags
257 #:strip-directories ,strip-directories)))
258
259 (define guile-for-build
260 (match guile
261 ((? package?)
262 (package-derivation store guile system #:graft? #f))
263 (#f ; the default
264 (let* ((distro (resolve-interface '(gnu packages commencement)))
265 (guile (module-ref distro 'guile-final)))
266 (package-derivation store guile system #:graft? #f)))))
267
268 (build-expression->derivation store name builder
269 #:system system
270 #:inputs inputs
271 #:modules imported-modules
272 #:outputs outputs
273 #:guile-for-build guile-for-build))
274
275(define ocaml-build-system
276 (build-system
277 (name 'ocaml)
278 (description "The standard OCaml build system")
279 (lower lower)))
280
281;;; ocaml.scm ends here