scan-api 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. #!/bin/sh
  2. # aside from this initial boilerplate, this is actually -*- scheme -*- code
  3. main='(module-ref (resolve-module '\''(scripts scan-api)) '\'main')'
  4. exec ${GUILE-guile} -l $0 -c "(apply $main (cdr (command-line)))" "$@"
  5. !#
  6. ;;; scan-api --- Scan and group interpreter and libguile interface elements
  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: scan-api GUILE SOFILE [GROUPINGS ...]
  26. ;;
  27. ;; Invoke GUILE, an executable guile interpreter, and use nm(1) on SOFILE, a
  28. ;; shared-object library, to determine available interface elements, and
  29. ;; display them to stdout as an alist:
  30. ;;
  31. ;; ((meta ...) (interface ...))
  32. ;;
  33. ;; The meta fields are `GUILE_LOAD_PATH', `LTDL_LIBRARY_PATH', `guile'
  34. ;; `libguileinterface', `sofile' and `groups'. The interface elements are in
  35. ;; turn sub-alists w/ keys `groups' and `scan-data'. Interface elements
  36. ;; initially belong in one of two groups `Scheme' or `C' (but not both --
  37. ;; signal error if that happens).
  38. ;;
  39. ;; Optional GROUPINGS ... are files each containing a single "grouping
  40. ;; definition" alist with each entry of the form:
  41. ;;
  42. ;; (NAME (description "DESCRIPTION") (members SYM...))
  43. ;;
  44. ;; All of the SYM... should be proper subsets of the interface. In addition
  45. ;; to `description' and `members' forms, the entry may optionally include:
  46. ;;
  47. ;; (grok USE-MODULES (lambda (x) CODE))
  48. ;;
  49. ;; where CODE implements a group-membership predicate to be applied to `x', a
  50. ;; symbol. [When evaluated, CODE can assume (use-modules MODULE) has been
  51. ;; executed where MODULE is an element of USE-MODULES, a list. [NOT YET
  52. ;; IMPLEMENTED!]]
  53. ;;
  54. ;; Currently, there are two convenience predicates that operate on `x':
  55. ;; (in-group? x GROUP)
  56. ;; (name-prefix? x PREFIX)
  57. ;;
  58. ;; TODO: Allow for concurrent Scheme/C membership.
  59. ;; Completely separate reporting.
  60. ;;; Code:
  61. (define-module (scripts scan-api)
  62. :use-module (ice-9 popen)
  63. :use-module (ice-9 rdelim)
  64. :use-module (ice-9 regex)
  65. :export (scan-api))
  66. (define put set-object-property!)
  67. (define get object-property)
  68. (define (add-props object . args)
  69. (let loop ((args args))
  70. (if (null? args)
  71. object ; retval
  72. (let ((key (car args))
  73. (value (cadr args)))
  74. (put object key value)
  75. (loop (cddr args))))))
  76. (define (scan re command match)
  77. (let ((rx (make-regexp re))
  78. (port (open-pipe command OPEN_READ)))
  79. (let loop ((line (read-line port)))
  80. (or (eof-object? line)
  81. (begin
  82. (cond ((regexp-exec rx line) => match))
  83. (loop (read-line port)))))))
  84. (define (scan-Scheme! ht guile)
  85. (scan "^.guile.+: ([^ \t]+)([ \t]+(.+))*$"
  86. (format #f "~A -c '~S ~S'"
  87. guile
  88. '(use-modules (ice-9 session))
  89. '(apropos "."))
  90. (lambda (m)
  91. (let ((x (string->symbol (match:substring m 1))))
  92. (put x 'Scheme (or (match:substring m 3)
  93. ""))
  94. (hashq-set! ht x #t)))))
  95. (define (scan-C! ht sofile)
  96. (scan "^[0-9a-fA-F]+ ([B-TV-Z]) (.+)$"
  97. (format #f "nm ~A" sofile)
  98. (lambda (m)
  99. (let ((x (string->symbol (match:substring m 2))))
  100. (put x 'C (string->symbol (match:substring m 1)))
  101. (and (hashq-get-handle ht x)
  102. (error "both Scheme and C:" x))
  103. (hashq-set! ht x #t)))))
  104. (define THIS-MODULE (current-module))
  105. (define (in-group? x group)
  106. (memq group (get x 'groups)))
  107. (define (name-prefix? x prefix)
  108. (string-match (string-append "^" prefix) (symbol->string x)))
  109. (define (add-group-name! x name)
  110. (put x 'groups (cons name (get x 'groups))))
  111. (define (make-grok-proc name form)
  112. (let* ((predicate? (eval form THIS-MODULE))
  113. (p (lambda (x)
  114. (and (predicate? x)
  115. (add-group-name! x name)))))
  116. (put p 'name name)
  117. p))
  118. (define (make-members-proc name members)
  119. (let ((p (lambda (x)
  120. (and (memq x members)
  121. (add-group-name! x name)))))
  122. (put p 'name name)
  123. p))
  124. (define (make-grouper files) ; \/^^^o/ . o
  125. (let ((hook (make-hook 1))) ; /\____\
  126. (for-each
  127. (lambda (file)
  128. (for-each
  129. (lambda (gdef)
  130. (let ((name (car gdef))
  131. (members (assq-ref gdef 'members))
  132. (grok (assq-ref gdef 'grok)))
  133. (or members grok
  134. (error "bad grouping, must have `members' or `grok'"))
  135. (add-hook! hook
  136. (if grok
  137. (add-props (make-grok-proc name (cadr grok))
  138. 'description
  139. (assq-ref gdef 'description))
  140. (make-members-proc name members))
  141. #t))) ; append
  142. (read (open-file file OPEN_READ))))
  143. files)
  144. hook))
  145. (define (scan-api . args)
  146. (let ((guile (list-ref args 0))
  147. (sofile (list-ref args 1))
  148. (grouper (false-if-exception (make-grouper (cddr args))))
  149. (ht (make-hash-table 3331)))
  150. (scan-Scheme! ht guile)
  151. (scan-C! ht sofile)
  152. (let ((all (sort (hash-fold (lambda (key value prior-result)
  153. (add-props
  154. key
  155. 'string (symbol->string key)
  156. 'scan-data (or (get key 'Scheme)
  157. (get key 'C))
  158. 'groups (if (get key 'Scheme)
  159. '(Scheme)
  160. '(C)))
  161. (and grouper (run-hook grouper key))
  162. (cons key prior-result))
  163. '()
  164. ht)
  165. (lambda (a b)
  166. (string<? (get a 'string)
  167. (get b 'string))))))
  168. (format #t ";;; generated by scan-api -- do not edit!\n\n")
  169. (format #t "(\n")
  170. (format #t "(meta\n")
  171. (format #t " (GUILE_LOAD_PATH . ~S)\n"
  172. (or (getenv "GUILE_LOAD_PATH") ""))
  173. (format #t " (LTDL_LIBRARY_PATH . ~S)\n"
  174. (or (getenv "LTDL_LIBRARY_PATH") ""))
  175. (format #t " (guile . ~S)\n" guile)
  176. (format #t " (libguileinterface . ~S)\n"
  177. (let ((i #f))
  178. (scan "(.+)"
  179. (format #f "~A -c '(display ~A)'"
  180. guile
  181. '(assq-ref %guile-build-info
  182. 'libguileinterface))
  183. (lambda (m) (set! i (match:substring m 1))))
  184. i))
  185. (format #t " (sofile . ~S)\n" sofile)
  186. (format #t " ~A\n"
  187. (cons 'groups (append (if grouper
  188. (map (lambda (p) (get p 'name))
  189. (hook->list grouper))
  190. '())
  191. '(Scheme C))))
  192. (format #t ") ;; end of meta\n")
  193. (format #t "(interface\n")
  194. (for-each (lambda (x)
  195. (format #t "(~A ~A (scan-data ~S))\n"
  196. x
  197. (cons 'groups (get x 'groups))
  198. (get x 'scan-data)))
  199. all)
  200. (format #t ") ;; end of interface\n")
  201. (format #t ") ;; eof\n")))
  202. #t)
  203. (define main scan-api)
  204. ;;; scan-api ends here