Reimplement %allocate-instance in Scheme
[bpt/guile.git] / module / scripts / autofrisk.scm
CommitLineData
2b8efa0c
TTN
1;;; autofrisk --- Generate module checks for use with auto* tools
2
a1a2ed53 3;; Copyright (C) 2002, 2006, 2009, 2011 Free Software Foundation, Inc.
2b8efa0c
TTN
4;;
5;; This program is free software; you can redistribute it and/or
83ba2d37
NJ
6;; modify it under the terms of the GNU Lesser General Public License
7;; as published by the Free Software Foundation; either version 3, or
2b8efa0c
TTN
8;; (at your option) any later version.
9;;
10;; This program is distributed in the hope that it will be useful,
11;; but WITHOUT ANY WARRANTY; without even the implied warranty of
12;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
83ba2d37 13;; Lesser General Public License for more details.
2b8efa0c 14;;
83ba2d37
NJ
15;; You should have received a copy of the GNU Lesser General Public
16;; License along with this software; see the file COPYING.LESSER. If
17;; not, write to the Free Software Foundation, Inc., 51 Franklin
18;; Street, Fifth Floor, Boston, MA 02110-1301 USA
2b8efa0c
TTN
19
20;;; Author: Thien-Thi Nguyen <ttn@gnu.org>
21
22;;; Commentary:
23
24;; Usage: autofrisk [file]
25;;
26;; This program looks for the file modules.af in the current directory
27;; and writes out modules.af.m4 containing autoconf definitions.
28;; If given, look for FILE instead of modules.af and output to FILE.m4.
29;;
30;; After running autofrisk, you should add to configure.ac the lines:
31;; AUTOFRISK_CHECKS
32;; AUTOFRISK_SUMMARY
33;; Then run "aclocal -I ." to update aclocal.m4, and finally autoconf.
34;;
35;; The modules.af file consists of a series of configuration forms (Scheme
36;; lists), which have one of the following formats:
37;; (files-glob PATTERN ...)
38;; (non-critical-external MODULE ...)
39;; (non-critical-internal MODULE ...)
40;; (programs (MODULE PROG ...) ...)
41;; (pww-varname VARNAME)
42;; PATTERN is a string that may contain "*" and "?" characters to be
43;; expanded into filenames. MODULE is a list of symbols naming a
44;; module, such as `(srfi srfi-1)'. VARNAME is a shell-safe name to use
45;; instead of "probably_wont_work", the default. This var is passed to
46;; `AC_SUBST'. PROG is a string.
47;;
48;; Only the `files-glob' form is required.
49;;
50;; TODO: Write better commentary.
51;; Make "please see README" configurable.
52
53;;; Code:
54
55(define-module (scripts autofrisk)
56 :autoload (ice-9 popen) (open-input-pipe)
57 :use-module (srfi srfi-1)
58 :use-module (srfi srfi-8)
59 :use-module (srfi srfi-13)
60 :use-module (srfi srfi-14)
61 :use-module (scripts read-scheme-source)
62 :use-module (scripts frisk)
63 :export (autofrisk))
64
a1a2ed53
AW
65(define %include-in-guild-list #f)
66(define %summary "Generate snippets for use in configure.ac files.")
67
2b8efa0c
TTN
68(define *recognized-keys* '(files-glob
69 non-critical-external
70 non-critical-internal
71 programs
72 pww-varname))
73
74(define (canonical-configuration forms)
75 (let ((chk (lambda (condition . x)
76 (or condition (apply error "syntax error:" x)))))
77 (chk (list? forms) "input not a list")
78 (chk (every list? forms) "non-list element")
79 (chk (every (lambda (form) (< 1 (length form))) forms) "list too short")
80 (let ((un #f))
81 (chk (every (lambda (form)
82 (let ((key (car form)))
83 (and (symbol? key)
84 (or (eq? 'quote key)
85 (memq key *recognized-keys*)
86 (begin
87 (set! un key)
88 #f)))))
89 forms)
90 "unrecognized key:" un))
91 (let ((bunched (map (lambda (key)
92 (fold (lambda (form so-far)
93 (or (and (eq? (car form) key)
94 (cdr form)
95 (append so-far (cdr form)))
96 so-far))
97 (list key)
98 forms))
99 *recognized-keys*)))
100 (lambda (key)
101 (assq-ref bunched key)))))
102
103(define (>>strong modules)
104 (for-each (lambda (module)
105 (format #t "GUILE_MODULE_REQUIRED~A\n" module))
106 modules))
107
108(define (safe-name module)
109 (let ((var (object->string module)))
110 (string-map! (lambda (c)
111 (if (char-set-contains? char-set:letter+digit c)
112 c
113 #\_))
114 var)
115 var))
116
117(define *pww* "probably_wont_work")
118
119(define (>>weak weak-edges)
120 (for-each (lambda (edge)
121 (let* ((up (edge-up edge))
122 (down (edge-down edge))
123 (var (format #f "have_guile_module~A" (safe-name up))))
124 (format #t "GUILE_MODULE_AVAILABLE(~A, ~A)\n" var up)
125 (format #t "test \"$~A\" = no &&\n ~A=\"~A $~A\"~A"
126 var *pww* down *pww* "\n\n")))
127 weak-edges))
128
129(define (>>program module progs)
130 (let ((vars (map (lambda (prog)
131 (format #f "guile_module~Asupport_~A"
132 (safe-name module)
133 prog))
134 progs)))
135 (for-each (lambda (var prog)
136 (format #t "AC_PATH_PROG(~A, ~A)\n" var prog))
137 vars progs)
138 (format #t "test \\\n")
139 (for-each (lambda (var)
140 (format #t " \"$~A\" = \"\" -o \\\n" var))
141 vars)
142 (format #t "~A &&\n~A=\"~A $~A\"\n\n"
143 (list-ref (list "war = peace"
144 "freedom = slavery"
145 "ignorance = strength")
146 (random 3))
147 *pww* module *pww*)))
148
149(define (>>programs programs)
150 (for-each (lambda (form)
151 (>>program (car form) (cdr form)))
152 programs))
153
154(define (unglob pattern)
155 (let ((p (open-input-pipe (format #f "echo '(' ~A ')'" pattern))))
156 (map symbol->string (read p))))
157
158(define (>>checks forms)
159 (let* ((cfg (canonical-configuration forms))
160 (files (apply append (map unglob (cfg 'files-glob))))
161 (ncx (cfg 'non-critical-external))
162 (nci (cfg 'non-critical-internal))
2b8efa0c
TTN
163 (report ((make-frisker) files))
164 (external (report 'external)))
165 (let ((pww-varname (cfg 'pww-varname)))
166 (or (null? pww-varname) (set! *pww* (car pww-varname))))
167 (receive (weak strong)
168 (partition (lambda (module)
169 (or (member module ncx)
170 (every (lambda (i)
171 (member i nci))
172 (map edge-down (mod-down-ls module)))))
173 external)
174 (format #t "AC_DEFUN([AUTOFRISK_CHECKS],[\n\n")
175 (>>strong strong)
176 (format #t "\n~A=~S\n\n" *pww* "")
177 (>>weak (fold (lambda (module so-far)
178 (append so-far (mod-down-ls module)))
179 (list)
180 weak))
181 (>>programs (cfg 'programs))
182 (format #t "AC_SUBST(~A)\n])\n\n" *pww*))))
183
184(define (>>summary)
185 (format #t
186 (symbol->string
187 '#{
188AC_DEFUN([AUTOFRISK_SUMMARY],[
189if test ! "$~A" = "" ; then
190 p=" ***"
191 echo "$p"
192 echo "$p NOTE:"
193 echo "$p The following modules probably won't work:"
194 echo "$p $~A"
195 echo "$p They can be installed anyway, and will work if their"
196 echo "$p dependencies are installed later. Please see README."
197 echo "$p"
198fi
199])
200}#)
201 *pww* *pww*))
202
203(define (autofrisk . args)
204 (let ((file (if (null? args) "modules.af" (car args))))
205 (or (file-exists? file)
206 (error "could not find input file:" file))
207 (with-output-to-file (format #f "~A.m4" file)
208 (lambda ()
209 (>>checks (read-scheme-source-silently file))
210 (>>summary)))))
211
212(define main autofrisk)
213
214;; Local variables:
215;; eval: (put 'receive 'scheme-indent-function 2)
216;; End:
217
218;;; autofrisk ends here