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.
- data/Rakefile +52 -29
- data/ext/AbstractMemory.c +72 -28
- data/ext/AutoPointer.c +54 -0
- data/ext/AutoPointer.h +18 -0
- data/ext/Buffer.c +21 -17
- data/ext/Callback.c +81 -43
- data/ext/Callback.h +1 -1
- data/ext/Invoker.c +465 -108
- data/ext/MemoryPointer.c +25 -90
- data/ext/NativeLibrary.c +90 -0
- data/ext/NativeLibrary.h +22 -0
- data/ext/Platform.c +21 -2
- data/ext/Pointer.c +107 -0
- data/ext/Pointer.h +21 -0
- data/ext/Types.c +16 -5
- data/ext/Types.h +3 -1
- data/ext/compat.h +14 -0
- data/ext/extconf.rb +13 -1
- data/ext/ffi.c +11 -1
- data/ext/ffi.mk +3 -3
- data/ext/libffi.darwin.mk +19 -8
- data/gen/Rakefile +12 -0
- data/lib/ffi/autopointer.rb +61 -0
- data/lib/ffi/errno.rb +8 -0
- data/lib/ffi/ffi.rb +38 -201
- data/lib/ffi/io.rb +7 -0
- data/lib/ffi/library.rb +116 -0
- data/lib/ffi/managedstruct.rb +55 -0
- data/lib/ffi/memorypointer.rb +3 -96
- data/lib/ffi/platform.rb +8 -5
- data/lib/ffi/pointer.rb +105 -0
- data/lib/ffi/struct.rb +97 -42
- data/lib/ffi/tools/const_generator.rb +177 -0
- data/lib/ffi/tools/generator.rb +58 -0
- data/lib/ffi/tools/generator_task.rb +35 -0
- data/lib/ffi/tools/struct_generator.rb +194 -0
- data/lib/ffi/tools/types_generator.rb +123 -0
- data/lib/ffi/types.rb +150 -0
- data/lib/ffi/variadic.rb +30 -0
- data/nbproject/Makefile-Default.mk +6 -3
- data/nbproject/Makefile-impl.mk +5 -5
- data/nbproject/Package-Default.bash +72 -0
- data/nbproject/configurations.xml +139 -25
- data/nbproject/private/configurations.xml +1 -1
- data/nbproject/project.xml +4 -0
- data/samples/gettimeofday.rb +6 -2
- data/samples/inotify.rb +59 -0
- data/samples/pty.rb +75 -0
- data/specs/buffer_spec.rb +64 -9
- data/specs/callback_spec.rb +308 -4
- data/specs/errno_spec.rb +13 -0
- data/specs/library_spec.rb +55 -0
- data/specs/managed_struct_spec.rb +40 -0
- data/specs/number_spec.rb +183 -0
- data/specs/pointer_spec.rb +126 -0
- data/specs/rbx/memory_pointer_spec.rb +7 -7
- data/specs/spec_helper.rb +7 -0
- data/specs/string_spec.rb +34 -0
- data/specs/struct_spec.rb +223 -0
- data/specs/typedef_spec.rb +48 -0
- data/specs/variadic_spec.rb +84 -0
- metadata +270 -237
data/ext/Types.c
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#include <ruby.h>
|
2
|
-
#include "
|
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
|
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
|
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
|
70
|
+
return rb_tainted_str_new2(*(char **) ptr);
|
60
71
|
case POINTER:
|
61
|
-
return
|
72
|
+
return rb_FFI_Pointer_new(*(void **) ptr);
|
62
73
|
default:
|
63
74
|
rb_raise(rb_eRuntimeError, "Unknown type: %d", type);
|
64
75
|
}
|
data/ext/Types.h
CHANGED
data/ext/compat.h
CHANGED
@@ -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 */
|
data/ext/extconf.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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)
|
data/ext/libffi.darwin.mk
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
+
|
data/gen/Rakefile
ADDED
@@ -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
|
data/lib/ffi/errno.rb
ADDED
data/lib/ffi/ffi.rb
CHANGED
@@ -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,
|
64
|
-
super("Function '#{function}' not found
|
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
|
-
|
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 +=
|
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
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
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
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
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
|
-
|