build: Update Guix build and install.
[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 package -i guile";; esac
13     cat <<EOF
14 Missing dependencies, run
15
16     $pm
17 EOF
18     exit 1
19 fi
20 unset GUILE_AUTO_COMPILE GUILE_LOAD_COMPILED_PATH
21 exec ${GUILE} --no-auto-compile -L $(pwd) -e '(@@ (configure) main)' -s "$0" ${1+"$@"}
22 !#
23
24 ;;; Mes --- Maxwell Equations of Software
25 ;;; Copyright © 2016 Jan Nieuwenhuizen <janneke@gnu.org>
26 ;;;
27 ;;; configure: This file is part of Mes.
28 ;;;
29 ;;; 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.
33 ;;;
34 ;;; 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.
38 ;;;
39 ;;; You should have received a copy of the GNU General Public License
40 ;;; along with Mes.  If not, see <http://www.gnu.org/licenses/>.
41
42
43 (define-module (configure)
44   #:use-module (ice-9 and-let-star)
45   #:use-module (ice-9 curried-definitions)
46   #:use-module (ice-9 getopt-long)
47   #:use-module (ice-9 match)
48   #:use-module (ice-9 optargs)
49   #:use-module (ice-9 popen)
50   #:use-module (ice-9 rdelim))
51
52 (define *shell* "sh")
53 (define PACKAGE "mes")
54 (define VERSION "0.4")
55 (define PREFIX "/usr/local")
56 (define GUILE_EV (effective-version))
57 (define CC (or (getenv "CC") "gcc"))
58 (define CC32 (or (getenv "CC32") "i686-unknown-linux-gnu-gcc"))
59 (define GUILE (or (getenv "guile") "guile"))
60 (define SYSCONFDIR "$(PREFIX)/etc")
61
62 ;;; Utility
63 (define (gulp-pipe command)
64   (let* ((port (open-pipe* OPEN_READ *shell* "-c" command))
65          (output (read-string port)))
66     (close-port port)
67     (string-trim-right output #\newline)))
68
69 (define (logf port string . rest)
70   (apply format (cons* port string rest))
71   (force-output port)
72   #t)
73
74 (define (stderr string . rest)
75   (apply logf (cons* (current-error-port) string rest)))
76
77 (define (stdout string . rest)
78   (apply logf (cons* (current-output-port) string rest)))
79
80 (define* ((->string #:optional (infix "")) h . t)
81   (let ((o (if (pair? t) (cons h t) h)))
82     (match o
83       ((? char?) (make-string 1 o))
84       ((? number?) (number->string o))
85       ((? string?) o)
86       ((? symbol?) (symbol->string o))
87       ((h ... t) (string-join (map (->string) o) ((->string) infix)))
88       (_ ""))))
89
90 (define (tuple< a b)
91   (cond
92    ((and (null? a) (null? b)) #t)
93    ((null? a) (not (null? b)))
94    ((null? b) #f)
95    ((and (not (< (car a) (car b)))
96          (not (< (car b) (car a))))
97     (tuple< (cdr a) (cdr b)))
98    (else (< (car a) (car b)))))
99
100 (define (tuple<= a b)
101   (or (equal? a b) (tuple< a b)))
102
103 ;;; Configure
104 (define (version->string version)
105   ((->string '.) version))
106
107 (define (string->version string)
108   (and-let* ((version (string-tokenize string
109                                        (char-set-adjoin char-set:digit #\.)))
110              ((pair? version))
111              (version (sort version (lambda (a b) (> (string-length a) (string-length b)))))
112              (version (car version))
113              (version (string-tokenize version
114                                        (char-set-complement (char-set #\.)))))
115             (map string->number version)))
116
117 (define required '())
118 (define* (check-version command expected
119                         #:optional
120                         (deb #f)
121                         (version-option '--version)
122                         (compare tuple<=))
123   (stderr "checking for ~a~a..." command
124           (if (null? expected) ""
125               (format #f " [~a]" (version->string expected))))
126   (let* ((actual (gulp-pipe (format #f "~a ~a 2>&1" command version-option)))
127          (actual (string->version actual))
128          (pass? (and actual (compare expected actual))))
129     (stderr "~a ~a\n" (if pass? (if (pair? actual) "" " yes")
130                           (if actual " no, found" "")) (version->string actual))
131     (if (not pass?)
132         (set! required (cons (or deb command) required)))
133     pass?))
134
135 (define* (check-pkg-config package expected #:optional (deb #f))
136   (check-version (format #f "pkg-config --modversion ~a" package) expected deb))
137
138 (define (check-compile-header-c++ header)
139   (and (= 0 (system (format #f "echo '#include \"~a\"' | gcc --language=c++ --std=c++11 -E - > /dev/null 2>&1" header)))
140        'yes))
141
142 (define* (check-header-c++ header deb #:optional (check check-compile-header-c++))
143   (stderr "checking for ~a..." header)
144   (let ((result (check header)))
145     (stderr " ~a\n" (if result result "no"))
146     (if (not result)
147         (set! required (cons deb required)))))
148
149 (define guix?
150   (system "guix --version &>/dev/null"))
151 ;;;
152
153 (define (parse-opts args)
154   (let* ((option-spec
155           '((build (value #t))
156             (help (single-char #\h))
157             (prefix (value #t))
158             (sysconfdir (value #t))
159             ;;ignore
160             (enable-fast-install)))
161          (options (getopt-long args option-spec))
162          (help? (option-ref options 'help #f))
163          (files (option-ref options '() '()))
164          (prefix (option-ref options '() PREFIX))
165          (usage? (and (not help?) #f)))
166     (if (pair? files)
167         (stderr "ignoring files: ~a\n" files))
168     (or (and (or help? usage?)
169              ((or (and usage? stderr) stdout) "\
170 Usage: ./configure [OPTION]...
171   -h, --help           display this help
172   --prefix=DIR         install in PREFIX [~a]
173   --sysconfdir=DIR     read-only single-machine data [PREFIX/etc]
174 " PREFIX)
175              (exit (or (and usage? 2) 0)))
176         options)))
177
178 (define BUILD_TRIPLET (gulp-pipe "gcc -dumpmachine 2>/dev/null"))
179
180 (define (main args)
181   (let* ((options (parse-opts args))
182          (build-triplet (option-ref options 'build BUILD_TRIPLET))
183          (prefix (option-ref options 'prefix PREFIX))
184          (sysconfdir (option-ref options 'sysconfdir SYSCONFDIR)))
185     (check-version 'bash '(4 0))
186     (check-version 'gcc '(4 8))
187     (check-version 'i686-unknown-linux-gnu-gcc '(4 8))
188     (check-version 'guile '(2 0))
189     (check-version 'make '(4 0))
190     (check-version 'perl '(5))
191
192     (when (pair? required)
193           (stderr "\nMissing dependencies, run\n\n")
194           (if guix?
195               (stderr "    guix environment -l guix.scm\n")
196               (stderr "    sudo apt-get install ~a\n" ((->string " ") required)))
197           (exit 1))
198     (with-output-to-file ".config.make"
199       (lambda ()
200         (stdout "CC:=~a\n" CC)
201         (stdout "CC32:=~a\n" CC32)
202         (stdout "GUILE:=~a\n" GUILE)
203         (stdout "GUILE_EV:=~a\n" GUILE_EV)
204         (stdout "GUIX_P:=~a\n" (if guix? guix? ""))
205         (stdout "PACKAGE:=~a\n" PACKAGE)
206         (stdout "VERSION:=~a\n" VERSION)
207         (stdout "PREFIX:=~a\n" (gulp-pipe (string-append "echo " prefix)))
208         (stdout "SYSCONFDIR:=~a\n" sysconfdir)))
209     (stdout "\nRun:
210   make            to build mes
211   make help       for help on other targets\n")))