test-ffi 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. #!/bin/sh
  2. exec guile -q -s "$0" "$@"
  3. !#
  4. ;;; test-ffi --- Foreign function interface. -*- Scheme -*-
  5. ;;;
  6. ;;; Copyright (C) 2010 Free Software Foundation, Inc.
  7. ;;;
  8. ;;; This library is free software; you can redistribute it and/or
  9. ;;; modify it under the terms of the GNU Lesser General Public
  10. ;;; License as published by the Free Software Foundation; either
  11. ;;; version 3 of the License, or (at your option) any later version.
  12. ;;;
  13. ;;; This library is distributed in the hope that it will be useful,
  14. ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. ;;; Lesser General Public License for more details.
  17. ;;;
  18. ;;; You should have received a copy of the GNU Lesser General Public
  19. ;;; License along with this library; if not, write to the Free Software
  20. ;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  21. (use-modules (system foreign)
  22. (rnrs bytevectors)
  23. (srfi srfi-1)
  24. (srfi srfi-26))
  25. (define lib
  26. (dynamic-link (string-append (getenv "builddir") "/libtest-ffi")))
  27. (define failed? #f)
  28. (define-syntax test
  29. (syntax-rules ()
  30. ((_ exp res)
  31. (let ((expected res)
  32. (actual exp))
  33. (if (not (equal? actual expected))
  34. (begin
  35. (set! failed? #t)
  36. (format (current-error-port)
  37. "bad return from expression `~a': expected ~A; got ~A~%"
  38. 'exp expected actual)))))))
  39. ;;;
  40. ;;; No args
  41. ;;;
  42. (define f-v-
  43. (pointer->procedure void (dynamic-func "test_ffi_v_" lib) '()))
  44. (test (f-v-) *unspecified*)
  45. (define f-s8-
  46. (pointer->procedure int8 (dynamic-func "test_ffi_s8_" lib) '()))
  47. (test (f-s8-) -100)
  48. (define f-u8-
  49. (pointer->procedure uint8 (dynamic-func "test_ffi_u8_" lib) '()))
  50. (test (f-u8-) 200)
  51. (define f-s16-
  52. (pointer->procedure int16 (dynamic-func "test_ffi_s16_" lib) '()))
  53. (test (f-s16-) -20000)
  54. (define f-u16-
  55. (pointer->procedure uint16 (dynamic-func "test_ffi_u16_" lib) '()))
  56. (test (f-u16-) 40000)
  57. (define f-s32-
  58. (pointer->procedure int32 (dynamic-func "test_ffi_s32_" lib) '()))
  59. (test (f-s32-) -2000000000)
  60. (define f-u32-
  61. (pointer->procedure uint32 (dynamic-func "test_ffi_u32_" lib) '()))
  62. (test (f-u32-) 4000000000)
  63. (define f-s64-
  64. (pointer->procedure int64 (dynamic-func "test_ffi_s64_" lib) '()))
  65. (test (f-s64-) -2000000000)
  66. (define f-u64-
  67. (pointer->procedure uint64 (dynamic-func "test_ffi_u64_" lib) '()))
  68. (test (f-u64-) 4000000000)
  69. ;;;
  70. ;;; One u8 arg
  71. ;;;
  72. (define f-v-u8
  73. (pointer->procedure void (dynamic-func "test_ffi_v_u8" lib) (list uint8)))
  74. (test (f-v-u8 10) *unspecified*)
  75. (define f-s8-u8
  76. (pointer->procedure int8 (dynamic-func "test_ffi_s8_u8" lib) (list uint8)))
  77. (test (f-s8-u8 10) -90)
  78. (define f-u8-u8
  79. (pointer->procedure uint8 (dynamic-func "test_ffi_u8_u8" lib) (list uint8)))
  80. (test (f-u8-u8 10) 210)
  81. (define f-s16-u8
  82. (pointer->procedure int16 (dynamic-func "test_ffi_s16_u8" lib) (list uint8)))
  83. (test (f-s16-u8 10) -19990)
  84. (define f-u16-u8
  85. (pointer->procedure uint16 (dynamic-func "test_ffi_u16_u8" lib) (list uint8)))
  86. (test (f-u16-u8 10) 40010)
  87. (define f-s32-u8
  88. (pointer->procedure int32 (dynamic-func "test_ffi_s32_u8" lib) (list uint8)))
  89. (test (f-s32-u8 10) -1999999990)
  90. (define f-u32-u8
  91. (pointer->procedure uint32 (dynamic-func "test_ffi_u32_u8" lib) (list uint8)))
  92. (test (f-u32-u8 10) 4000000010)
  93. (define f-s64-u8
  94. (pointer->procedure int64 (dynamic-func "test_ffi_s64_u8" lib) (list uint8)))
  95. (test (f-s64-u8 10) -1999999990)
  96. (define f-u64-u8
  97. (pointer->procedure uint64 (dynamic-func "test_ffi_u64_u8" lib) (list uint8)))
  98. (test (f-u64-u8 10) 4000000010)
  99. ;;;
  100. ;;; One s64 arg
  101. ;;;
  102. (define f-v-s64
  103. (pointer->procedure void (dynamic-func "test_ffi_v_s64" lib) (list int64)))
  104. (test (f-v-s64 10) *unspecified*)
  105. (define f-s8-s64
  106. (pointer->procedure int8 (dynamic-func "test_ffi_s8_s64" lib) (list int64)))
  107. (test (f-s8-s64 10) -90)
  108. (define f-u8-s64
  109. (pointer->procedure uint8 (dynamic-func "test_ffi_u8_s64" lib) (list int64)))
  110. (test (f-u8-s64 10) 210)
  111. (define f-s16-s64
  112. (pointer->procedure int16 (dynamic-func "test_ffi_s16_s64" lib) (list int64)))
  113. (test (f-s16-s64 10) -19990)
  114. (define f-u16-s64
  115. (pointer->procedure uint16 (dynamic-func "test_ffi_u16_s64" lib) (list int64)))
  116. (test (f-u16-s64 10) 40010)
  117. (define f-s32-s64
  118. (pointer->procedure int32 (dynamic-func "test_ffi_s32_s64" lib) (list int64)))
  119. (test (f-s32-s64 10) -1999999990)
  120. (define f-u32-s64
  121. (pointer->procedure uint32 (dynamic-func "test_ffi_u32_s64" lib) (list int64)))
  122. (test (f-u32-s64 10) 4000000010)
  123. (define f-s64-s64
  124. (pointer->procedure int64 (dynamic-func "test_ffi_s64_s64" lib) (list int64)))
  125. (test (f-s64-s64 10) -1999999990)
  126. (define f-u64-s64
  127. (pointer->procedure uint64 (dynamic-func "test_ffi_u64_s64" lib) (list int64)))
  128. (test (f-u64-s64 10) 4000000010)
  129. ;;
  130. ;; Multiple int args of differing types
  131. ;;
  132. (define f-sum
  133. (pointer->procedure int64 (dynamic-func "test_ffi_sum" lib)
  134. (list int8 int16 int32 int64)))
  135. (test (f-sum -1 2000 -30000 40000000000)
  136. (+ -1 2000 -30000 40000000000))
  137. ;;
  138. ;; More than ten arguments
  139. ;;
  140. (define f-sum-many
  141. (pointer->procedure int64 (dynamic-func "test_ffi_sum_many" lib)
  142. (list uint8 uint16 uint32 uint64
  143. int8 int16 int32 int64
  144. int8 int16 int32 int64)))
  145. (test (f-sum-many 255 65535 4294967295 1844674407370955161
  146. -1 2000 -30000 40000000000
  147. 5 -6000 70000 -80000000000)
  148. (+ 255 65535 4294967295 1844674407370955161
  149. -1 2000 -30000 40000000000
  150. 5 -6000 70000 -80000000000))
  151. ;;
  152. ;; Structs
  153. ;;
  154. (define f-sum-struct
  155. (pointer->procedure int64 (dynamic-func "test_ffi_sum_struct" lib)
  156. (list (list int8 int16 int32 int64))))
  157. (test (f-sum-struct (make-c-struct (list int8 int16 int32 int64)
  158. (list -1 2000 -30000 40000000000)))
  159. (+ -1 2000 -30000 40000000000))
  160. ;;
  161. ;; Structs
  162. ;;
  163. (define f-memcpy
  164. (pointer->procedure '* (dynamic-func "test_ffi_memcpy" lib)
  165. (list '* '* int32)))
  166. (let* ((src* '(0 1 2 3 4 5 6 7))
  167. (src (bytevector->pointer (u8-list->bytevector src*)))
  168. (dest (bytevector->pointer (make-bytevector 16 0)))
  169. (res (f-memcpy dest src (length src*))))
  170. (or (= (pointer-address dest) (pointer-address res))
  171. (error "memcpy res not equal to dest"))
  172. (or (equal? (bytevector->u8-list (pointer->bytevector dest 16))
  173. '(0 1 2 3 4 5 6 7 0 0 0 0 0 0 0 0))
  174. (error "unexpected dest")))
  175. ;;
  176. ;; Function pointers
  177. ;;
  178. (define f-callback-1
  179. (pointer->procedure int (dynamic-func "test_ffi_callback_1" lib)
  180. (list '* int)))
  181. (if (defined? 'procedure->pointer)
  182. (let* ((calls 0)
  183. (ptr (procedure->pointer int
  184. (lambda (x)
  185. (set! calls (+ 1 calls))
  186. (* x 3))
  187. (list int)))
  188. (input (iota 123)))
  189. (define (expected-result x)
  190. (+ 7 (* x 3)))
  191. (let ((result (map (cut f-callback-1 ptr <>) input)))
  192. (and (or (= calls (length input))
  193. (error "incorrect number of callback calls" calls))
  194. (or (equal? (map expected-result input) result)
  195. (error "incorrect result" result))))))
  196. (define f-callback-2
  197. (pointer->procedure double (dynamic-func "test_ffi_callback_2" lib)
  198. (list '* float int double)))
  199. (if (defined? 'procedure->pointer)
  200. (let* ((proc (lambda (x y z)
  201. (* (+ x (exact->inexact y)) z)))
  202. (ptr (procedure->pointer double proc
  203. (list float int double)))
  204. (arg1 (map (cut * <> 1.25) (iota 123 500)))
  205. (arg2 (iota 123))
  206. (arg3 (map (cut / <> 2.0) (iota 123 0 -10))))
  207. (define result
  208. (map (cut f-callback-2 ptr <> <> <>)
  209. arg1 arg2 arg3))
  210. (or (equal? result (map proc arg1 arg2 arg3))
  211. (error "incorrect result" result))))
  212. ;;;
  213. ;;; Global symbols.
  214. ;;;
  215. (use-modules ((rnrs bytevectors) #:select (utf8->string)))
  216. (if (defined? 'setlocale)
  217. (setlocale LC_ALL "C"))
  218. (define global (dynamic-link))
  219. (define strerror
  220. (pointer->procedure '* (dynamic-func "strerror" global)
  221. (list int)))
  222. (define strlen
  223. (pointer->procedure size_t (dynamic-func "strlen" global)
  224. (list '*)))
  225. (let* ((ptr (strerror ENOENT))
  226. (len (strlen ptr))
  227. (bv (pointer->bytevector ptr len 0 'u8))
  228. (str (utf8->string bv)))
  229. (test #t (not (not (string-contains str "file")))))
  230. (exit (not failed?))
  231. ;; Local Variables:
  232. ;; mode: scheme
  233. ;; End: