Release 0.10.
[mes.git] / configure
1 #! /bin/sh
2 # -*- scheme -*-
3 unset LANG LC_ALL
4 echo -n "checking for guile..."
5 GUILE=$(type -p ${GUILE-guile} 2>/dev/null|tail -n 1|sed 's,^.* ,,')
6 export GUILE
7 if [ -x "$GUILE" ]; then
8     echo " $GUILE"
9 else
10     pm=$({ guix --help || dpkg --help; }|head -n 1|sed 's,.*Usage: \([^ ]*\).*,\1,g')
11 #-paredit:'})(
12     case "$pm" in dpkg) message="sudo apt-get install guile-2.0";; *) message="guix environment guix.scm";; esac
13     cat <<EOF
14 Missing dependencies, run
15
16     $pm
17 EOF
18     exit 1
19 fi
20 exec ${GUILE} --no-auto-compile -L $(pwd) -C $(pwd) -e 'main' -s "$0" ${1+"$@"}
21 !#
22
23 ;;; Mes --- Maxwell Equations of Software
24 ;;; Copyright © 2016,2017 Jan Nieuwenhuizen <janneke@gnu.org>
25 ;;;
26 ;;; configure: This file is part of Mes.
27 ;;;
28 ;;; Mes is free software; you can redistribute it and/or modify it
29 ;;; under the terms of the GNU General Public License as published by
30 ;;; the Free Software Foundation; either version 3 of the License, or (at
31 ;;; your option) any later version.
32 ;;;
33 ;;; Mes is distributed in the hope that it will be useful, but
34 ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
35 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
36 ;;; GNU General Public License for more details.
37 ;;;
38 ;;; You should have received a copy of the GNU General Public License
39 ;;; along with Mes.  If not, see <http://www.gnu.org/licenses/>.
40
41 (define (main args)
42   ((@@ (configure) main) args))
43
44 (define-module (configure)
45   #:use-module (ice-9 and-let-star)
46   #:use-module (ice-9 curried-definitions)
47   #:use-module (ice-9 getopt-long)
48   #:use-module (ice-9 match)
49   #:use-module (ice-9 optargs)
50   #:use-module (ice-9 popen)
51   #:use-module (ice-9 rdelim))
52
53 (define *shell* "sh")
54 (define PACKAGE "mes")
55 (define VERSION "0.10")
56 (define PREFIX "/usr/local")
57 (define GUILE_EFFECTIVE_VERSION (effective-version))
58 (define GUILE (or (getenv "guile") "guile"))
59 (define SYSCONFDIR "$(PREFIX)/etc")
60
61 ;;; Utility
62 (define (logf port string . rest)
63   (apply format (cons* port string rest))
64   (force-output port)
65   #t)
66
67 (define (stderr string . rest)
68   (apply logf (cons* (current-error-port) string rest)))
69
70 (define (stdout string . rest)
71   (apply logf (cons* (current-output-port) string rest)))
72
73 (define *verbose?* #f)
74
75 (define (verbose string . rest)
76   (if *verbose?* (apply stderr (cons string rest))))
77
78 (define (gulp-pipe command)
79   (let* ((port (open-pipe* OPEN_READ *shell* "-c" command))
80          (output (read-string port))
81          (status (close-pipe port)))
82     (verbose "command[~a]: ~s => ~a\n" status command output)
83     (if (not (zero? status)) "" (string-trim-right output #\newline))))
84
85 (define* ((->string #:optional (infix "")) h . t)
86   (let ((o (if (pair? t) (cons h t) h)))
87     (match o
88       ((? char?) (make-string 1 o))
89       ((? number?) (number->string o))
90       ((? string?) o)
91       ((? symbol?) (symbol->string o))
92       ((h ... t) (string-join (map (->string) o) ((->string) infix)))
93       (_ ""))))
94
95 (define (tuple< a b)
96   (cond
97    ((and (null? a) (null? b)) #t)
98    ((null? a) (not (null? b)))
99    ((null? b) #f)
100    ((and (not (< (car a) (car b)))
101          (not (< (car b) (car a))))
102     (tuple< (cdr a) (cdr b)))
103    (else (< (car a) (car b)))))
104
105 (define (tuple<= a b)
106   (or (equal? a b) (tuple< a b)))
107
108 ;;; Configure
109 (define (version->string version)
110   ((->string '.) version))
111
112 (define (string->version string)
113   (and-let* ((version (string-tokenize string
114                                        (char-set-adjoin char-set:digit #\.)))
115              ((pair? version))
116              (version (sort version (lambda (a b) (> (string-length a) (string-length b)))))
117              (version (car version))
118              (version (string-tokenize version
119                                        (char-set-complement (char-set #\.)))))
120             (map string->number version)))
121
122 (define optional '())
123 (define required '())
124 (define* (check-version name expected
125                         #:key
126                         optional?
127                         (deb #f)
128                         (version-option '--version)
129                         (compare tuple<=)
130                         (command name))
131   (stderr "checking for ~a~a..." name
132           (if (null? expected) ""
133               (format #f " [~a]" (version->string expected))))
134   (let* ((output (gulp-pipe (format #f "~a ~a 2>&1" command version-option)))
135          (actual (string->version output))
136          (pass? (and actual (compare expected actual))))
137     (stderr "~a ~a\n" (if pass? (if (pair? actual) "" " yes")
138                           (if actual " no, found" "")) (version->string actual))
139     (or pass?
140         (if (not (pair? name)) (begin (if optional? (set! optional (cons (or deb name) optional))
141                                           (set! required (cons (or deb name) required)))
142                                       pass?)
143             (check-version (cdr name) expected deb version-option compare)))))
144
145 (define* (check-pkg-config package expected #:optional (deb #f))
146   (check-version (format #f "pkg-config --modversion ~a" package) expected deb))
147
148 (define (check-compile-header-c header)
149   (and (= 0 (system (format #f "echo '#include ~s' | gcc -E - > /dev/null 2>&1" header)))
150        'yes))
151
152 (define (check-compile-header-c++ header)
153   (and (= 0 (system (format #f "echo '#include ~s' | gcc --language=c++ --std=c++11 -E - > /dev/null 2>&1" header)))
154        'yes))
155
156 (define* (check-header-c header deb #:optional (check check-compile-header-c))
157   (stderr "checking for ~a..." header)
158   (let ((result (check header)))
159     (stderr " ~a\n" (if result result "no"))
160     (if (not result)
161         (set! required (cons deb required)))))
162
163 (define* (check-header-c++ header deb #:optional (check check-compile-header-c++))
164   (check-header-c header deb check))
165
166 (define guix?
167   (and (zero? (system "guix --version 1>/dev/null 2>/dev/null")) 1))
168 ;;;
169
170 (define CC (or (getenv "CC") "gcc"))
171 (define BUILD_TRIPLET %host-type)
172 (define ARCH (car (string-split BUILD_TRIPLET #\-)))
173 (define CC32 (or (getenv "CC32")
174                  (if (member ARCH '("i686" "arm")) (string-append BUILD_TRIPLET "-" CC)
175                      "i686-unknown-linux-gnu-gcc")))
176 (define HEX2 (or (getenv "HEX2") "hex2"))
177 (define M1 (or (getenv "M1") "M1"))
178
179 (define (parse-opts args)
180   (let* ((option-spec
181           '((build (value #t))
182             (host (value #t))
183             (help (single-char #\h))
184             (prefix (value #t))
185             (sysconfdir (value #t))
186             (verbose (single-char #\v))
187             (with-courage)
188             ;;ignore
189             (enable-fast-install)))
190          (options (getopt-long args option-spec))
191          (help? (option-ref options 'help #f))
192          (files (option-ref options '() '()))
193          (prefix (option-ref options '() PREFIX))
194          (usage? (and (not help?) #f)))
195     (if (pair? files)
196         (stderr "ignoring files: ~a\n" files))
197     (or (and (or help? usage?)
198              ((or (and usage? stderr) stdout) "\
199 Usage: ./configure [OPTION]...
200   -h, --help           display this help
201       --build=BUILD    configure for building on BUILD [guessed]
202       --host=HOST      cross-compile to build programs to run on HOST [BUILD]
203   --prefix=DIR         install in PREFIX [~a]
204   --sysconfdir=DIR     read-only single-machine data [PREFIX/etc]
205   -v, --verbose        be verbose
206   --with-courage       assert being courageous to configure for unsupported platform
207 " PREFIX)
208              (exit (or (and usage? 2) 0)))
209         options)))
210
211 (define (main args)
212   (let* ((options (parse-opts args))
213          (build-triplet (option-ref options 'build BUILD_TRIPLET))
214          (host-triplet (option-ref options 'host BUILD_TRIPLET))
215          (prefix (option-ref options 'prefix PREFIX))
216          (sysconfdir (option-ref options 'sysconfdir SYSCONFDIR))
217          (verbose? (option-ref options 'verbose #f))
218          (with-courage? (option-ref options 'with-courage #f))
219          (make? #f))
220     (set! *verbose?* verbose?)
221     (check-version 'guile '(2 0))
222     (check-version HEX2 '(0 1))
223     (check-version M1 '(0 2))
224     (check-version 'nyacc '(0 80 3) #:command (string-append GUILE " -c '(use-modules (nyacc lalr)) (display *nyacc-version*)'"))
225
226     (check-version 'bash '(4 0))
227     (when (and (not (member ARCH '("i686" "x86_64"))) (not with-courage?))
228           (stderr "platform not supported: ~a, try --with-courage\n" ARCH)
229           (exit 1))
230     (if (not (check-version CC '(4 8) #:optional? #t))
231         (set! CC #f))
232     (when CC
233       (check-header-c "stdio.h" "libc-dev")
234       (check-header-c "limits.h" "linux-headers"))
235     (if (not (check-version CC32 '(4 8) #:optional? #t))
236         (set! CC32 #f))
237     (set! make? (check-version 'make '(4 0) #:optional? #t))
238     (check-version 'perl '(5))
239
240     (when (pair? required)
241       (stderr "\nMissing dependencies [~a], run\n\n" ((->string ", ") required))
242       (if guix?
243           (stderr "    guix environment -l guix.scm\n")
244           (stderr "    sudo apt-get install ~a\n" ((->string " ") required)))
245       (exit 1))
246     (with-output-to-file ".config.make"
247       (lambda ()
248         (stdout "build:=~a\n" build-triplet)
249         (stdout "host:=~a\n" host-triplet)
250         (stdout "srcdir:=.\n")
251         (stdout "ARCH:=~a\n" ARCH)
252         (stdout "CC:=~a\n" (or CC ""))
253         (stdout "CC32:=~a\n" (or CC32 ""))
254         (stdout "HEX2:=~a\n" (or HEX2 ""))
255         (stdout "M1:=~a\n" (or M1 ""))
256         (stdout "GUILE:=~a\n" GUILE)
257         (stdout "GUILE_FOR_BUILD:=~a\n" GUILE)
258         (stdout "GUILE_EFFECTIVE_VERSION:=~a\n" GUILE_EFFECTIVE_VERSION)
259         (stdout "GUIX_P:=~a\n" (if guix? guix? ""))
260         (stdout "HEX2:=~a\n" (or HEX2 ""))
261         (stdout "PACKAGE:=~a\n" PACKAGE)
262         (stdout "VERSION:=~a\n" VERSION)
263         (stdout "PREFIX:=~a\n" (gulp-pipe (string-append "echo " prefix)))
264         (stdout "SYSCONFDIR:=~a\n" sysconfdir)))
265     (format (current-output-port)
266             "\nRun:
267   ~a            to build mes
268   ~a help       for help on other targets\n"
269             (if make? "make" "./make.scm")
270             (if make? "make" "./make.scm"))))