Commit | Line | Data |
---|---|---|
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 | |
102 | with the same fields as P, which is assumed to use OCAML-BUILD-SYSTEM, such | |
103 | that it is compiled with OCAML and FINDLIB instead. The inputs are changed | |
104 | recursively accordingly. If the name of P starts with OLD-PREFIX, this is | |
105 | replaced by NEW-PREFIX; otherwise, NEW-PREFIX is prepended to the name. | |
106 | ||
1e8da4cd JL |
107 | When the package uses the DUNE-BUILD-SYSTEM, the procedure creates a package |
108 | with the same fields as P, such that it is compiled with OCAML, FINDLIB and DUNE | |
109 | instead. | |
110 | ||
c6cfec42 BW |
111 | When VARIANT-PROPERTY is present, it is used as a key to search for |
112 | pre-defined variants of this transformation recorded in the 'properties' field | |
113 | of packages. The property value must be the promise of a package. This is a | |
114 | convenient way for package writers to force the transformation to use | |
115 | pre-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 | |
227 | provides 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 |