#! /bin/sh # -*- scheme -*- unset LANG LC_ALL echo -n "checking for guile..." GUILE=$(command -v ${GUILE-guile}) GUIX=$(command -v ${GUIX-guix}) export GUILE GUIX if [ -x "$GUILE" ]; then echo " $GUILE" elif [ -x "$GUIX" ]; then cat < ;;; ;;; configure: This file is part of Mes. ;;; ;;; Mes is free software; you can redistribute it and/or modify it ;;; under the terms of the GNU General Public License as published by ;;; the Free Software Foundation; either version 3 of the License, or (at ;;; your option) any later version. ;;; ;;; Mes is distributed in the hope that it will be useful, but ;;; WITHOUT ANY WARRANTY; without even the implied warranty of ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;;; GNU General Public License for more details. ;;; ;;; You should have received a copy of the GNU General Public License ;;; along with Mes. If not, see . (define-module (configure) #:use-module (srfi srfi-1) #:use-module (srfi srfi-26) #:use-module (ice-9 and-let-star) #:use-module (ice-9 curried-definitions) #:use-module (ice-9 getopt-long) #:use-module (ice-9 match) #:use-module (ice-9 optargs) #:use-module (ice-9 popen) #:use-module (ice-9 rdelim) #:use-module (ice-9 regex) #:export (main)) (define* (PATH-search-path name #:key (default name) warn?) (or (search-path (string-split (getenv "PATH") #\:) name) (and (and warn? (format (current-error-port) "warning: not found: ~a\n" name)) default))) (define *shell* "sh") (define PACKAGE "mes") (define VERSION "0.16.1") (define GUILE (PATH-search-path (or (getenv "guile") "guile"))) (define GUILE_EFFECTIVE_VERSION (effective-version)) (define prefix "/usr/local") (define infodir "${prefix}/share/info") (define mandir "${prefix}/share/man") (define sysconfdir "${prefix}/etc") ;;; Utility (define (logf port string . rest) (apply format (cons* port string rest)) (force-output port) #t) (define (stderr string . rest) (apply logf (cons* (current-error-port) string rest))) (define (stdout string . rest) (apply logf (cons* (current-output-port) string rest))) (define *verbose?* #f) (define (verbose string . rest) (if *verbose?* (apply stderr (cons string rest)))) (define (gulp-pipe command) (let* ((port (open-pipe* OPEN_READ *shell* "-c" command)) (output (read-string port)) (status (close-pipe port))) (verbose "command[~a]: ~s => ~a\n" status command output) (if (not (zero? status)) "" (string-trim-right output #\newline)))) (define* ((->string #:optional (infix "")) h . t) (let ((o (if (pair? t) (cons h t) h))) (match o ((? char?) (make-string 1 o)) ((? number?) (number->string o)) ((? string?) o) ((? symbol?) (symbol->string o)) ((h ... t) (string-join (map (->string) o) ((->string) infix))) (_ "")))) (define (tuple< a b) (cond ((and (null? a) (null? b)) #t) ((null? a) (not (null? b))) ((null? b) #f) ((and (not (< (car a) (car b))) (not (< (car b) (car a)))) (tuple< (cdr a) (cdr b))) (else (< (car a) (car b))))) (define (tuple<= a b) (or (equal? a b) (tuple< a b))) ;;; Configure (define (version->string version) ((->string '.) version)) (define (string->version string) (and-let* ((version (string-tokenize string (char-set-adjoin char-set:digit #\.))) ((pair? version)) (version (sort version (lambda (a b) (> (string-length a) (string-length b))))) (version (car version)) (version (string-tokenize version (char-set-complement (char-set #\.))))) (map string->number version))) (define optional '()) (define required '()) (define* (check-version name expected #:key optional? (deb #f) (version-option '--version) (compare tuple<=) (command name)) (stderr "checking for ~a~a..." (basename name) (if (null? expected) "" (format #f " [~a]" (version->string expected)))) (let* ((output (gulp-pipe (format #f "~a ~a 2>&1" command version-option))) (actual (string->version output)) (pass? (and actual (compare expected actual))) ;(pass? (PATH-search-path command)) ) (stderr "~a ~a\n" (if pass? (if (pair? actual) "" " yes") (if actual " no, found" "")) (version->string actual)) (or pass? (if (not (pair? name)) (begin (if optional? (set! optional (cons (or deb name) optional)) (set! required (cons (or deb name) required))) pass?) (check-version (cdr name) expected deb version-option compare))))) (define* (check-pkg-config package expected #:optional (deb #f)) (check-version (format #f "pkg-config --modversion ~a" package) expected deb)) (define (check-compile-header-c header) (and (= 0 (system (format #f "echo '#include ~s' | gcc -E - > /dev/null 2>&1" header))) 'yes)) (define (check-compile-header-c++ header) (and (= 0 (system (format #f "echo '#include ~s' | gcc --language=c++ --std=c++11 -E - > /dev/null 2>&1" header))) 'yes)) (define* (check-header-c header deb #:optional (check check-compile-header-c)) (stderr "checking for ~a..." header) (let ((result (check header))) (stderr " ~a\n" (if result result "no")) (if (not result) (set! required (cons deb required))))) (define* (check-header-c++ header deb #:optional (check check-compile-header-c++)) (check-header-c header deb check)) (define guix? (and (zero? (system "guix --version 1>/dev/null 2>/dev/null")) 1)) ;;; (define (parse-opts args) (let* ((option-spec '((build (value #t)) (host (value #t)) (help (single-char #\h)) (prefix (value #t)) (sysconfdir (value #t)) (verbose (single-char #\v)) (with-courage) (infodir (value #t)) (mandir (value #t)) (disable-silent-rules) (enable-fast-install) ; Ignored for Guix (includedir (value #t)) ; Ignored for Debian (mandir (value #t)) ; Ignored for Debian (localstatedir (value #t)) ; Ignored for Debian (libdir (value #t)) ; Ignored for Debian (libexecdir (value #t)) ; Ignored for Debian (runstatedir (value #t)) ; Ignored for Debian (disable-maintainer-mode) ; Ignored for Debian (disable-dependency-tracking) ; Ignored for Debian ))) (getopt-long args option-spec))) (define* (print-help #:optional (port (current-output-port))) (format port "\ `configure' configures ~a ~a to adapt to many kinds of systems. Usage: ./configure [OPTION]... [VAR=VALUE] To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Options: -h, --help display this help --build=BUILD configure for building on BUILD [guessed] --disable-silent-rules verbose build output [BUILD_DEBUG=1] --host=HOST cross-compile to build programs to run on HOST [BUILD] -v, --verbose be verbose --with-courage assert being courageous to configure for unsupported platform Installation directories: --prefix=DIR install in prefix DIR [~a] --infodir=DIR info documentation [PREFIX/share/info] --mandir=DIR man pages [PREFIX/share/man] Ignored for Guix: --enable-fast-install Ignored for Debian: --disable-dependency-tracking --disable-maintainer-mode --includedir=DIR --libdir=DIR --libexecdir=DIR --localstatedir=DIR --mandir=DIR --runstatedir=DIR Some influential environment variables: CC C compiler command CFLAGS C compiler flags CC32 x86 C compiler command CC32_CFLAGS x86 C compiler flags GUILE guile command GUILE_TOOLS guile-tools command MES_CFLAGS MesCC flags MES_SEED location of mes-seed MESCC_TOOLS_SEED location of mescc-tools-seed TCC tcc C compiler command TINYCC_SEED location of tinycc-seed " PACKAGE VERSION (getenv "prefix"))) (define* (substitute file-name pairs #:key (target (if (string-suffix? ".in" file-name) (string-drop-right file-name 3) target))) (with-output-to-file target (lambda _ (display (fold (lambda (o result) (regexp-substitute/global #f (car o) result 'pre (cdr o) 'post)) (with-input-from-file file-name read-string) pairs))))) (define (main args) (let* ((CC (or (getenv "CC") "gcc")) (srcdir (dirname (car (command-line)))) (abs-top-srcdir (canonicalize-path srcdir)) (builddir (getcwd)) (abs-top-builddir (canonicalize-path builddir)) (BUILD_TRIPLET %host-type) (ARCH (car (string-split BUILD_TRIPLET #\-))) (options (parse-opts args)) (build-triplet (option-ref options 'build BUILD_TRIPLET)) (host-triplet (option-ref options 'host BUILD_TRIPLET)) (prefix (option-ref options 'prefix prefix)) (infodir (option-ref options 'infodir infodir)) (sysconfdir (option-ref options 'sysconfdir sysconfdir)) (datadir (string-append prefix "/share/mes")) (moduledir (string-append datadir"module")) (guile-effective-version (effective-version)) (guile-site-dir (if (equal? prefix ".") (canonicalize-path ".") (string-append prefix "/share/guile/site/" guile-effective-version))) (guile-site-ccache-dir (if (equal? prefix ".") (canonicalize-path ".") (string-append prefix "/lib/guile/" guile-effective-version "/site-ccache"))) (verbose? (option-ref options 'verbose #f)) (with-courage? (option-ref options 'with-courage #f)) (disable-silent-rules? (option-ref options 'disable-silent-rules #f)) (make? #f) (vars (filter (cut string-index <> #\=) (option-ref options '() '()))) (help? (option-ref options 'help #f))) (for-each (lambda (v) (apply setenv (string-split v #\=))) vars) (let ((CC32 (or (getenv "CC32") (if (member ARCH '("i686" "arm")) (string-append BUILD_TRIPLET "-" CC) "i686-unknown-linux-gnu-gcc"))) (BASH (or (getenv "BASH") "bash")) (HELP2MAN (or (getenv "HELP2MAN") "help2man")) (TCC (or (getenv "TCC") "tcc")) (MAKEINFO (or (getenv "MAKEINFO") "makeinfo")) (GUILE_TOOLS (or (getenv "GUILE_TOOLS") "guile-tools")) (BLOOD_ELF (or (getenv "BLOOD_ELF") "blood-elf")) (HEX2 (or (getenv "HEX2") "hex2")) (M1 (or (getenv "M1") "M1")) (CFLAGS (getenv "CFLAGS")) (CC32_CFLAGS (getenv "CC32_CFLAGS")) (HEX2FLAGS (getenv "HEX2FLAGS")) (M1FLAGS (getenv "M1FLAGS")) (MES_CFLAGS (getenv "MES_CFLAGS")) (MES_SEED (or (getenv "MES_SEED") "../mes-seed")) (MESCC_TOOLS_SEED (or (getenv "MESCC_TOOLS_SEED") "../mescc-tools-seed")) (TINYCC_SEED (or (getenv "TINYCC_SEED") "../tinycc-seed"))) (when help? (print-help) (exit 0)) (set! *verbose?* verbose?) (check-version "guile" '(2 0)) (check-version "guile-tools" '(2 0)) (check-version "mes-seed" '(0 16 1) #:optional? #t #:command (string-append MES_SEED "/refresh.sh")) (check-version "tinycc-seed" '(0 16) #:optional? #t #:command (string-append TINYCC_SEED "/refresh.sh")) (check-version BLOOD_ELF '(0 1)) (check-version HEX2 '(0 3)) (check-version M1 '(0 3)) (check-version "nyacc" '(0 80 41) #:command (string-append GUILE " -c '(use-modules (nyacc lalr)) (display *nyacc-version*)'")) (check-version "bash" '(4 0)) (when (and (check-version "git" '(2 0) #:optional? #t) (not (file-exists? ".git"))) ;; Debian wants to run `make clean' from a tarball (and (zero? (system* "git" "init")) (zero? (system* "git" "add" ".")) (zero? (system* "git" "commit" "-m" "Import mes")))) (when (and (not (member ARCH '("i686" "x86_64"))) (not with-courage?)) (stderr "platform not supported: ~a, try --with-courage\n" ARCH) (exit 1)) (if (check-version "bash" '(2)) (set! BASH (PATH-search-path BASH)) (set! BASH #f)) (if (not (check-version CC '(4 8) #:optional? #t)) (set! CC #f)) (when CC (check-header-c "stdio.h" "libc-dev") (check-header-c "limits.h" "linux-headers")) (if (not (check-version CC32 '(4 8) #:optional? #t)) (set! CC32 #f)) (if (not (check-version TCC '(0 9 26) #:optional? #t #:version-option "-v")) (set! TCC #f)) (set! make? (check-version "make" '(4 0) #:optional? #t)) (check-version "perl" '(5)) (if (not (check-version "makeinfo" '(6) #:optional? #t)) (set! MAKEINFO #f)) (if (not (check-version "help2man" '(1 47) #:optional? #t)) (set! HELP2MAN #f)) (when (pair? required) (stderr "\nMissing dependencies [~a], run\n\n" ((->string ", ") required)) (if guix? (stderr " guix environment -l guix.scm\n") (stderr " sudo apt-get install ~a\n" ((->string " ") required))) (exit 1)) (with-output-to-file ".config.make" (lambda () (stdout "build:=~a\n" build-triplet) (stdout "host:=~a\n" host-triplet) (stdout "srcdir:=.\n") (stdout "prefix:=~a\n" (gulp-pipe (string-append "echo " prefix))) (stdout "infodir:=~a\n" infodir) (stdout "mandir:=~a\n" mandir) (stdout "datadir:=~a\n" datadir) (stdout "moduledir:=~a\n" moduledir) (stdout "sysconfdir:=~a\n" sysconfdir) (stdout "ARCH:=~a\n" ARCH) (stdout "CC:=~a\n" (or CC "")) (stdout "CC32:=~a\n" (or CC32 "")) (stdout "HELP2MAN:=~a\n" (or HELP2MAN "")) (stdout "MAKEINFO:=~a\n" (or MAKEINFO "")) (stdout "TCC:=~a\n" (or TCC "")) (stdout "BLOOD_ELF:=~a\n" (or BLOOD_ELF "")) (stdout "MES_SEED:=~a\n" (or MES_SEED "")) (stdout "MESCC_TOOLS_SEED:=~a\n" (or MESCC_TOOLS_SEED "")) (stdout "TINYCC_SEED:=~a\n" (or TINYCC_SEED "")) (stdout "HEX2:=~a\n" (or HEX2 "")) (stdout "M1:=~a\n" (or M1 "")) (stdout "GUILE:=~a\n" GUILE) (stdout "GUILE_TOOLS:=~a\n" GUILE_TOOLS) (stdout "GUILE_FOR_BUILD:=~a\n" GUILE) (stdout "GUILE_EFFECTIVE_VERSION:=~a\n" GUILE_EFFECTIVE_VERSION) (stdout "GUIX_P:=~a\n" (if guix? guix? "")) (stdout "HEX2:=~a\n" (or HEX2 "")) (stdout "PACKAGE:=~a\n" PACKAGE) (stdout "VERSION:=~a\n" VERSION) (when disable-silent-rules? (stdout "BUILD_DEBUG:=1\n")) (when CFLAGS (stdout "CFLAGS:=~a\n" CFLAGS)) (when CC32_CFLAGS (stdout "CC32_CFLAGS:=~a\n" CC32_CFLAGS)) (when HEX2FLAGS (stdout "HEX2FLAGS:=~a\n" HEX2FLAGS)) (when M1FLAGS (stdout "M1FLAGS:=~a\n" M1FLAGS)) (when MES_CFLAGS (stdout "MES_CFLAGS:=~a\n" MES_CFLAGS)))) (let ((pairs `(("@abs_top_srcdir@" . ,abs-top-srcdir) ("@abs_top_builddir@" . ,abs-top-builddir) ("@BASH@" . ,BASH) ("@GUILE@" . ,GUILE) ("@guile_site_dir@" . ,guile-site-dir) ("@guile_site_ccache_dir@" . ,guile-site-ccache-dir) ("@VERSION@" . ,VERSION) ("mes/module/" . ,(string-append moduledir "/"))))) (for-each (lambda (o) (substitute o pairs) (chmod (string-drop-right o 3) #o755)) '( "build-aux/pre-inst-env.in" "mes/module/mes/boot-0.scm.in" "scripts/mescc.in" ))) (chmod "build-aux/pre-inst-env" #o755) (rename-file "build-aux/pre-inst-env" "pre-inst-env") (chmod "scripts/mescc" #o755) (format (current-output-port) "\nRun: ~a to build mes ~a help for help on other targets\n" (if make? "make" "./build.sh") (if make? "make" "./build.sh")))))