build: Handle CFLAGS, CPPFLAGS for Debian.
[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-dev
24 EOF
25     exit 1
26 fi
27 exec ${GUILE-guile} -L . --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.16")
62 (define GUILE (or (getenv "guile") "guile"))
63 (define GUILE_EFFECTIVE_VERSION (effective-version))
64
65 (define prefix "/usr/local")
66 (define infodir "${prefix}/share/info")
67 (define mandir "${prefix}/share/man")
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* (PATH-search-path name #:key (default name) warn?)
132   (or (search-path (string-split (getenv "PATH") #\:) name)
133       (and (and warn? (format (current-error-port) "warning: not found: ~a\n" name))
134            default)))
135
136 (define optional '())
137 (define required '())
138 (define* (check-version name expected
139                         #:key
140                         optional?
141                         (deb #f)
142                         (version-option '--version)
143                         (compare tuple<=)
144                         (command name))
145   (stderr "checking for ~a~a..." (basename name)
146           (if (null? expected) ""
147               (format #f " [~a]" (version->string expected))))
148   (let* ((output (gulp-pipe (format #f "~a ~a 2>&1" command version-option)))
149          (actual (string->version output))
150          (pass? (and actual (compare expected actual)))
151          ;(pass? (PATH-search-path command))
152          )
153     (stderr "~a ~a\n" (if pass? (if (pair? actual) "" " yes")
154                           (if actual " no, found" "")) (version->string actual))
155     (or pass?
156         (if (not (pair? name)) (begin (if optional? (set! optional (cons (or deb name) optional))
157                                           (set! required (cons (or deb name) required)))
158                                       pass?)
159             (check-version (cdr name) expected deb version-option compare)))))
160
161 (define* (check-pkg-config package expected #:optional (deb #f))
162   (check-version (format #f "pkg-config --modversion ~a" package) expected deb))
163
164 (define (check-compile-header-c header)
165   (and (= 0 (system (format #f "echo '#include ~s' | gcc -E - > /dev/null 2>&1" header)))
166        'yes))
167
168 (define (check-compile-header-c++ header)
169   (and (= 0 (system (format #f "echo '#include ~s' | gcc --language=c++ --std=c++11 -E - > /dev/null 2>&1" header)))
170        'yes))
171
172 (define* (check-header-c header deb #:optional (check check-compile-header-c))
173   (stderr "checking for ~a..." header)
174   (let ((result (check header)))
175     (stderr " ~a\n" (if result result "no"))
176     (if (not result)
177         (set! required (cons deb required)))))
178
179 (define* (check-header-c++ header deb #:optional (check check-compile-header-c++))
180   (check-header-c header deb check))
181
182 (define guix?
183   (and (zero? (system "guix --version 1>/dev/null 2>/dev/null")) 1))
184 ;;;
185
186 (define (parse-opts args)
187   (let* ((option-spec
188           '((build (value #t))
189             (host (value #t))
190             (help (single-char #\h))
191             (prefix (value #t))
192             (sysconfdir (value #t))
193             (verbose (single-char #\v))
194             (with-courage)
195             (infodir (value #t))
196             (mandir (value #t))
197             (disable-silent-rules)
198
199             (enable-fast-install)       ; Ignored for Guix
200             (includedir (value #t))     ; Ignored for Debian
201             (mandir (value #t))         ; Ignored for Debian
202             (localstatedir (value #t))  ; Ignored for Debian
203             (libdir (value #t))         ; Ignored for Debian
204             (libexecdir (value #t))     ; Ignored for Debian
205             (runstatedir (value #t))    ; Ignored for Debian
206             (disable-maintainer-mode)   ; Ignored for Debian
207             (disable-dependency-tracking) ; Ignored for Debian
208             )))
209
210     (getopt-long args option-spec)))
211
212 (define* (print-help #:optional (port (current-output-port)))
213   (format port "\
214 `configure' configures ~a ~a to adapt to many kinds of systems.
215
216 Usage: ./configure [OPTION]... [VAR=VALUE]
217
218 To assign environment variables (e.g., CC, CFLAGS...), specify them as
219 VAR=VALUE.  See below for descriptions of some of the useful variables.
220
221 Defaults for the options are specified in brackets.
222
223 Options:
224   -h, --help           display this help
225       --build=BUILD    configure for building on BUILD [guessed]
226       --disable-silent-rules
227                        verbose build output [BUILD_DEBUG=1]
228       --host=HOST      cross-compile to build programs to run on HOST [BUILD]
229   -v, --verbose        be verbose
230   --with-courage       assert being courageous to configure for unsupported platform
231
232 Installation directories:
233   --prefix=DIR         install in prefix DIR [~a]
234   --infodir=DIR        info documentation [PREFIX/share/info]
235   --mandir=DIR         man pages [PREFIX/share/man]
236
237 Ignored for Guix:
238   --enable-fast-install
239
240 Ignored for Debian:
241   --disable-dependency-tracking
242   --disable-maintainer-mode
243   --includedir=DIR
244   --libdir=DIR
245   --libexecdir=DIR
246   --localstatedir=DIR
247   --mandir=DIR
248   --runstatedir=DIR
249
250 Some influential environment variables:
251   CC                C compiler command
252   CFLAGS            C compiler flags
253   CC32              x86 C compiler command
254   CC32_CFLAGS       x86 C compiler flags
255   GUILE             guile command
256   GUILE_TOOLS       guile-tools command
257   MES_CFLAGS        MesCC flags
258   MES_SEED          location of mes-seed
259   MESCC_TOOLS_SEED  location of mescc-tools-seed
260   TCC               tcc C compiler command
261   TINYCC_SEED       location of tinycc-seed
262 " PACKAGE VERSION (getenv "prefix")))
263
264 (define (main args)
265   (let* ((CC (or (getenv "CC") "gcc"))
266          (BUILD_TRIPLET %host-type)
267          (ARCH (car (string-split BUILD_TRIPLET #\-)))
268          (options (parse-opts args))
269          (build-triplet (option-ref options 'build BUILD_TRIPLET))
270          (host-triplet (option-ref options 'host BUILD_TRIPLET))
271          (prefix (option-ref options 'prefix prefix))
272          (infodir (option-ref options 'infodir infodir))
273          (sysconfdir (option-ref options 'sysconfdir sysconfdir))
274          (verbose? (option-ref options 'verbose #f))
275          (with-courage? (option-ref options 'with-courage #f))
276          (disable-silent-rules? (option-ref options 'disable-silent-rules #f))
277          (make? #f)
278          (vars (filter (cut string-index <> #\=) (option-ref options '() '())))
279          (help? (option-ref options 'help #f)))
280     (for-each (lambda (v) (apply setenv (string-split v #\=))) vars)
281     (let ((CC32 (or (getenv "CC32")
282                     (if (member ARCH '("i686" "arm")) (string-append BUILD_TRIPLET "-" CC)
283                         "i686-unknown-linux-gnu-gcc")))
284           (HELP2MAN (or (getenv "HELP2MAN") "help2man"))
285           (TCC (or (getenv "TCC") "tcc"))
286           (MAKEINFO (or (getenv "MAKEINFO") "makeinfo"))
287           (GUILE_TOOLS (or (getenv "GUILE_TOOLS") "guile-tools"))
288           (BLOOD_ELF (or (getenv "BLOOD_ELF") "blood-elf"))
289           (HEX2 (or (getenv "HEX2") "hex2"))
290           (M1 (or (getenv "M1") "M1"))
291           (CFLAGS (getenv "CFLAGS"))
292           (CC32_CFLAGS (getenv "CC32_CFLAGS"))
293           (HEX2FLAGS (getenv "HEX2FLAGS"))
294           (M1FLAGS (getenv "M1FLAGS"))
295           (MES_CFLAGS (getenv "MES_CFLAGS"))
296           (MES_SEED (or (getenv "MES_SEED") "../mes-seed"))
297           (MESCC_TOOLS_SEED (or (getenv "MESCC_TOOLS_SEED") "../mescc-tools-seed"))
298           (TINYCC_SEED (or (getenv "TINYCC_SEED") "../tinycc-seed")))
299       (when help?
300         (print-help)
301         (exit 0))
302       (set! *verbose?* verbose?)
303       (check-version "guile" '(2 0))
304       (check-version "guile-tools" '(2 0))
305       (check-version "mes-seed" '(0 16) #:optional? #t #:command (string-append MES_SEED "/refresh.sh"))
306       (check-version "tinycc-seed" '(0 16) #:optional? #t #:command (string-append TINYCC_SEED "/refresh.sh"))
307       (check-version BLOOD_ELF '(0 1))
308       (check-version HEX2 '(0 3))
309       (check-version M1 '(0 3))
310       (check-version "nyacc" '(0 80 41) #:command (string-append GUILE " -c '(use-modules (nyacc lalr)) (display *nyacc-version*)'"))
311
312       (check-version "bash" '(4 0))
313       (when (and (check-version "git" '(2 0) #:optional? #t)
314                  (not (file-exists? ".git")))
315         ;; Debian wants to run `make clean' from a tarball
316         (and (zero? (system* "git" "init"))
317              (zero? (system* "git" "add" "."))
318              (zero? (system* "git" "commit" "-m" "Import mes"))))
319       (when (and (not (member ARCH '("i686" "x86_64"))) (not with-courage?))
320         (stderr "platform not supported: ~a, try --with-courage\n" ARCH)
321         (exit 1))
322       (if (not (check-version CC '(4 8) #:optional? #t))
323           (set! CC #f))
324       (when CC
325         (check-header-c "stdio.h" "libc-dev")
326         (check-header-c "limits.h" "linux-headers"))
327       (if (not (check-version CC32 '(4 8) #:optional? #t))
328           (set! CC32 #f))
329       (if (not (check-version TCC '(0 9 26) #:optional? #t #:version-option "-v"))
330           (set! TCC #f))
331       (set! make? (check-version "make" '(4 0) #:optional? #t))
332       (check-version "perl" '(5))
333       (if (not (check-version "makeinfo" '(6) #:optional? #t))
334           (set! MAKEINFO #f))
335       (if (not (check-version "help2man" '(1 47) #:optional? #t))
336           (set! HELP2MAN #f))
337
338       (when (pair? required)
339         (stderr "\nMissing dependencies [~a], run\n\n" ((->string ", ") required))
340         (if guix?
341             (stderr "    guix environment -l guix.scm\n")
342             (stderr "    sudo apt-get install ~a\n" ((->string " ") required)))
343         (exit 1))
344       (with-output-to-file ".config.make"
345         (lambda ()
346           (stdout "build:=~a\n" build-triplet)
347           (stdout "host:=~a\n" host-triplet)
348           (stdout "srcdir:=.\n")
349           (stdout "prefix:=~a\n" (gulp-pipe (string-append "echo " prefix)))
350           (stdout "infodir:=~a\n" infodir)
351           (stdout "mandir:=~a\n" mandir)
352           (stdout "sysconfdir:=~a\n" sysconfdir)
353
354           (stdout "ARCH:=~a\n" ARCH)
355           (stdout "CC:=~a\n" (or CC ""))
356           (stdout "CC32:=~a\n" (or CC32 ""))
357           (stdout "HELP2MAN:=~a\n" (or HELP2MAN ""))
358           (stdout "TCC:=~a\n" (or TCC ""))
359           (stdout "BLOOD_ELF:=~a\n" (or BLOOD_ELF ""))
360           (stdout "MES_SEED:=~a\n" (or MES_SEED ""))
361           (stdout "MESCC_TOOLS_SEED:=~a\n" (or MESCC_TOOLS_SEED ""))
362           (stdout "TINYCC_SEED:=~a\n" (or TINYCC_SEED ""))
363           (stdout "HEX2:=~a\n" (or HEX2 ""))
364           (stdout "M1:=~a\n" (or M1 ""))
365           (stdout "GUILE:=~a\n" GUILE)
366           (stdout "GUILE_TOOLS:=~a\n" GUILE_TOOLS)
367           (stdout "GUILE_FOR_BUILD:=~a\n" GUILE)
368           (stdout "GUILE_EFFECTIVE_VERSION:=~a\n" GUILE_EFFECTIVE_VERSION)
369           (stdout "GUIX_P:=~a\n" (if guix? guix? ""))
370           (stdout "HEX2:=~a\n" (or HEX2 ""))
371           (stdout "PACKAGE:=~a\n" PACKAGE)
372           (stdout "VERSION:=~a\n" VERSION)
373           (when disable-silent-rules?
374             (stdout "BUILD_DEBUG:=1\n"))
375           (when CFLAGS (stdout "CFLAGS:=~a\n" CFLAGS))
376           (when CC32_CFLAGS (stdout "CC32_CFLAGS:=~a\n" CC32_CFLAGS))
377           (when HEX2FLAGS (stdout "HEX2FLAGS:=~a\n" HEX2FLAGS))
378           (when M1FLAGS (stdout "M1FLAGS:=~a\n" M1FLAGS))
379           (when MES_CFLAGS (stdout "MES_CFLAGS:=~a\n" MES_CFLAGS))))
380       (format (current-output-port)
381               "\nRun:
382   ~a            to build mes
383   ~a help       for help on other targets\n"
384               (if make? "make" "./build.sh")
385               (if make? "make" "./build.sh")))))