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
@@ -0,0 +1,123 @@
|
|
1
|
+
require 'tempfile'
|
2
|
+
|
3
|
+
module FFI
|
4
|
+
class TypesGenerator
|
5
|
+
|
6
|
+
##
|
7
|
+
# Maps different C types to the C type representations we use
|
8
|
+
|
9
|
+
TYPE_MAP = {
|
10
|
+
"char" => :char,
|
11
|
+
"signed char" => :char,
|
12
|
+
"__signed char" => :char,
|
13
|
+
"unsigned char" => :uchar,
|
14
|
+
|
15
|
+
"short" => :short,
|
16
|
+
"signed short" => :short,
|
17
|
+
"signed short int" => :short,
|
18
|
+
"unsigned short" => :ushort,
|
19
|
+
"unsigned short int" => :ushort,
|
20
|
+
|
21
|
+
"int" => :int,
|
22
|
+
"signed int" => :int,
|
23
|
+
"unsigned int" => :uint,
|
24
|
+
|
25
|
+
"long" => :long,
|
26
|
+
"long int" => :long,
|
27
|
+
"signed long" => :long,
|
28
|
+
"signed long int" => :long,
|
29
|
+
"unsigned long" => :ulong,
|
30
|
+
"unsigned long int" => :ulong,
|
31
|
+
"long unsigned int" => :ulong,
|
32
|
+
|
33
|
+
"long long" => :long_long,
|
34
|
+
"long long int" => :long_long,
|
35
|
+
"signed long long" => :long_long,
|
36
|
+
"signed long long int" => :long_long,
|
37
|
+
"unsigned long long" => :ulong_long,
|
38
|
+
"unsigned long long int" => :ulong_long,
|
39
|
+
|
40
|
+
"char *" => :string,
|
41
|
+
"void *" => :pointer,
|
42
|
+
}
|
43
|
+
|
44
|
+
def self.generate(options = {})
|
45
|
+
typedefs = nil
|
46
|
+
Tempfile.open 'ffi_types_generator' do |io|
|
47
|
+
io.puts <<-C
|
48
|
+
#include <sys/types.h>
|
49
|
+
#include <sys/socket.h>
|
50
|
+
#include <sys/resource.h>
|
51
|
+
C
|
52
|
+
|
53
|
+
io.close
|
54
|
+
typedefs = `gcc -E -x c #{options[:cppflags]} -D_DARWIN_USE_64_BIT_INODE -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -c #{io.path}`
|
55
|
+
end
|
56
|
+
|
57
|
+
code = ""
|
58
|
+
|
59
|
+
typedefs.each_line do |type|
|
60
|
+
# We only care about single line typedef
|
61
|
+
next unless type =~ /typedef/
|
62
|
+
# Ignore unions or structs
|
63
|
+
next if type =~ /union|struct/
|
64
|
+
|
65
|
+
# strip off the starting typedef and ending ;
|
66
|
+
type.gsub!(/^(.*typedef\s*)/, "")
|
67
|
+
type.gsub!(/\s*;\s*$/, "")
|
68
|
+
|
69
|
+
parts = type.split(/\s+/)
|
70
|
+
def_type = parts.join(" ")
|
71
|
+
|
72
|
+
# GCC does mapping with __attribute__ stuf, also see
|
73
|
+
# http://hal.cs.berkeley.edu/cil/cil016.html section 16.2.7. Problem
|
74
|
+
# with this is that the __attribute__ stuff can either occur before or
|
75
|
+
# after the new type that is defined...
|
76
|
+
if type =~ /__attribute__/
|
77
|
+
if parts.last =~ /__QI__|__HI__|__SI__|__DI__|__word__/
|
78
|
+
|
79
|
+
# In this case, the new type is BEFORE __attribute__ we need to
|
80
|
+
# find the final_type as the type before the part that starts with
|
81
|
+
# __attribute__
|
82
|
+
final_type = ""
|
83
|
+
parts.each do |p|
|
84
|
+
break if p =~ /__attribute__/
|
85
|
+
final_type = p
|
86
|
+
end
|
87
|
+
else
|
88
|
+
final_type = parts.pop
|
89
|
+
end
|
90
|
+
|
91
|
+
def_type = case type
|
92
|
+
when /__QI__/ then "char"
|
93
|
+
when /__HI__/ then "short"
|
94
|
+
when /__SI__/ then "int"
|
95
|
+
when /__DI__/ then "long long"
|
96
|
+
when /__word__/ then "long"
|
97
|
+
else "int"
|
98
|
+
end
|
99
|
+
|
100
|
+
def_type = "unsigned #{def_type}" if type =~ /unsigned/
|
101
|
+
else
|
102
|
+
final_type = parts.pop
|
103
|
+
def_type = parts.join(" ")
|
104
|
+
end
|
105
|
+
|
106
|
+
if type = TYPE_MAP[def_type]
|
107
|
+
code << "rbx.platform.typedef.#{final_type} = #{type}\n"
|
108
|
+
TYPE_MAP[final_type] = TYPE_MAP[def_type]
|
109
|
+
else
|
110
|
+
# Fallback to an ordinary pointer if we don't know the type
|
111
|
+
if def_type =~ /\*/
|
112
|
+
code << "rbx.platform.typedef.#{final_type} = pointer\n"
|
113
|
+
TYPE_MAP[final_type] = :pointer
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
code
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
data/lib/ffi/types.rb
ADDED
@@ -0,0 +1,150 @@
|
|
1
|
+
module FFI
|
2
|
+
TypeDefs = Hash.new
|
3
|
+
def self.add_typedef(current, add)
|
4
|
+
if current.kind_of? Integer
|
5
|
+
code = current
|
6
|
+
else
|
7
|
+
code = TypeDefs[current]
|
8
|
+
raise TypeError, "Unable to resolve type '#{current}'" unless code
|
9
|
+
end
|
10
|
+
|
11
|
+
TypeDefs[add] = code
|
12
|
+
end
|
13
|
+
def self.find_type(name, type_map = nil)
|
14
|
+
type_map = TypeDefs if type_map.nil?
|
15
|
+
code = type_map[name]
|
16
|
+
code = name if !code && name.kind_of?(Integer)
|
17
|
+
code = name if !code && name.kind_of?(FFI::CallbackInfo)
|
18
|
+
raise TypeError, "Unable to resolve type '#{name}'" unless code
|
19
|
+
return code
|
20
|
+
end
|
21
|
+
|
22
|
+
# Converts a char
|
23
|
+
add_typedef(NativeType::INT8, :char)
|
24
|
+
|
25
|
+
# Converts an unsigned char
|
26
|
+
add_typedef(NativeType::UINT8, :uchar)
|
27
|
+
|
28
|
+
# Converts an 8 bit int
|
29
|
+
add_typedef(NativeType::INT8, :int8)
|
30
|
+
|
31
|
+
# Converts an unsigned char
|
32
|
+
add_typedef(NativeType::UINT8, :uint8)
|
33
|
+
|
34
|
+
# Converts a short
|
35
|
+
add_typedef(NativeType::INT16, :short)
|
36
|
+
|
37
|
+
# Converts an unsigned short
|
38
|
+
add_typedef(NativeType::UINT16, :ushort)
|
39
|
+
|
40
|
+
# Converts a 16bit int
|
41
|
+
add_typedef(NativeType::INT16, :int16)
|
42
|
+
|
43
|
+
# Converts an unsigned 16 bit int
|
44
|
+
add_typedef(NativeType::UINT16, :uint16)
|
45
|
+
|
46
|
+
# Converts an int
|
47
|
+
add_typedef(NativeType::INT32, :int)
|
48
|
+
|
49
|
+
# Converts an unsigned int
|
50
|
+
add_typedef(NativeType::UINT32, :uint)
|
51
|
+
|
52
|
+
# Converts a 32 bit int
|
53
|
+
add_typedef(NativeType::INT32, :int32)
|
54
|
+
|
55
|
+
# Converts an unsigned 16 bit int
|
56
|
+
add_typedef(NativeType::UINT32, :uint32)
|
57
|
+
|
58
|
+
# Converts a long
|
59
|
+
add_typedef(NativeType::LONG, :long)
|
60
|
+
|
61
|
+
# Converts an unsigned long
|
62
|
+
add_typedef(NativeType::ULONG, :ulong)
|
63
|
+
|
64
|
+
# Converts a 64 bit int
|
65
|
+
add_typedef(NativeType::INT64, :int64)
|
66
|
+
|
67
|
+
# Converts an unsigned 64 bit int
|
68
|
+
add_typedef(NativeType::UINT64, :uint64)
|
69
|
+
|
70
|
+
# Converts a long long
|
71
|
+
add_typedef(NativeType::INT64, :long_long)
|
72
|
+
|
73
|
+
# Converts an unsigned long long
|
74
|
+
add_typedef(NativeType::UINT64, :ulong_long)
|
75
|
+
|
76
|
+
# Converts a float
|
77
|
+
add_typedef(NativeType::FLOAT32, :float)
|
78
|
+
|
79
|
+
# Converts a double
|
80
|
+
add_typedef(NativeType::FLOAT64, :double)
|
81
|
+
|
82
|
+
# Converts a pointer to opaque data
|
83
|
+
add_typedef(NativeType::POINTER, :pointer)
|
84
|
+
|
85
|
+
# For when a function has no return value
|
86
|
+
add_typedef(NativeType::VOID, :void)
|
87
|
+
|
88
|
+
# Converts NUL-terminated C strings
|
89
|
+
add_typedef(NativeType::STRING, :string)
|
90
|
+
|
91
|
+
# Converts FFI::Buffer objects
|
92
|
+
add_typedef(NativeType::BUFFER_IN, :buffer_in)
|
93
|
+
add_typedef(NativeType::BUFFER_OUT, :buffer_out)
|
94
|
+
add_typedef(NativeType::BUFFER_INOUT, :buffer_inout)
|
95
|
+
add_typedef(NativeType::VARARGS, :varargs)
|
96
|
+
|
97
|
+
# Use for a C struct with a char [] embedded inside.
|
98
|
+
add_typedef(NativeType::CHAR_ARRAY, :char_array)
|
99
|
+
|
100
|
+
TypeSizes = {
|
101
|
+
1 => :char,
|
102
|
+
2 => :short,
|
103
|
+
4 => :int,
|
104
|
+
8 => :long_long,
|
105
|
+
}
|
106
|
+
SizeTypes = {
|
107
|
+
NativeType::INT8 => 1,
|
108
|
+
NativeType::UINT8 => 1,
|
109
|
+
NativeType::INT16 => 2,
|
110
|
+
NativeType::UINT16 => 2,
|
111
|
+
NativeType::INT32 => 4,
|
112
|
+
NativeType::UINT32 => 4,
|
113
|
+
NativeType::INT64 => 8,
|
114
|
+
NativeType::UINT64 => 8,
|
115
|
+
NativeType::FLOAT32 => 4,
|
116
|
+
NativeType::FLOAT64 => 8,
|
117
|
+
NativeType::LONG => FFI::Platform::LONG_SIZE / 8,
|
118
|
+
NativeType::ULONG => FFI::Platform::LONG_SIZE / 8,
|
119
|
+
NativeType::POINTER => FFI::Platform::ADDRESS_SIZE / 8,
|
120
|
+
}
|
121
|
+
|
122
|
+
def self.size_to_type(size)
|
123
|
+
if sz = TypeSizes[size]
|
124
|
+
return sz
|
125
|
+
end
|
126
|
+
|
127
|
+
# Be like C, use int as the default type size.
|
128
|
+
return :int
|
129
|
+
end
|
130
|
+
def self.type_size(type)
|
131
|
+
if sz = SizeTypes[find_type(type)]
|
132
|
+
return sz
|
133
|
+
end
|
134
|
+
raise ArgumentError, "Unknown native type"
|
135
|
+
end
|
136
|
+
|
137
|
+
# Load all the platform dependent types
|
138
|
+
begin
|
139
|
+
File.open(File.join(FFI::Platform::CONF_DIR, 'types.conf'), "r") do |f|
|
140
|
+
prefix = "rbx.platform.typedef."
|
141
|
+
f.each_line { |line|
|
142
|
+
if line.index(prefix) == 0
|
143
|
+
new_type, orig_type = line.chomp.slice(prefix.length..-1).split(/\s*=\s*/)
|
144
|
+
add_typedef(orig_type.to_sym, new_type.to_sym)
|
145
|
+
end
|
146
|
+
}
|
147
|
+
end
|
148
|
+
rescue Errno::ENOENT
|
149
|
+
end
|
150
|
+
end
|
data/lib/ffi/variadic.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
module FFI
|
2
|
+
class VariadicInvoker
|
3
|
+
def VariadicInvoker.new(library, function, arg_types, ret_type, options)
|
4
|
+
invoker = self.__new(library, function, ret_type, options[:convention].to_s)
|
5
|
+
invoker.init(arg_types, options[:type_map])
|
6
|
+
invoker
|
7
|
+
end
|
8
|
+
def init(arg_types, type_map)
|
9
|
+
@fixed = Array.new
|
10
|
+
@type_map = type_map
|
11
|
+
arg_types.each_with_index do |type, i|
|
12
|
+
@fixed << type unless type == FFI::NativeType::VARARGS
|
13
|
+
end
|
14
|
+
end
|
15
|
+
def call(*args, &block)
|
16
|
+
param_types = Array.new(@fixed)
|
17
|
+
param_values = Array.new
|
18
|
+
@fixed.each_with_index do |t, i|
|
19
|
+
param_values << args[i]
|
20
|
+
end
|
21
|
+
i = @fixed.length
|
22
|
+
while i < args.length
|
23
|
+
param_types << FFI.find_type(args[i], @type_map)
|
24
|
+
param_values << args[i + 1]
|
25
|
+
i += 2
|
26
|
+
end
|
27
|
+
invoke(param_types, param_values, &block)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -17,11 +17,14 @@ CCC=g++
|
|
17
17
|
CXX=g++
|
18
18
|
FC=
|
19
19
|
|
20
|
+
# Macros
|
21
|
+
PLATFORM=GNU-MacOSX
|
22
|
+
|
20
23
|
# Include project Makefile
|
21
24
|
include ruby-ffi-Makefile.mk
|
22
25
|
|
23
26
|
# Object Directory
|
24
|
-
OBJECTDIR=build/Default
|
27
|
+
OBJECTDIR=build/Default/${PLATFORM}
|
25
28
|
|
26
29
|
# Object Files
|
27
30
|
OBJECTFILES=
|
@@ -41,14 +44,14 @@ LDLIBSOPTIONS=
|
|
41
44
|
|
42
45
|
# Build Targets
|
43
46
|
.build-conf: ${BUILD_SUBPROJECTS}
|
44
|
-
cd . &&
|
47
|
+
cd . && rake compile
|
45
48
|
|
46
49
|
# Subprojects
|
47
50
|
.build-subprojects:
|
48
51
|
|
49
52
|
# Clean Targets
|
50
53
|
.clean-conf:
|
51
|
-
cd . &&
|
54
|
+
cd . && rake clean
|
52
55
|
|
53
56
|
# Subprojects
|
54
57
|
.clean-subprojects:
|
data/nbproject/Makefile-impl.mk
CHANGED
@@ -35,19 +35,19 @@ ALLCONFS=Default
|
|
35
35
|
|
36
36
|
|
37
37
|
# build
|
38
|
-
.build-impl: .validate-impl .depcheck-impl
|
38
|
+
.build-impl: .build-pre .validate-impl .depcheck-impl
|
39
39
|
@#echo "=> Running $@... Configuration=$(CONF)"
|
40
40
|
${MAKE} -f nbproject/Makefile-${CONF}.mk SUBPROJECTS=${SUBPROJECTS} .build-conf
|
41
41
|
|
42
42
|
|
43
43
|
# clean
|
44
|
-
.clean-impl: .validate-impl .depcheck-impl
|
44
|
+
.clean-impl: .clean-pre .validate-impl .depcheck-impl
|
45
45
|
@#echo "=> Running $@... Configuration=$(CONF)"
|
46
46
|
${MAKE} -f nbproject/Makefile-${CONF}.mk SUBPROJECTS=${SUBPROJECTS} .clean-conf
|
47
47
|
|
48
48
|
|
49
49
|
# clobber
|
50
|
-
.clobber-impl: .depcheck-impl
|
50
|
+
.clobber-impl: .clobber-pre .depcheck-impl
|
51
51
|
@#echo "=> Running $@..."
|
52
52
|
for CONF in ${ALLCONFS}; \
|
53
53
|
do \
|
@@ -55,7 +55,7 @@ ALLCONFS=Default
|
|
55
55
|
done
|
56
56
|
|
57
57
|
# all
|
58
|
-
.all-impl: .depcheck-impl
|
58
|
+
.all-impl: .all-pre .depcheck-impl
|
59
59
|
@#echo "=> Running $@..."
|
60
60
|
for CONF in ${ALLCONFS}; \
|
61
61
|
do \
|
@@ -92,7 +92,7 @@ ALLCONFS=Default
|
|
92
92
|
|
93
93
|
|
94
94
|
# help
|
95
|
-
.help-impl:
|
95
|
+
.help-impl: .help-pre
|
96
96
|
@echo "This makefile supports the following configurations:"
|
97
97
|
@echo " ${ALLCONFS}"
|
98
98
|
@echo ""
|
@@ -0,0 +1,72 @@
|
|
1
|
+
#!/bin/bash -x
|
2
|
+
|
3
|
+
#
|
4
|
+
# Generated - do not edit!
|
5
|
+
#
|
6
|
+
|
7
|
+
# Macros
|
8
|
+
TOP=`pwd`
|
9
|
+
PLATFORM=GNU-MacOSX
|
10
|
+
TMPDIR=build/Default/${PLATFORM}/tmp-packaging
|
11
|
+
TMPDIRNAME=tmp-packaging
|
12
|
+
OUTPUT_PATH=MissingOutputInProject
|
13
|
+
OUTPUT_BASENAME=MissingOutputInProject
|
14
|
+
PACKAGE_TOP_DIR=ruby-ffi/
|
15
|
+
|
16
|
+
# Functions
|
17
|
+
function checkReturnCode
|
18
|
+
{
|
19
|
+
rc=$?
|
20
|
+
if [ $rc != 0 ]
|
21
|
+
then
|
22
|
+
exit $rc
|
23
|
+
fi
|
24
|
+
}
|
25
|
+
function makeDirectory
|
26
|
+
# $1 directory path
|
27
|
+
# $2 permission (optional)
|
28
|
+
{
|
29
|
+
mkdir -p "$1"
|
30
|
+
checkReturnCode
|
31
|
+
if [ "$2" != "" ]
|
32
|
+
then
|
33
|
+
chmod $2 "$1"
|
34
|
+
checkReturnCode
|
35
|
+
fi
|
36
|
+
}
|
37
|
+
function copyFileToTmpDir
|
38
|
+
# $1 from-file path
|
39
|
+
# $2 to-file path
|
40
|
+
# $3 permission
|
41
|
+
{
|
42
|
+
cp "$1" "$2"
|
43
|
+
checkReturnCode
|
44
|
+
if [ "$3" != "" ]
|
45
|
+
then
|
46
|
+
chmod $3 "$2"
|
47
|
+
checkReturnCode
|
48
|
+
fi
|
49
|
+
}
|
50
|
+
|
51
|
+
# Setup
|
52
|
+
cd "${TOP}"
|
53
|
+
mkdir -p dist/Default/${PLATFORM}/package
|
54
|
+
rm -rf ${TMPDIR}
|
55
|
+
mkdir -p ${TMPDIR}
|
56
|
+
|
57
|
+
# Copy files and create directories and links
|
58
|
+
cd "${TOP}"
|
59
|
+
makeDirectory ${TMPDIR}/ruby-ffi/bin
|
60
|
+
copyFileToTmpDir "${OUTPUT_PATH}" "${TMPDIR}/${PACKAGE_TOP_DIR}bin/${OUTPUT_BASENAME}" 0755
|
61
|
+
|
62
|
+
|
63
|
+
# Generate tar file
|
64
|
+
cd "${TOP}"
|
65
|
+
rm -f dist/Default/${PLATFORM}/package/ruby-ffi.tar
|
66
|
+
cd ${TMPDIR}
|
67
|
+
tar -vcf ../../../../dist/Default/${PLATFORM}/package/ruby-ffi.tar *
|
68
|
+
checkReturnCode
|
69
|
+
|
70
|
+
# Cleanup
|
71
|
+
cd "${TOP}"
|
72
|
+
rm -rf ${TMPDIR}
|