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