4 guile=$(command -v ${GUILE-guile})
5 guix=$(command -v ${GUIX-guix})
6 if [ -n "$guix" ] ; then
7 install="guix environment -l .guix.scm"
9 install="sudo apt-get install guile-2.2-dev"
11 if [ -z "$guile" ]; then
14 Missing dependencies: ${GUILE-guile}, please install Guile 2.2 or later; run
21 exec ${guile} -L . --no-auto-compile -e '(configure)' -s "$0" ${1+"$@"}
24 ;;; GNU Mes --- Maxwell Equations of Software
25 ;;; Copyright © 2016,2017,2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
27 ;;; configure: This file is part of GNU Mes.
29 ;;; GNU Mes is free software; you can redistribute it and/or modify it
30 ;;; under the terms of the GNU General Public License as published by
31 ;;; the Free Software Foundation; either version 3 of the License, or (at
32 ;;; your option) any later version.
34 ;;; GNU Mes is distributed in the hope that it will be useful, but
35 ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
36 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
37 ;;; GNU General Public License for more details.
39 ;;; You should have received a copy of the GNU General Public License
40 ;;; along with GNU Mes. If not, see <http://www.gnu.org/licenses/>.
42 (define-module (configure)
43 #:use-module (srfi srfi-1)
44 #:use-module (srfi srfi-9)
45 #:use-module (srfi srfi-9 gnu)
46 #:use-module (srfi srfi-26)
47 #:use-module (ice-9 and-let-star)
48 #:use-module (ice-9 curried-definitions)
49 #:use-module (ice-9 getopt-long)
50 #:use-module (ice-9 match)
51 #:use-module (ice-9 optargs)
52 #:use-module (ice-9 popen)
53 #:use-module (ice-9 rdelim)
54 #:use-module (ice-9 regex)
57 (define* (PATH-search-path name #:key (default name) warn?)
58 (or (search-path (string-split (getenv "PATH") #\:) name)
59 (and (and warn? (format (current-error-port) "warning: not found: ~a\n" name))
63 (define PACKAGE "mes")
64 (define VERSION "0.17.1")
67 (define (logf port string . rest)
68 (apply format (cons* port string rest))
72 (define (stderr string . rest)
73 (apply logf (cons* (current-error-port) string rest)))
75 (define (stdout string . rest)
76 (apply logf (cons* (current-output-port) string rest)))
80 (define (verbose string . rest)
81 (if %verbose? (apply stderr (cons string rest))))
83 (define (gulp-pipe command)
84 (let* ((port (open-pipe* OPEN_READ *shell* "-c" command))
85 (output (read-string port))
86 (status (close-pipe port)))
87 (verbose "command[~a]: ~s => ~a\n" status command output)
88 (if (not (zero? status)) "" (string-trim-right output #\newline))))
90 (define* ((->string #:optional (infix "")) h . t)
91 (let ((o (if (pair? t) (cons h t) h)))
93 ((? char?) (make-string 1 o))
94 ((? number?) (number->string o))
96 ((? symbol?) (symbol->string o))
97 ((h ... t) (string-join (map (->string) o) ((->string) infix)))
102 ((and (null? a) (null? b)) #t)
103 ((null? a) (not (null? b)))
105 ((and (not (< (car a) (car b)))
106 (not (< (car b) (car a))))
107 (tuple< (cdr a) (cdr b)))
108 (else (< (car a) (car b)))))
110 (define (tuple<= a b)
111 (or (equal? a b) (tuple< a b)))
113 (define (conjoin . predicates)
114 (lambda (. arguments)
115 (every (cut apply <> arguments) predicates)))
117 (define (char->char from to char)
118 (if (eq? char from) to char))
120 (define (string-replace-char string from to)
121 (string-map (cut char->char from to <>) string))
125 (define-immutable-record-type <dependency>
126 (make-depedency name version-expected optional? version-option commands file-name)
128 (name dependency-name)
129 (version-expected dependency-version-expected)
130 (version-option dependency-version-option)
131 (optional? dependency-optional?)
132 (commands dependency-commands)
133 (file-name dependency-file-name)
134 (version-found dependency-version-found))
136 (define* (make-dep name #:optional (version '(0))
137 #:key optional? (version-option "--version") (commands (list name)) file-name)
138 (let* ((env-var (getenv (name->shell-name name)))
139 (commands (if env-var (cons env-var commands) commands)))
140 (make-depedency name version optional? version-option commands file-name)))
142 (define (find-dep name deps)
143 (find (compose (cut equal? <> name) dependency-name) deps))
145 (define (file-name name deps)
146 (and=> (find-dep name deps) dependency-file-name))
148 (define (variable-name dependency)
150 (dependency-name dependency)
153 (define (name->shell-name name)
154 (string-upcase (string-replace-char name #\- #\_)))
156 (define (version->string version)
157 ((->string '.) version))
159 (define (string->version string)
160 (and-let* ((version (string-tokenize string
161 (char-set-adjoin char-set:digit #\.)))
163 (version (sort version (lambda (a b) (> (string-length a) (string-length b)))))
164 (version (car version))
165 (version (string-tokenize version
166 (char-set-complement (char-set #\.)))))
167 (map string->number version)))
169 (define (check-program-version dependency)
170 (let ((name (dependency-name dependency))
171 (expected (dependency-version-expected dependency))
172 (version-option (dependency-version-option dependency))
173 (commands (dependency-commands dependency)))
174 (let loop ((commands commands))
175 (if (null? commands) dependency
176 (let ((command (car commands)))
177 (stdout "checking for ~a~a... " command
178 (if (null? expected) ""
179 (format #f " [~a]" (version->string expected))))
180 (let* ((output (gulp-pipe (format #f "~a ~a 2>&1" command version-option)))
181 (actual (string->version output))
182 (pass? (and actual (tuple< expected actual)))
183 (dependency (set-field dependency (dependency-version-found) actual)))
184 (stdout "~a ~a\n" (if pass? (if (pair? actual) "" " yes")
185 (if actual " no, found" "no")) (version->string actual))
186 (if pass? (let ((file-name (or (PATH-search-path command)
187 (dependency-file-name dependency))))
188 (set-field dependency (dependency-file-name) file-name))
189 (loop (cdr commands)))))))))
191 (define (check-file dependency)
192 (stdout "checking for ~a... " (dependency-name dependency))
193 (let ((file-name (and (file-exists? (dependency-file-name dependency))
194 (dependency-file-name dependency))))
195 (stdout "~a\n" (or file-name ""))
196 (set-field dependency (dependency-file-name) file-name)))
198 (define* (check-header-c dependency #:optional (check check-compile-header-c))
199 (let ((name (dependency-name dependency)))
200 (stderr "checking for ~a..." name)
201 (let ((result (check name)))
202 (stderr " ~a\n" (if result "yes" "no"))
203 (if result (set-field dependency (dependency-file-name) name)
204 dependency-file-name))))
206 (define (check-compile-header-c header)
207 (zero? (system (format #f "echo '#include ~s' | gcc -E - > /dev/null 2>&1" header))))
209 (define (parse-opts args)
213 (help (single-char #\h))
220 (sysconfdir (value #t))
221 (verbose (single-char #\v))
226 (disable-silent-rules)
227 (enable-silent-rules)
229 (enable-fast-install) ; Ignored for Guix
230 (includedir (value #t)) ; Ignored for Debian
231 (mandir (value #t)) ; Ignored for Debian
232 (localstatedir (value #t)) ; Ignored for Debian
233 (libdir (value #t)) ; Ignored for Debian
234 (libexecdir (value #t)) ; Ignored for Debian
235 (runstatedir (value #t)) ; Ignored for Debian
236 (disable-maintainer-mode) ; Ignored for Debian
237 (disable-dependency-tracking) ; Ignored for Debian
240 (getopt-long args option-spec)))
242 (define* (print-help #:optional (port (current-output-port)))
244 `configure' configures ~a ~a to adapt to many kinds of systems.
246 Usage: ./configure [OPTION]... [VAR=VALUE]
248 To assign environment variables (e.g., CC, CFLAGS...), specify them as
249 VAR=VALUE. See below for descriptions of some of the useful variables.
251 Defaults for the options are specified in brackets.
254 -h, --help display this help
255 --build=BUILD configure for building on BUILD [guessed]
256 --disable-silent-rules
257 verbose build output [BUILD_DEBUG=1]
258 --host=HOST cross-compile to build programs to run on HOST [BUILD]
259 -v, --verbose be verbose
260 --with-courage assert being courageous to configure for unsupported platform
261 --with-cheating cheat using Guile instead of Mes
263 Installation directories:
264 --prefix=DIR install in prefix DIR [~a]
265 --infodir=DIR info documentation [PREFIX/share/info]
266 --mandir=DIR man pages [PREFIX/share/man]
269 --enable-fast-install
272 --disable-dependency-tracking
273 --disable-maintainer-mode
280 Some influential environment variables:
281 CC C compiler command
282 CFLAGS C compiler flags
283 CC32 x86 C compiler command
284 CC64_CFLAGS x86_64 C compiler flags
285 CC64 x86_64 C compiler command
286 CC32_CFLAGS x86 C compiler flags
288 GUILE_TOOLS guile-tools command
289 MES_CFLAGS MesCC flags
290 MES_SEED location of mes-seed
291 MESCC_TOOLS_SEED location of mescc-tools-seed
292 TCC tcc C compiler command
293 TINYCC_PREFIX location of tinycc [for tests/test2]
294 TINYCC_SEED location of tinycc-seed
295 " PACKAGE VERSION (getenv "prefix")))
298 (let* ((options (parse-opts args))
299 (build-type (option-ref options 'build %host-type))
301 (arch (car (string-split build-type #\-)))
302 (host-type (option-ref options 'host %host-type))(prefix "/usr/local")
304 (prefix "/usr/local")
305 (prefix (option-ref options 'prefix prefix))
306 (infodir (option-ref options 'infodir "${prefix}/share/info"))
307 (mandir (option-ref options 'infodir "${prefix}/share/man"))
308 (sysconfdir (option-ref options 'sysconfdir "${prefix}/etc"))
310 (bindir (option-ref options 'bindir "${prefix}/bin"))
311 (datadir (option-ref options 'datadir "${prefix}/share"))
312 (docdir (option-ref options 'docdir "${datadir}/doc/mes-${VERSION}"))
313 (libdir (option-ref options 'libdir "${prefix}/lib"))
314 (moduledir "${datadir}/mes/module")
315 (moduledir/ (gulp-pipe (string-append "echo " prefix "/share/mes/module/")))
316 (guile-effective-version (effective-version))
317 (guile-site-dir (if (equal? prefix ".") (canonicalize-path ".")
318 (string-append "${prefix}/share/guile/site/" guile-effective-version)))
319 (guile-site-ccache-dir (if (equal? prefix ".") (canonicalize-path ".")
320 (string-append "${prefix}/lib/guile/" guile-effective-version "/site-ccache")))
322 (srcdir (dirname (car (command-line))))
323 (srcdest (if (equal? srcdir ".") ""
324 (string-append srcdir "/")))
325 (abs-top-srcdir (canonicalize-path srcdir))
326 (abs-top-builddir (canonicalize-path (getcwd)))
327 (top-builddir (if (equal? srcdir ".") "."
330 (with-cheating? (option-ref options 'with-cheating #f))
331 (with-courage? (option-ref options 'with-courage #f))
332 (disable-silent-rules? (option-ref options 'disable-silent-rules #f))
333 (enable-silent-rules? (option-ref options 'enable-silent-rules #f))
334 (vars (filter (cut string-index <> #\=) (option-ref options '() '())))
335 (help? (option-ref options 'help #f)))
339 (set! %verbose? (option-ref options 'verbose #f))
341 (stderr "configure args=~s\n" args))
342 (for-each (lambda (v) (apply setenv (string-split v #\=))) vars)
343 (let* ((mes-seed (or (getenv "MES_SEED")
344 (string-append srcdest "../mes-seed")))
345 (tinycc-prefix (or (getenv "TINYCC_PREFIX")
346 (string-append srcdest "../tinycc-prefix")))
347 (tinycc-seed (or (getenv "TINYCC_SEED")
348 (string-append srcdest "../tinycc-seed")))
349 (mescc-tools-seed (or (getenv "MESCC_TOOLS_SEED")
350 (string-append srcdest "../mescc-tools-seed")))
351 (deps (fold (lambda (program results)
352 (cons (check-program-version program) results))
354 (list (make-dep "guile" '(2 0) #:commands '("guile-2.2" "guile-2.0" "guile-2" "guile"))
355 (make-dep "guix" '(0 13) #:optional? #t)
356 (make-dep "bash" '(2 0) #:optional? #t)
357 (make-dep "guile-tools" '(2 0))
358 (make-dep "mes-seed" '(0 17 1) #:optional? #t
359 #:commands (list (string-append mes-seed "/refresh.sh"))
360 #:file-name mes-seed)
361 (make-dep "tinycc-seed" '(0 17 1) #:optional? #t
362 #:commands (list (string-append tinycc-seed "/refresh.sh"))
363 #:file-name tinycc-seed)
364 (make-dep "cc" '(2 95) #:commands '("gcc"))
365 (make-dep "make" '(4))
366 (make-dep "cc32" '(2 95)
368 #:commands '("i686-unknown-linux-gnu-gcc"))
369 (make-dep "cc64" '(2 95)
372 (make-dep "M1" '(0 3))
373 (make-dep "blood-elf" '(0 1))
374 (make-dep "hex2" '(0 3))
375 (make-dep "tcc" '(0 9 26) #:optional? #t #:version-option "-v")
376 (make-dep "makeinfo" '(5) #:optional? #t)
377 (make-dep "dot" '(2) #:version-option "-V")
378 (make-dep "help2man" '(1 47) #:optional? #t)
379 (make-dep "perl" '(5) #:optional? #t)
380 (make-dep "git" '(2) #:optional? #t))))
381 (deps (cons (check-program-version (make-dep "nyacc" '(0 80 41) #:commands (list (string-append (file-name "guile" deps) " -c '(use-modules (nyacc lalr)) (display *nyacc-version*)'")) #:file-name #t))
383 (deps (if (file-name "cc" deps)
384 (cons* (check-header-c (make-dep "stdio.h"))
385 (check-header-c (make-dep "limits.h"))
388 (deps (cons (check-file (make-dep "mescc-tools-seed" '(0) #:optional? #t
389 #:file-name mescc-tools-seed))
391 (deps (cons (check-file (make-dep "tinycc-prefix" '(0) #:optional? #t
392 #:file-name tinycc-prefix))
394 (missing (filter (conjoin (negate dependency-file-name)
395 (negate dependency-optional?)) deps)))
397 (define* (substitute file-name pairs
398 #:key (target (if (string-suffix? ".in" file-name)
399 (string-drop-right file-name 3) file-name)))
400 (system* "mkdir" "-p" (dirname target))
401 (with-output-to-file target
404 (fold (lambda (o result)
405 (regexp-substitute/global #f (car o) result 'pre (cdr o) 'post))
406 (with-input-from-file file-name read-string) pairs)))))
408 (when (and (not (member arch '("i686" "x86_64"))) (not with-courage?))
409 (stderr "platform not supported: ~a, try --with-courage\n" arch)
411 (when (pair? missing)
412 (stderr "\nMissing dependencies: ~a\n" (string-join (map dependency-name missing)))
414 (let ((git (find-dep "git" deps)))
416 (not (file-exists? ".git")))
417 ;; Debian wants to run `make clean' from a tarball
418 (and (zero? (system* "git" "init"))
419 (zero? (system* "git" "add" "."))
420 (zero? (system* "git" "commit" "--allow-empty" "-m" "Import mes")))))
421 (with-output-to-file ".config.make"
423 (stdout "PACKAGE:=~a\n" PACKAGE)
424 (stdout "VERSION:=~a\n" VERSION)
426 (stdout "ARCH:=~a\n" arch)
427 (stdout "build:=~a\n" build-type)
428 (stdout "host:=~a\n" host-type)
430 (stdout "top_builddir:=~a\n" top-builddir)
431 (stdout "abs_top_builddir:=~a\n" abs-top-builddir)
432 (stdout "abs_top_srcdir:=~a\n" abs-top-srcdir)
434 (stdout "srcdest:=~a\n" srcdest)
435 (stdout "srcdir:=~a\n" srcdir)
437 (stdout "prefix:=~a\n" (gulp-pipe (string-append "echo " prefix)))
438 (stdout "datadir:=~a\n" datadir)
439 (stdout "docdir:=~a\n" docdir)
441 (stdout "bindir:=~a\n" bindir)
442 (stdout "guile_site_ccache_dir:=~a\n" guile-site-ccache-dir)
443 (stdout "guile_site_dir:=~a\n" guile-site-dir)
444 (stdout "infodir:=~a\n" infodir)
445 (stdout "libdir:=~a\n" libdir)
446 (stdout "mandir:=~a\n" mandir)
447 (stdout "moduledir:=~a\n" moduledir)
448 (stdout "sysconfdir:=~a\n" sysconfdir)
450 (for-each (lambda (o)
451 (stdout "~a:=~a\n" (variable-name o) (or (dependency-file-name o) "")))
453 (stdout "GUILE_EFFECTIVE_VERSION:=~a\n" (effective-version))
455 (when disable-silent-rules?
459 (stdout "MES:=guile\n"))
461 (for-each (lambda (o)
462 (stdout "~a:=~a\n" o (or (getenv o) "")))
472 (let ((pairs `(("@srcdest@" . ,srcdest)
473 ("@srcdir@" . ,srcdir)
474 ("@abs_top_srcdir@" . ,abs-top-srcdir)
475 ("@abs_top_builddir@" . ,abs-top-builddir)
476 ("@top_builddir@" . ,top-builddir)
477 ("@BASH@" . ,(file-name "bash" deps))
478 ("@GUILE@" . ,(file-name "guile" deps))
479 ("@MES@" . ,(file-name "guile" deps))
480 ("@prefix@" . ,prefix)
481 ("@guile_site_dir@" . ,guile-site-dir)
482 ("@guile_site_ccache_dir@" . ,guile-site-ccache-dir)
483 ("@VERSION@" . ,VERSION)
484 ("mes/module/" . ,(string-append moduledir/)))))
485 (for-each (lambda (o)
486 (let* ((src (string-append srcdest o))
487 (target (string-drop-right o 3))
488 (target (if (not (string-prefix? "build-aux/" target)) target
489 (string-drop target (string-length "build-aux/")))))
490 (substitute src pairs #:target target)))
492 "build-aux/GNUmakefile.in"
493 "build-aux/build.sh.in"
494 "build-aux/check.sh.in"
495 "build-aux/install.sh.in"
496 "build-aux/pre-inst-env.in"
497 "build-aux/uninstall.sh.in"
498 "mes/module/mes/boot-0.scm.in"
501 (chmod "build.sh" #o755)
502 (chmod "check.sh" #o755)
503 (chmod "install.sh" #o755)
504 (chmod "pre-inst-env" #o755)
505 (chmod "uninstall.sh" #o755)
506 (chmod "scripts/mescc" #o755)
507 (let ((make (and=> (file-name "make" deps) basename)))
508 (format (current-output-port)
511 ~a help for help on other targets\n"
512 (or make "./build.sh")
513 (or make "./build.sh"))))))