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