autofrisk 7.8 KB

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