ffi 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of ffi might be problematic. Click here for more details.

Files changed (62) hide show
  1. data/Rakefile +52 -29
  2. data/ext/AbstractMemory.c +72 -28
  3. data/ext/AutoPointer.c +54 -0
  4. data/ext/AutoPointer.h +18 -0
  5. data/ext/Buffer.c +21 -17
  6. data/ext/Callback.c +81 -43
  7. data/ext/Callback.h +1 -1
  8. data/ext/Invoker.c +465 -108
  9. data/ext/MemoryPointer.c +25 -90
  10. data/ext/NativeLibrary.c +90 -0
  11. data/ext/NativeLibrary.h +22 -0
  12. data/ext/Platform.c +21 -2
  13. data/ext/Pointer.c +107 -0
  14. data/ext/Pointer.h +21 -0
  15. data/ext/Types.c +16 -5
  16. data/ext/Types.h +3 -1
  17. data/ext/compat.h +14 -0
  18. data/ext/extconf.rb +13 -1
  19. data/ext/ffi.c +11 -1
  20. data/ext/ffi.mk +3 -3
  21. data/ext/libffi.darwin.mk +19 -8
  22. data/gen/Rakefile +12 -0
  23. data/lib/ffi/autopointer.rb +61 -0
  24. data/lib/ffi/errno.rb +8 -0
  25. data/lib/ffi/ffi.rb +38 -201
  26. data/lib/ffi/io.rb +7 -0
  27. data/lib/ffi/library.rb +116 -0
  28. data/lib/ffi/managedstruct.rb +55 -0
  29. data/lib/ffi/memorypointer.rb +3 -96
  30. data/lib/ffi/platform.rb +8 -5
  31. data/lib/ffi/pointer.rb +105 -0
  32. data/lib/ffi/struct.rb +97 -42
  33. data/lib/ffi/tools/const_generator.rb +177 -0
  34. data/lib/ffi/tools/generator.rb +58 -0
  35. data/lib/ffi/tools/generator_task.rb +35 -0
  36. data/lib/ffi/tools/struct_generator.rb +194 -0
  37. data/lib/ffi/tools/types_generator.rb +123 -0
  38. data/lib/ffi/types.rb +150 -0
  39. data/lib/ffi/variadic.rb +30 -0
  40. data/nbproject/Makefile-Default.mk +6 -3
  41. data/nbproject/Makefile-impl.mk +5 -5
  42. data/nbproject/Package-Default.bash +72 -0
  43. data/nbproject/configurations.xml +139 -25
  44. data/nbproject/private/configurations.xml +1 -1
  45. data/nbproject/project.xml +4 -0
  46. data/samples/gettimeofday.rb +6 -2
  47. data/samples/inotify.rb +59 -0
  48. data/samples/pty.rb +75 -0
  49. data/specs/buffer_spec.rb +64 -9
  50. data/specs/callback_spec.rb +308 -4
  51. data/specs/errno_spec.rb +13 -0
  52. data/specs/library_spec.rb +55 -0
  53. data/specs/managed_struct_spec.rb +40 -0
  54. data/specs/number_spec.rb +183 -0
  55. data/specs/pointer_spec.rb +126 -0
  56. data/specs/rbx/memory_pointer_spec.rb +7 -7
  57. data/specs/spec_helper.rb +7 -0
  58. data/specs/string_spec.rb +34 -0
  59. data/specs/struct_spec.rb +223 -0
  60. data/specs/typedef_spec.rb +48 -0
  61. data/specs/variadic_spec.rb +84 -0
  62. metadata +270 -237
@@ -1,5 +1,5 @@
1
1
  #include <ruby.h>
2
- #include "MemoryPointer.h"
2
+ #include "Pointer.h"
3
3
  #include "Types.h"
4
4
 
5
5
  ffi_type*
@@ -12,6 +12,10 @@ rb_FFI_NativeTypeToFFI(NativeType type)
12
12
  return &ffi_type_sint8;
13
13
  case UINT8:
14
14
  return &ffi_type_uint8;
15
+ case INT16:
16
+ return &ffi_type_sint16;
17
+ case UINT16:
18
+ return &ffi_type_uint16;
15
19
  case INT32:
16
20
  return &ffi_type_sint32;
17
21
  case UINT32:
@@ -27,6 +31,9 @@ rb_FFI_NativeTypeToFFI(NativeType type)
27
31
  case STRING:
28
32
  case RBXSTRING:
29
33
  case POINTER:
34
+ case BUFFER_IN:
35
+ case BUFFER_OUT:
36
+ case BUFFER_INOUT:
30
37
  return &ffi_type_pointer;
31
38
  default:
32
39
  return NULL;
@@ -40,13 +47,17 @@ rb_FFI_NativeValueToRuby(NativeType type, const void* ptr)
40
47
  case VOID:
41
48
  return Qnil;
42
49
  case INT8:
50
+ return INT2NUM(*(char *) ptr);
43
51
  case INT16:
52
+ return INT2NUM(*(short *) ptr);
44
53
  case INT32:
45
- return INT2FIX(*(int *) ptr);
54
+ return INT2NUM(*(int *) ptr);
46
55
  case UINT8:
56
+ return UINT2NUM(*(unsigned char *) ptr);
47
57
  case UINT16:
58
+ return UINT2NUM(*(unsigned short *) ptr);
48
59
  case UINT32:
49
- return INT2FIX(*(unsigned int *) ptr);
60
+ return UINT2NUM(*(unsigned int *) ptr);
50
61
  case INT64:
51
62
  return LL2NUM(*(signed long long *) ptr);
52
63
  case UINT64:
@@ -56,9 +67,9 @@ rb_FFI_NativeValueToRuby(NativeType type, const void* ptr)
56
67
  case FLOAT64:
57
68
  return rb_float_new(*(double *) ptr);
58
69
  case STRING:
59
- return rb_str_new2(*(char **) ptr);
70
+ return rb_tainted_str_new2(*(char **) ptr);
60
71
  case POINTER:
61
- return rb_FFI_MemoryPointer_new(*(void **) ptr);
72
+ return rb_FFI_Pointer_new(*(void **) ptr);
62
73
  default:
63
74
  rb_raise(rb_eRuntimeError, "Unknown type: %d", type);
64
75
  }
@@ -36,7 +36,9 @@ typedef enum {
36
36
  */
37
37
  STRING,
38
38
  /** A Rubinus :string arg - copies data both ways, and nul terminates */
39
- RBXSTRING
39
+ RBXSTRING,
40
+ /** The function takes a variable number of arguments */
41
+ VARARGS,
40
42
  } NativeType;
41
43
 
42
44
  #include <ffi.h>
@@ -1,8 +1,22 @@
1
1
  #ifndef FFI_COMPAT_H
2
2
  #define FFI_COMPAT_H
3
3
 
4
+ #include <ruby.h>
5
+
4
6
  #ifndef RARRAY_LEN
5
7
  # define RARRAY_LEN(ary) RARRAY(ary)->len
6
8
  #endif
9
+ #ifndef RSTRING_LEN
10
+ # define RSTRING_LEN(s) RSTRING(s)->len
11
+ #endif
12
+ #ifndef RSTRING_LEN
13
+ # define RSTRING_LEN(s) RSTRING(s)->len
14
+ #endif
15
+ #ifndef RSTRING_PTR
16
+ # define RSTRING_PTR(s) RSTRING(s)->ptr
17
+ #endif
18
+ #ifndef NUM2ULL
19
+ # define NUM2ULL(x) rb_num2ull((VALUE)x)
20
+ #endif
7
21
 
8
22
  #endif /* FFI_COMPAT_H */
@@ -2,7 +2,19 @@
2
2
  require 'mkmf'
3
3
  require 'rbconfig'
4
4
  dir_config("ffi_c")
5
+ IS_MAC = Config::CONFIG['host_os'] =~ /^darwin/
6
+ #if IS_MAC
7
+ # $CPPFLAGS << " -DMACOSX"
8
+ # find_header("ffi.h", "/usr/include/ffi")
9
+ #end
10
+ have_closure_alloc = have_library("ffi", "ffi_closure_alloc", [ "ffi.h" ])
11
+ $defs.push("-DHAVE_FFI_CLOSURE_ALLOC") if have_closure_alloc
12
+ libffi_ok = have_closure_alloc
13
+ $defs << "-DHAVE_LIBFFI" if libffi_ok
14
+ $defs << "-DHAVE_EXTCONF_H" if $defs.empty? # needed so create_header works
15
+
5
16
  create_makefile("ffi_c")
17
+ create_header("extconf.h")
6
18
  File.open("Makefile", "a") do |mf|
7
19
  mf.puts "include $(srcdir)/ffi.mk"
8
20
  if Config::CONFIG['host_os'] =~ /darwin/
@@ -10,4 +22,4 @@ File.open("Makefile", "a") do |mf|
10
22
  else
11
23
  mf.puts "include $(srcdir)/libffi.mk"
12
24
  end
13
- end
25
+ end unless libffi_ok
data/ext/ffi.c CHANGED
@@ -7,7 +7,10 @@
7
7
 
8
8
  #include "rbffi.h"
9
9
  #include "AbstractMemory.h"
10
+ #include "Pointer.h"
10
11
  #include "MemoryPointer.h"
12
+ #include "AutoPointer.h"
13
+ #include "NativeLibrary.h"
11
14
  #include "Platform.h"
12
15
  #include "Types.h"
13
16
 
@@ -37,6 +40,10 @@ Init_ffi_c() {
37
40
  rb_define_const(moduleNativeType, "STRING", INT2FIX(STRING));
38
41
  rb_define_const(moduleNativeType, "RBXSTRING", INT2FIX(RBXSTRING));
39
42
  rb_define_const(moduleNativeType, "CHAR_ARRAY", INT2FIX(CHAR_ARRAY));
43
+ rb_define_const(moduleNativeType, "BUFFER_IN", INT2FIX(BUFFER_IN));
44
+ rb_define_const(moduleNativeType, "BUFFER_OUT", INT2FIX(BUFFER_OUT));
45
+ rb_define_const(moduleNativeType, "BUFFER_INOUT", INT2FIX(BUFFER_INOUT));
46
+ rb_define_const(moduleNativeType, "VARARGS", INT2FIX(VARARGS));
40
47
  if (sizeof(long) == 4) {
41
48
  rb_define_const(moduleNativeType, "LONG", INT2FIX(INT32));
42
49
  rb_define_const(moduleNativeType, "ULONG", INT2FIX(UINT32));
@@ -46,9 +53,12 @@ Init_ffi_c() {
46
53
  }
47
54
  rb_FFI_Platform_Init();
48
55
  rb_FFI_AbstractMemory_Init();
56
+ rb_FFI_Pointer_Init();
57
+ rb_FFI_AutoPointer_Init();
49
58
  rb_FFI_MemoryPointer_Init();
50
59
  rb_FFI_Buffer_Init();
51
60
  rb_FFI_Callback_Init();
52
- rb_FFI_Invoker_Init();
61
+ rb_FFI_NativeLibrary_Init();
62
+ rb_FFI_Invoker_Init();
53
63
  }
54
64
 
data/ext/ffi.mk CHANGED
@@ -1,9 +1,9 @@
1
1
  # -*- makefile -*-
2
2
 
3
- CFLAGS += -Werror
4
- LIBS += -lpthread
3
+ CFLAGS += -Werror -Wformat
5
4
  INCFLAGS += -I$(BUILD_DIR) -I$(LIBFFI_BUILD_DIR)/include
6
- LOCAL_LIBS += $(LIBFFI)
5
+ CPPFLAGS += -I$(BUILD_DIR) -I$(LIBFFI_BUILD_DIR)/include
6
+ LOCAL_LIBS += $(LIBFFI) -lpthread
7
7
 
8
8
  FFI_MMAP_EXEC = -DFFI_MMAP_EXEC_WRIT
9
9
  FFI_CFLAGS = $(FFI_MMAP_EXEC) $(OFLAGS)
@@ -1,26 +1,36 @@
1
1
  # -*- makefile -*-
2
+ ARCHES :=
3
+ CCACHE := $(shell type -p ccache)
4
+ ifneq ($(findstring -arch ppc,$(CFLAGS)),)
5
+ ARCHES += ppc
6
+ endif
7
+ ifneq ($(findstring -arch i386,$(CFLAGS)),)
8
+ ARCHES += i386
9
+ endif
10
+ ifneq ($(findstring -arch x86_64,$(CFLAGS)),)
11
+ ARCHES += x86_64
12
+ endif
13
+ ifeq ($(ARCHES),)
14
+ ARCHES = $(shell arch)
15
+ endif
2
16
 
3
17
  build_ffi = \
4
18
  mkdir -p $(BUILD_DIR)/libffi-$(1); \
5
19
  (if [ ! -f $(BUILD_DIR)/libffi-$(1)/Makefile ]; then \
6
20
  echo "Configuring libffi for $(1)"; \
7
21
  cd $(BUILD_DIR)/libffi-$(1) && \
8
- env CFLAGS="-arch $(1) $(FFI_CFLAGS)" LDFLAGS="-arch $(1)" \
22
+ env CC="$(CCACHE) $(CC)" CFLAGS="-arch $(1) $(FFI_CFLAGS)" LDFLAGS="-arch $(1)" \
9
23
  $(FFI_CONFIGURE) --host=$(1)-apple-darwin > /dev/null; \
10
24
  fi); \
11
25
  env MACOSX_DEPLOYMENT_TARGET=10.4 $(MAKE) -C $(BUILD_DIR)/libffi-$(1)
12
26
 
13
27
  $(LIBFFI):
14
- @$(call build_ffi,i386)
15
- @$(call build_ffi,ppc)
16
- @$(call build_ffi,x86_64)
28
+ @for arch in $(ARCHES); do $(call build_ffi,$$arch);done
17
29
 
18
30
  # Assemble into a FAT (i386, ppc) library
19
31
  @mkdir -p $(BUILD_DIR)/libffi/.libs
20
32
  env MACOSX_DEPLOYMENT_TARGET=10.4 /usr/bin/libtool -static -o $@ \
21
- $(BUILD_DIR)/libffi-i386/.libs/libffi_convenience.a \
22
- $(BUILD_DIR)/libffi-x86_64/.libs/libffi_convenience.a \
23
- $(BUILD_DIR)/libffi-ppc/.libs/libffi_convenience.a
33
+ $(foreach arch, $(ARCHES),$(BUILD_DIR)/libffi-$(arch)/.libs/libffi_convenience.a)
24
34
  @mkdir -p $(LIBFFI_BUILD_DIR)/include
25
35
  $(RM) $(LIBFFI_BUILD_DIR)/include/ffi.h
26
36
  @( \
@@ -41,4 +51,5 @@ $(LIBFFI):
41
51
  printf "#include \"libffi-ppc/include/ffitarget.h\"\n";\
42
52
  printf "#endif\n";\
43
53
  ) > $(LIBFFI_BUILD_DIR)/include/ffitarget.h
44
-
54
+
55
+
@@ -0,0 +1,12 @@
1
+ require 'fileutils'
2
+ require "#{File.join(ENV['RUBYLIBDIR'], 'ffi', 'tools', 'types_generator.rb')}"
3
+ types_conf = File.join(ENV['RUBYLIBDIR'], 'ffi', 'types.conf')
4
+ task types_conf do |task|
5
+ options = {}
6
+ FileUtils.mkdir_p(File.dirname(task.name), { :mode => 0755 })
7
+ File.open(task.name, File::CREAT|File::TRUNC|File::RDWR, 0644) do |f|
8
+ f.puts FFI::TypesGenerator.generate(options)
9
+ end
10
+ end
11
+ task :default => types_conf do
12
+ end
@@ -0,0 +1,61 @@
1
+ module FFI
2
+ class AutoPointer < Pointer
3
+
4
+ # call-seq:
5
+ # AutoPointer.new(pointer, method) => the passed Method will be invoked at GC time
6
+ # AutoPointer.new(pointer, proc) => the passed Proc will be invoked at GC time (SEE WARNING BELOW!)
7
+ # AutoPointer.new(pointer) { |p| ... } => the passed block will be invoked at GC time (SEE WARNING BELOW!)
8
+ # AutoPointer.new(pointer) => the pointer's release() class method will be invoked at GC time
9
+ #
10
+ # WARNING: passing a proc _may_ cause your pointer to never be GC'd, unless you're careful to avoid trapping a reference to the pointer in the proc. See the test specs for examples.
11
+ # WARNING: passing a block will cause your pointer to never be GC'd. This is bad.
12
+ #
13
+ # Please note that the safest, and therefore preferred, calling
14
+ # idiom is to pass a Method as the second parameter. Example usage:
15
+ #
16
+ # class PointerHelper
17
+ # def self.release(pointer)
18
+ # ...
19
+ # end
20
+ # end
21
+ #
22
+ # p = AutoPointer.new(other_pointer, PointerHelper.method(:release))
23
+ #
24
+ # The above code will cause PointerHelper#release to be invoked at GC time.
25
+ #
26
+ # The last calling idiom (only one parameter) is generally only
27
+ # going to be useful if you subclass AutoPointer, and override
28
+ # release(), which by default does nothing.
29
+ #
30
+ def self.new(ptr, proc=nil, &block)
31
+ raise ArgumentError, "Invalid pointer" if ptr.nil? || !ptr.kind_of?(Pointer) \
32
+ || ptr.kind_of?(MemoryPointer) || ptr.kind_of?(AutoPointer)
33
+ free_lambda = if proc and proc.is_a? Method
34
+ finalize(ptr, self.method_to_proc(proc))
35
+ elsif proc and proc.is_a? Proc
36
+ finalize(ptr, proc)
37
+ else
38
+ finalize(ptr, self.method_to_proc(self.method(:release)))
39
+ end
40
+ ap = self.__alloc(ptr)
41
+ ObjectSpace.define_finalizer(ap, free_lambda)
42
+ ap
43
+ end
44
+ def self.release(ptr)
45
+ end
46
+
47
+ private
48
+ def self.finalize(ptr, proc)
49
+ #
50
+ # having a method create the lambda eliminates inadvertent
51
+ # references to the underlying object, which would prevent GC
52
+ # from running.
53
+ #
54
+ Proc.new { |*args| proc.call(ptr) }
55
+ end
56
+ def self.method_to_proc method
57
+ # again, can't call this inline as it causes a memory leak.
58
+ method.to_proc
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,8 @@
1
+ module FFI
2
+ def self.errno
3
+ FFI::LastError.error
4
+ end
5
+ def self.errno=(error)
6
+ FFI::LastError.error = error
7
+ end
8
+ end
@@ -1,30 +1,5 @@
1
1
  #
2
- # Version: CPL 1.0/GPL 2.0/LGPL 2.1
3
- #
4
- # The contents of this file are subject to the Common Public
5
- # License Version 1.0 (the "License"); you may not use this file
6
- # except in compliance with the License. You may obtain a copy of
7
- # the License at http://www.eclipse.org/legal/cpl-v10.html
8
- #
9
- # Software distributed under the License is distributed on an "AS
10
- # IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
11
- # implied. See the License for the specific language governing
12
- # rights and limitations under the License.
13
- #
14
2
  # Copyright (C) 2008 JRuby project
15
- #
16
- # Alternatively, the contents of this file may be used under the terms of
17
- # either of the GNU General Public License Version 2 or later (the "GPL"),
18
- # or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
19
- # in which case the provisions of the GPL or the LGPL are applicable instead
20
- # of those above. If you wish to allow use of your version of this file only
21
- # under the terms of either the GPL or the LGPL, and not to allow others to
22
- # use your version of this file under the terms of the CPL, indicate your
23
- # decision by deleting the provisions above and replace them with the notice
24
- # and other provisions required by the GPL or the LGPL. If you do not delete
25
- # the provisions above, a recipient may use your version of this file under
26
- # the terms of any one of the CPL, the GPL or the LGPL.
27
- #
28
3
  # Copyright (c) 2007, 2008 Evan Phoenix
29
4
  # All rights reserved.
30
5
  #
@@ -60,200 +35,62 @@ module FFI
60
35
  class SignatureError < NativeError; end
61
36
 
62
37
  class NotFoundError < NativeError
63
- def initialize(function, library)
64
- super("Function '#{function}' not found! (Looking in '#{library}' or this process)")
38
+ def initialize(function, *libraries)
39
+ super("Function '#{function}' not found in [#{libraries[0].nil? ? 'current process' : libraries.join(", ")}]")
65
40
  end
66
41
  end
67
42
  end
68
43
 
69
44
  require 'ffi/platform'
45
+ require 'ffi/types'
46
+ require 'ffi/library'
47
+ require 'ffi/errno'
70
48
  require 'ffi/memorypointer'
71
49
  require 'ffi/buffer'
72
50
  require 'ffi/struct'
51
+ require 'ffi/managedstruct'
73
52
  require 'ffi/callback'
53
+ require 'ffi/io'
54
+ require 'ffi/autopointer'
55
+ require 'ffi/variadic'
74
56
 
75
57
  module FFI
76
- TypeDefs = Hash.new
77
- def self.add_typedef(current, add)
78
- if current.kind_of? Integer
79
- code = current
80
- else
81
- code = TypeDefs[current]
82
- raise TypeError, "Unable to resolve type '#{current}'" unless code
83
- end
84
-
85
- TypeDefs[add] = code
86
- end
87
- def self.find_type(name)
88
- code = TypeDefs[name]
89
- code = name if !code && name.kind_of?(Integer)
90
- code = name if !code && name.kind_of?(FFI::Callback)
91
- raise TypeError, "Unable to resolve type '#{name}'" unless code
92
- return code
93
- end
94
-
95
- # Converts a char
96
- add_typedef(NativeType::INT8, :char)
97
-
98
- # Converts an unsigned char
99
- add_typedef(NativeType::UINT8, :uchar)
100
-
101
- # Converts an 8 bit int
102
- add_typedef(NativeType::INT8, :int8)
103
-
104
- # Converts an unsigned char
105
- add_typedef(NativeType::UINT8, :uint8)
106
-
107
- # Converts a short
108
- add_typedef(NativeType::INT16, :short)
109
-
110
- # Converts an unsigned short
111
- add_typedef(NativeType::UINT16, :ushort)
112
-
113
- # Converts a 16bit int
114
- add_typedef(NativeType::INT16, :int16)
115
-
116
- # Converts an unsigned 16 bit int
117
- add_typedef(NativeType::UINT16, :uint16)
118
-
119
- # Converts an int
120
- add_typedef(NativeType::INT32, :int)
121
-
122
- # Converts an unsigned int
123
- add_typedef(NativeType::UINT32, :uint)
124
-
125
- # Converts a 32 bit int
126
- add_typedef(NativeType::INT32, :int32)
127
-
128
- # Converts an unsigned 16 bit int
129
- add_typedef(NativeType::UINT32, :uint32)
130
-
131
- # Converts a long
132
- add_typedef(NativeType::LONG, :long)
133
-
134
- # Converts an unsigned long
135
- add_typedef(NativeType::ULONG, :ulong)
136
-
137
- # Converts a 64 bit int
138
- add_typedef(NativeType::INT64, :int64)
139
-
140
- # Converts an unsigned 64 bit int
141
- add_typedef(NativeType::UINT64, :uint64)
142
-
143
- # Converts a long long
144
- add_typedef(NativeType::INT64, :long_long)
145
-
146
- # Converts an unsigned long long
147
- add_typedef(NativeType::UINT64, :ulong_long)
148
-
149
- # Converts a float
150
- add_typedef(NativeType::FLOAT32, :float)
151
-
152
- # Converts a double
153
- add_typedef(NativeType::FLOAT64, :double)
154
-
155
- # Converts a pointer to opaque data
156
- add_typedef(NativeType::POINTER, :pointer)
157
-
158
- # For when a function has no return value
159
- add_typedef(NativeType::VOID, :void)
160
-
161
- # Converts NUL-terminated C strings
162
- add_typedef(NativeType::STRING, :string)
163
-
164
- # Use for a C struct with a char [] embedded inside.
165
- add_typedef(NativeType::CHAR_ARRAY, :char_array)
166
-
167
- TypeSizes = {
168
- 1 => :char,
169
- 2 => :short,
170
- 4 => :int,
171
- 8 => :long_long,
172
- }
173
58
 
174
- SizeTypes = {
175
- NativeType::INT8 => 1,
176
- NativeType::UINT8 => 1,
177
- NativeType::INT16 => 2,
178
- NativeType::UINT16 => 2,
179
- NativeType::INT32 => 4,
180
- NativeType::UINT32 => 4,
181
- NativeType::INT64 => 8,
182
- NativeType::UINT64 => 8,
183
- NativeType::FLOAT32 => 4,
184
- NativeType::FLOAT64 => 8,
185
- NativeType::LONG => FFI::Platform::LONG_SIZE / 8,
186
- NativeType::ULONG => FFI::Platform::LONG_SIZE / 8,
187
- NativeType::POINTER => FFI::Platform::ADDRESS_SIZE / 8,
188
- }
189
- def self.type_size(type)
190
- if sz = SizeTypes[find_type(type)]
191
- return sz
192
- end
193
- raise ArgumentError, "Unknown native type"
194
- end
195
- def self.create_invoker(lib, name, args, ret, convention = :default)
59
+ def self.map_library_name(lib)
196
60
  # Mangle the library name to reflect the native library naming conventions
197
- if lib
61
+ lib = Platform::LIBC if Platform::IS_LINUX && lib == 'c'
62
+ if lib && File.basename(lib) == lib
63
+ ext = ".#{Platform::LIBSUFFIX}"
198
64
  lib = Platform::LIBPREFIX + lib unless lib =~ /^#{Platform::LIBPREFIX}/
199
- lib += Platform::LIBSUFFIX unless lib =~ /#{Platform::LIBSUFFIX}/
65
+ lib += ext unless lib =~ /#{ext}/
200
66
  end
67
+ lib
68
+ end
69
+ def self.create_invoker(lib, name, args, ret, options = { :convention => :default })
201
70
  # Current artificial limitation based on JRuby::FFI limit
202
71
  raise SignatureError, 'FFI functions may take max 32 arguments!' if args.size > 32
203
-
204
- invoker = FFI::Invoker.new(lib, name, args.map { |e| find_type(e) },
205
- find_type(ret), convention.to_s)
206
- raise NotFoundError.new(name, lib) unless invoker
207
- return invoker
208
- end
209
- end
210
72
 
211
- module FFI::Library
212
- # TODO: Rubinius does *names here and saves the array. Multiple libs?
213
- def ffi_lib(name)
214
- @ffi_lib = name
215
- end
216
- def ffi_convention(convention)
217
- @ffi_convention = convention
218
- end
219
- ##
220
- # Attach C function +name+ to this module.
221
- #
222
- # If you want to provide an alternate name for the module function, supply
223
- # it after the +name+, otherwise the C function name will be used.#
224
- #
225
- # After the +name+, the C function argument types are provided as an Array.
226
- #
227
- # The C function return type is provided last.
73
+ # Open the library if needed
74
+ library = if lib.kind_of?(DynamicLibrary)
75
+ lib
76
+ elsif lib.kind_of?(String)
77
+ # Allow FFI.create_invoker to be called with a library name
78
+ DynamicLibrary.open(FFI.map_library_name(lib), DynamicLibrary::RTLD_LAZY)
79
+ elsif lib.nil?
80
+ FFI::Library::DEFAULT
81
+ else
82
+ raise LoadError, "Invalid library '#{lib}'"
83
+ end
84
+ function = library.find_symbol(name)
85
+ raise NotFoundError.new(name, library.name) unless function
228
86
 
229
- def attach_function(mname, a3, a4, a5=nil)
230
- cname, arg_types, ret_type = a5 ? [ a3, a4, a5 ] : [ mname.to_s, a3, a4 ]
231
- lib = @ffi_lib
232
- convention = @ffi_convention ? @ffi_convention : :default
233
- # Convert :foo to the native type
234
- arg_types.map! { |e|
235
- begin
236
- FFI.find_type(e)
237
- rescue FFI::TypeError
238
- @ffi_callbacks[e] || e
239
- end
240
- }
241
- invoker = FFI.create_invoker lib, cname.to_s, arg_types, ret_type, convention
242
- raise ArgumentError, "Unable to find function '#{cname}' to bind to #{self.name}.#{mname}" unless invoker
243
- #
244
- # Attach the invoker to this module as 'mname'.
245
- #
246
- self.module_eval <<-code
247
- @ffi_invoker_#{mname} = invoker
248
- def self.#{mname}(*args, &block)
249
- @ffi_invoker_#{mname}.call(*args, &block)
250
- end
251
- code
252
- invoker
253
- end
254
- def callback(name, args, ret)
255
- @ffi_callbacks = Hash.new unless @ffi_callbacks
256
- @ffi_callbacks[name] = FFI::Callback.new(FFI.find_type(ret), args.map { |e| FFI.find_type(e) })
87
+ args = args.map {|e| find_type(e) }
88
+ if args.length > 0 && args[args.length - 1] == FFI::NativeType::VARARGS
89
+ invoker = FFI::VariadicInvoker.new(library, function, args, find_type(ret), options)
90
+ else
91
+ invoker = FFI::Invoker.new(library, function, args, find_type(ret), options[:convention].to_s)
92
+ end
93
+ raise NotFoundError.new(name, library.name) unless invoker
94
+ return invoker
257
95
  end
258
96
  end
259
-