ffi 1.15.5-x64-mingw-ucrt
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +338 -0
- data/COPYING +49 -0
- data/Gemfile +14 -0
- data/LICENSE +24 -0
- data/LICENSE.SPECS +22 -0
- data/README.md +136 -0
- data/Rakefile +191 -0
- data/ffi.gemspec +42 -0
- data/lib/3.1/ffi_c.so +0 -0
- data/lib/ffi/abstract_memory.rb +44 -0
- data/lib/ffi/autopointer.rb +203 -0
- data/lib/ffi/buffer.rb +4 -0
- data/lib/ffi/callback.rb +4 -0
- data/lib/ffi/data_converter.rb +67 -0
- data/lib/ffi/enum.rb +296 -0
- data/lib/ffi/errno.rb +43 -0
- data/lib/ffi/ffi.rb +47 -0
- data/lib/ffi/io.rb +62 -0
- data/lib/ffi/library.rb +592 -0
- data/lib/ffi/managedstruct.rb +84 -0
- data/lib/ffi/memorypointer.rb +1 -0
- data/lib/ffi/platform/aarch64-darwin/types.conf +130 -0
- data/lib/ffi/platform/aarch64-freebsd/types.conf +128 -0
- data/lib/ffi/platform/aarch64-freebsd12/types.conf +181 -0
- data/lib/ffi/platform/aarch64-linux/types.conf +104 -0
- data/lib/ffi/platform/aarch64-openbsd/types.conf +134 -0
- data/lib/ffi/platform/arm-freebsd/types.conf +152 -0
- data/lib/ffi/platform/arm-freebsd12/types.conf +152 -0
- data/lib/ffi/platform/arm-linux/types.conf +132 -0
- data/lib/ffi/platform/i386-cygwin/types.conf +3 -0
- data/lib/ffi/platform/i386-darwin/types.conf +100 -0
- data/lib/ffi/platform/i386-freebsd/types.conf +152 -0
- data/lib/ffi/platform/i386-freebsd12/types.conf +152 -0
- data/lib/ffi/platform/i386-gnu/types.conf +107 -0
- data/lib/ffi/platform/i386-linux/types.conf +103 -0
- data/lib/ffi/platform/i386-netbsd/types.conf +126 -0
- data/lib/ffi/platform/i386-openbsd/types.conf +128 -0
- data/lib/ffi/platform/i386-solaris/types.conf +122 -0
- data/lib/ffi/platform/i386-windows/types.conf +52 -0
- data/lib/ffi/platform/ia64-linux/types.conf +104 -0
- data/lib/ffi/platform/mips-linux/types.conf +102 -0
- data/lib/ffi/platform/mips64-linux/types.conf +104 -0
- data/lib/ffi/platform/mips64el-linux/types.conf +104 -0
- data/lib/ffi/platform/mipsel-linux/types.conf +102 -0
- data/lib/ffi/platform/mipsisa32r6-linux/types.conf +102 -0
- data/lib/ffi/platform/mipsisa32r6el-linux/types.conf +102 -0
- data/lib/ffi/platform/mipsisa64r6-linux/types.conf +104 -0
- data/lib/ffi/platform/mipsisa64r6el-linux/types.conf +104 -0
- data/lib/ffi/platform/powerpc-aix/types.conf +180 -0
- data/lib/ffi/platform/powerpc-darwin/types.conf +100 -0
- data/lib/ffi/platform/powerpc-linux/types.conf +130 -0
- data/lib/ffi/platform/powerpc-openbsd/types.conf +156 -0
- data/lib/ffi/platform/powerpc64-linux/types.conf +104 -0
- data/lib/ffi/platform/powerpc64le-linux/types.conf +100 -0
- data/lib/ffi/platform/riscv64-linux/types.conf +104 -0
- data/lib/ffi/platform/s390-linux/types.conf +102 -0
- data/lib/ffi/platform/s390x-linux/types.conf +102 -0
- data/lib/ffi/platform/sparc-linux/types.conf +102 -0
- data/lib/ffi/platform/sparc-solaris/types.conf +128 -0
- data/lib/ffi/platform/sparc64-linux/types.conf +102 -0
- data/lib/ffi/platform/sparcv9-openbsd/types.conf +156 -0
- data/lib/ffi/platform/sparcv9-solaris/types.conf +128 -0
- data/lib/ffi/platform/x86_64-cygwin/types.conf +3 -0
- data/lib/ffi/platform/x86_64-darwin/types.conf +130 -0
- data/lib/ffi/platform/x86_64-dragonflybsd/types.conf +130 -0
- data/lib/ffi/platform/x86_64-freebsd/types.conf +128 -0
- data/lib/ffi/platform/x86_64-freebsd12/types.conf +158 -0
- data/lib/ffi/platform/x86_64-haiku/types.conf +117 -0
- data/lib/ffi/platform/x86_64-linux/types.conf +132 -0
- data/lib/ffi/platform/x86_64-msys/types.conf +119 -0
- data/lib/ffi/platform/x86_64-netbsd/types.conf +128 -0
- data/lib/ffi/platform/x86_64-openbsd/types.conf +134 -0
- data/lib/ffi/platform/x86_64-solaris/types.conf +122 -0
- data/lib/ffi/platform/x86_64-windows/types.conf +52 -0
- data/lib/ffi/platform.rb +185 -0
- data/lib/ffi/pointer.rb +167 -0
- data/lib/ffi/struct.rb +316 -0
- data/lib/ffi/struct_by_reference.rb +72 -0
- data/lib/ffi/struct_layout.rb +96 -0
- data/lib/ffi/struct_layout_builder.rb +227 -0
- data/lib/ffi/tools/const_generator.rb +232 -0
- data/lib/ffi/tools/generator.rb +105 -0
- data/lib/ffi/tools/generator_task.rb +32 -0
- data/lib/ffi/tools/struct_generator.rb +195 -0
- data/lib/ffi/tools/types_generator.rb +137 -0
- data/lib/ffi/types.rb +194 -0
- data/lib/ffi/union.rb +43 -0
- data/lib/ffi/variadic.rb +69 -0
- data/lib/ffi/version.rb +3 -0
- data/lib/ffi.rb +27 -0
- data/rakelib/ffi_gem_helper.rb +65 -0
- data/samples/getlogin.rb +8 -0
- data/samples/getpid.rb +8 -0
- data/samples/gettimeofday.rb +18 -0
- data/samples/hello.rb +8 -0
- data/samples/inotify.rb +60 -0
- data/samples/pty.rb +75 -0
- data/samples/qsort.rb +20 -0
- metadata +207 -0
data/lib/ffi/types.rb
ADDED
@@ -0,0 +1,194 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (C) 2008-2010 Wayne Meissner
|
3
|
+
# Copyright (c) 2007, 2008 Evan Phoenix
|
4
|
+
#
|
5
|
+
# This file is part of ruby-ffi.
|
6
|
+
#
|
7
|
+
# All rights reserved.
|
8
|
+
#
|
9
|
+
# Redistribution and use in source and binary forms, with or without
|
10
|
+
# modification, are permitted provided that the following conditions are met:
|
11
|
+
#
|
12
|
+
# * Redistributions of source code must retain the above copyright notice, this
|
13
|
+
# list of conditions and the following disclaimer.
|
14
|
+
# * Redistributions in binary form must reproduce the above copyright notice
|
15
|
+
# this list of conditions and the following disclaimer in the documentation
|
16
|
+
# and/or other materials provided with the distribution.
|
17
|
+
# * Neither the name of the Ruby FFI project nor the names of its contributors
|
18
|
+
# may be used to endorse or promote products derived from this software
|
19
|
+
# without specific prior written permission.
|
20
|
+
#
|
21
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
22
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
23
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
24
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
25
|
+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
26
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
27
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
28
|
+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
29
|
+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
30
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
31
|
+
#
|
32
|
+
|
33
|
+
# see {file:README}
|
34
|
+
module FFI
|
35
|
+
|
36
|
+
# @param [Type, DataConverter, Symbol] old type definition used by {FFI.find_type}
|
37
|
+
# @param [Symbol] add new type definition's name to add
|
38
|
+
# @return [Type]
|
39
|
+
# Add a definition type to type definitions.
|
40
|
+
def self.typedef(old, add)
|
41
|
+
TypeDefs[add] = self.find_type(old)
|
42
|
+
end
|
43
|
+
|
44
|
+
# (see FFI.typedef)
|
45
|
+
def self.add_typedef(old, add)
|
46
|
+
typedef old, add
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
# @param [Type, DataConverter, Symbol] name
|
51
|
+
# @param [Hash] type_map if nil, {FFI::TypeDefs} is used
|
52
|
+
# @return [Type]
|
53
|
+
# Find a type in +type_map+ ({FFI::TypeDefs}, by default) from
|
54
|
+
# a type objet, a type name (symbol). If +name+ is a {DataConverter},
|
55
|
+
# a new {Type::Mapped} is created.
|
56
|
+
def self.find_type(name, type_map = nil)
|
57
|
+
if name.is_a?(Type)
|
58
|
+
name
|
59
|
+
|
60
|
+
elsif type_map && type_map.has_key?(name)
|
61
|
+
type_map[name]
|
62
|
+
|
63
|
+
elsif TypeDefs.has_key?(name)
|
64
|
+
TypeDefs[name]
|
65
|
+
|
66
|
+
elsif name.is_a?(DataConverter)
|
67
|
+
(type_map || TypeDefs)[name] = Type::Mapped.new(name)
|
68
|
+
else
|
69
|
+
raise TypeError, "unable to resolve type '#{name}'"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# List of type definitions
|
74
|
+
TypeDefs.merge!({
|
75
|
+
# The C void type; only useful for function return types
|
76
|
+
:void => Type::VOID,
|
77
|
+
|
78
|
+
# C boolean type
|
79
|
+
:bool => Type::BOOL,
|
80
|
+
|
81
|
+
# C nul-terminated string
|
82
|
+
:string => Type::STRING,
|
83
|
+
|
84
|
+
# C signed char
|
85
|
+
:char => Type::CHAR,
|
86
|
+
# C unsigned char
|
87
|
+
:uchar => Type::UCHAR,
|
88
|
+
|
89
|
+
# C signed short
|
90
|
+
:short => Type::SHORT,
|
91
|
+
# C unsigned short
|
92
|
+
:ushort => Type::USHORT,
|
93
|
+
|
94
|
+
# C signed int
|
95
|
+
:int => Type::INT,
|
96
|
+
# C unsigned int
|
97
|
+
:uint => Type::UINT,
|
98
|
+
|
99
|
+
# C signed long
|
100
|
+
:long => Type::LONG,
|
101
|
+
|
102
|
+
# C unsigned long
|
103
|
+
:ulong => Type::ULONG,
|
104
|
+
|
105
|
+
# C signed long long integer
|
106
|
+
:long_long => Type::LONG_LONG,
|
107
|
+
|
108
|
+
# C unsigned long long integer
|
109
|
+
:ulong_long => Type::ULONG_LONG,
|
110
|
+
|
111
|
+
# C single precision float
|
112
|
+
:float => Type::FLOAT,
|
113
|
+
|
114
|
+
# C double precision float
|
115
|
+
:double => Type::DOUBLE,
|
116
|
+
|
117
|
+
# C long double
|
118
|
+
:long_double => Type::LONGDOUBLE,
|
119
|
+
|
120
|
+
# Native memory address
|
121
|
+
:pointer => Type::POINTER,
|
122
|
+
|
123
|
+
# 8 bit signed integer
|
124
|
+
:int8 => Type::INT8,
|
125
|
+
# 8 bit unsigned integer
|
126
|
+
:uint8 => Type::UINT8,
|
127
|
+
|
128
|
+
# 16 bit signed integer
|
129
|
+
:int16 => Type::INT16,
|
130
|
+
# 16 bit unsigned integer
|
131
|
+
:uint16 => Type::UINT16,
|
132
|
+
|
133
|
+
# 32 bit signed integer
|
134
|
+
:int32 => Type::INT32,
|
135
|
+
# 32 bit unsigned integer
|
136
|
+
:uint32 => Type::UINT32,
|
137
|
+
|
138
|
+
# 64 bit signed integer
|
139
|
+
:int64 => Type::INT64,
|
140
|
+
# 64 bit unsigned integer
|
141
|
+
:uint64 => Type::UINT64,
|
142
|
+
|
143
|
+
:buffer_in => Type::BUFFER_IN,
|
144
|
+
:buffer_out => Type::BUFFER_OUT,
|
145
|
+
:buffer_inout => Type::BUFFER_INOUT,
|
146
|
+
|
147
|
+
# Used in function prototypes to indicate the arguments are variadic
|
148
|
+
:varargs => Type::VARARGS,
|
149
|
+
})
|
150
|
+
|
151
|
+
# This will convert a pointer to a Ruby string (just like `:string`), but
|
152
|
+
# also allow to work with the pointer itself. This is useful when you want
|
153
|
+
# a Ruby string already containing a copy of the data, but also the pointer
|
154
|
+
# to the data for you to do something with it, like freeing it, in case the
|
155
|
+
# library handed the memory off to the caller (Ruby-FFI).
|
156
|
+
#
|
157
|
+
# It's {typedef}'d as +:strptr+.
|
158
|
+
class StrPtrConverter
|
159
|
+
extend DataConverter
|
160
|
+
native_type Type::POINTER
|
161
|
+
|
162
|
+
# @param [Pointer] val
|
163
|
+
# @param ctx not used
|
164
|
+
# @return [Array(String, Pointer)]
|
165
|
+
# Returns a [ String, Pointer ] tuple so the C memory for the string can be freed
|
166
|
+
def self.from_native(val, ctx)
|
167
|
+
[ val.null? ? nil : val.get_string(0), val ]
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
typedef(StrPtrConverter, :strptr)
|
172
|
+
|
173
|
+
# @param type +type+ is an instance of class accepted by {FFI.find_type}
|
174
|
+
# @return [Numeric]
|
175
|
+
# Get +type+ size, in bytes.
|
176
|
+
def self.type_size(type)
|
177
|
+
find_type(type).size
|
178
|
+
end
|
179
|
+
|
180
|
+
# Load all the platform dependent types
|
181
|
+
begin
|
182
|
+
File.open(File.join(Platform::CONF_DIR, 'types.conf'), "r") do |f|
|
183
|
+
prefix = "rbx.platform.typedef."
|
184
|
+
f.each_line { |line|
|
185
|
+
if line.index(prefix) == 0
|
186
|
+
new_type, orig_type = line.chomp.slice(prefix.length..-1).split(/\s*=\s*/)
|
187
|
+
typedef(orig_type.to_sym, new_type.to_sym)
|
188
|
+
end
|
189
|
+
}
|
190
|
+
end
|
191
|
+
typedef :pointer, :caddr_t
|
192
|
+
rescue Errno::ENOENT
|
193
|
+
end
|
194
|
+
end
|
data/lib/ffi/union.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (C) 2009 Andrea Fazzi <andrea.fazzi@alcacoop.it>
|
3
|
+
#
|
4
|
+
# This file is part of ruby-ffi.
|
5
|
+
#
|
6
|
+
# All rights reserved.
|
7
|
+
#
|
8
|
+
# Redistribution and use in source and binary forms, with or without
|
9
|
+
# modification, are permitted provided that the following conditions are met:
|
10
|
+
#
|
11
|
+
# * Redistributions of source code must retain the above copyright notice, this
|
12
|
+
# list of conditions and the following disclaimer.
|
13
|
+
# * Redistributions in binary form must reproduce the above copyright notice
|
14
|
+
# this list of conditions and the following disclaimer in the documentation
|
15
|
+
# and/or other materials provided with the distribution.
|
16
|
+
# * Neither the name of the Ruby FFI project nor the names of its contributors
|
17
|
+
# may be used to endorse or promote products derived from this software
|
18
|
+
# without specific prior written permission.
|
19
|
+
#
|
20
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
21
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
22
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
23
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
24
|
+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
25
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
26
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
27
|
+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
28
|
+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
29
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
30
|
+
#
|
31
|
+
|
32
|
+
require 'ffi/struct'
|
33
|
+
|
34
|
+
module FFI
|
35
|
+
|
36
|
+
class Union < FFI::Struct
|
37
|
+
def self.builder
|
38
|
+
b = StructLayoutBuilder.new
|
39
|
+
b.union = true
|
40
|
+
b
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/ffi/variadic.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (C) 2008, 2009 Wayne Meissner
|
3
|
+
# Copyright (C) 2009 Luc Heinrich
|
4
|
+
#
|
5
|
+
# This file is part of ruby-ffi.
|
6
|
+
#
|
7
|
+
# All rights reserved.
|
8
|
+
#
|
9
|
+
# Redistribution and use in source and binary forms, with or without
|
10
|
+
# modification, are permitted provided that the following conditions are met:
|
11
|
+
#
|
12
|
+
# * Redistributions of source code must retain the above copyright notice, this
|
13
|
+
# list of conditions and the following disclaimer.
|
14
|
+
# * Redistributions in binary form must reproduce the above copyright notice
|
15
|
+
# this list of conditions and the following disclaimer in the documentation
|
16
|
+
# and/or other materials provided with the distribution.
|
17
|
+
# * Neither the name of the Ruby FFI project nor the names of its contributors
|
18
|
+
# may be used to endorse or promote products derived from this software
|
19
|
+
# without specific prior written permission.
|
20
|
+
#
|
21
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
22
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
23
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
24
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
25
|
+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
26
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
27
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
28
|
+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
29
|
+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
30
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
31
|
+
#
|
32
|
+
|
33
|
+
module FFI
|
34
|
+
class VariadicInvoker
|
35
|
+
def call(*args, &block)
|
36
|
+
param_types = Array.new(@fixed)
|
37
|
+
param_values = Array.new
|
38
|
+
@fixed.each_with_index do |t, i|
|
39
|
+
param_values << args[i]
|
40
|
+
end
|
41
|
+
i = @fixed.length
|
42
|
+
while i < args.length
|
43
|
+
param_types << FFI.find_type(args[i], @type_map)
|
44
|
+
param_values << args[i + 1]
|
45
|
+
i += 2
|
46
|
+
end
|
47
|
+
invoke(param_types, param_values, &block)
|
48
|
+
end
|
49
|
+
|
50
|
+
#
|
51
|
+
# Attach the invoker to module +mod+ as +mname+
|
52
|
+
#
|
53
|
+
def attach(mod, mname)
|
54
|
+
invoker = self
|
55
|
+
params = "*args"
|
56
|
+
call = "call"
|
57
|
+
mod.module_eval <<-code
|
58
|
+
@@#{mname} = invoker
|
59
|
+
def self.#{mname}(#{params})
|
60
|
+
@@#{mname}.#{call}(#{params})
|
61
|
+
end
|
62
|
+
def #{mname}(#{params})
|
63
|
+
@@#{mname}.#{call}(#{params})
|
64
|
+
end
|
65
|
+
code
|
66
|
+
invoker
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
data/lib/ffi/version.rb
ADDED
data/lib/ffi.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
if RUBY_ENGINE == 'ruby'
|
2
|
+
begin
|
3
|
+
require RUBY_VERSION.split('.')[0, 2].join('.') + '/ffi_c'
|
4
|
+
rescue Exception
|
5
|
+
require 'ffi_c'
|
6
|
+
end
|
7
|
+
|
8
|
+
require 'ffi/ffi'
|
9
|
+
|
10
|
+
elsif RUBY_ENGINE == 'jruby' && (RUBY_ENGINE_VERSION.split('.').map(&:to_i) <=> [9, 2, 20]) >= 0
|
11
|
+
JRuby::Util.load_ext("org.jruby.ext.ffi.FFIService")
|
12
|
+
require 'ffi/ffi'
|
13
|
+
|
14
|
+
elsif RUBY_ENGINE == 'truffleruby' && (RUBY_ENGINE_VERSION.split('.').map(&:to_i) <=> [20, 1, 0]) >= 0
|
15
|
+
require 'truffleruby/ffi_backend'
|
16
|
+
require 'ffi/ffi'
|
17
|
+
|
18
|
+
else
|
19
|
+
# Remove the ffi gem dir from the load path, then reload the internal ffi implementation
|
20
|
+
$LOAD_PATH.delete(File.dirname(__FILE__))
|
21
|
+
$LOAD_PATH.delete(File.join(File.dirname(__FILE__), 'ffi'))
|
22
|
+
unless $LOADED_FEATURES.nil?
|
23
|
+
$LOADED_FEATURES.delete(__FILE__)
|
24
|
+
$LOADED_FEATURES.delete('ffi.rb')
|
25
|
+
end
|
26
|
+
require 'ffi.rb'
|
27
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
require 'bundler/gem_helper'
|
3
|
+
|
4
|
+
class FfiGemHelper < Bundler::GemHelper
|
5
|
+
attr_accessor :cross_platforms
|
6
|
+
|
7
|
+
def install
|
8
|
+
super
|
9
|
+
|
10
|
+
task "release:guard_clean" => ["release:update_history"]
|
11
|
+
|
12
|
+
task "release:update_history" do
|
13
|
+
update_history
|
14
|
+
end
|
15
|
+
|
16
|
+
task "release:rubygem_push" => ["gem:native", "gem:java"]
|
17
|
+
end
|
18
|
+
|
19
|
+
def hfile
|
20
|
+
"CHANGELOG.md"
|
21
|
+
end
|
22
|
+
|
23
|
+
def headline
|
24
|
+
'([^\w]*)(\d+\.\d+\.\d+(?:\.\w+)?)([^\w]+)([2Y][0Y][0-9Y][0-9Y]-[0-1M][0-9M]-[0-3D][0-9D])([^\w]*|$)'
|
25
|
+
end
|
26
|
+
|
27
|
+
def reldate
|
28
|
+
Time.now.strftime("%Y-%m-%d")
|
29
|
+
end
|
30
|
+
|
31
|
+
def update_history
|
32
|
+
hin = File.read(hfile)
|
33
|
+
hout = hin.sub(/#{headline}/) do
|
34
|
+
raise "#{hfile} isn't up-to-date for version #{version}" unless $2==version.to_s
|
35
|
+
$1 + $2 + $3 + reldate + $5
|
36
|
+
end
|
37
|
+
if hout != hin
|
38
|
+
Bundler.ui.confirm "Updating #{hfile} for release."
|
39
|
+
File.write(hfile, hout)
|
40
|
+
Rake::FileUtilsExt.sh "git", "commit", hfile, "-m", "Update release date in #{hfile}"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def tag_version
|
45
|
+
Bundler.ui.confirm "Tag release with annotation:"
|
46
|
+
m = File.read(hfile).match(/(?<annotation>#{headline}.*?)#{headline}/m) || raise("Unable to find release notes in #{hfile}")
|
47
|
+
Bundler.ui.info(m[:annotation].gsub(/^/, " "))
|
48
|
+
IO.popen(["git", "tag", "--file=-", version_tag], "w") do |fd|
|
49
|
+
fd.write m[:annotation]
|
50
|
+
end
|
51
|
+
yield if block_given?
|
52
|
+
rescue
|
53
|
+
Bundler.ui.error "Untagging #{version_tag} due to error."
|
54
|
+
sh_with_code "git tag -d #{version_tag}"
|
55
|
+
raise
|
56
|
+
end
|
57
|
+
|
58
|
+
def rubygem_push(path)
|
59
|
+
cross_platforms.each do |ruby_platform|
|
60
|
+
super(path.gsub(/\.gem\z/, "-#{ruby_platform}.gem"))
|
61
|
+
end
|
62
|
+
super(path.gsub(/\.gem\z/, "-java.gem"))
|
63
|
+
super(path)
|
64
|
+
end
|
65
|
+
end
|
data/samples/getlogin.rb
ADDED
data/samples/getpid.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
require 'rbconfig'
|
3
|
+
|
4
|
+
class Timeval < FFI::Struct
|
5
|
+
layout tv_sec: :ulong, tv_usec: :ulong
|
6
|
+
end
|
7
|
+
module LibC
|
8
|
+
extend FFI::Library
|
9
|
+
if FFI::Platform.windows?
|
10
|
+
ffi_lib RbConfig::CONFIG["LIBRUBY_SO"]
|
11
|
+
else
|
12
|
+
ffi_lib FFI::Library::LIBC
|
13
|
+
end
|
14
|
+
attach_function :gettimeofday, [ :pointer, :pointer ], :int
|
15
|
+
end
|
16
|
+
t = Timeval.new
|
17
|
+
LibC.gettimeofday(t.pointer, nil)
|
18
|
+
puts "t.tv_sec=#{t[:tv_sec]} t.tv_usec=#{t[:tv_usec]}"
|
data/samples/hello.rb
ADDED
data/samples/inotify.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
|
3
|
+
module Inotify
|
4
|
+
extend FFI::Library
|
5
|
+
ffi_lib FFI::Library::LIBC
|
6
|
+
class Event < FFI::Struct
|
7
|
+
layout \
|
8
|
+
:wd, :int,
|
9
|
+
:mask, :uint,
|
10
|
+
:cookie, :uint,
|
11
|
+
:len, :uint
|
12
|
+
end
|
13
|
+
attach_function :init, :inotify_init, [ ], :int
|
14
|
+
attach_function :add_watch, :inotify_add_watch, [ :int, :string, :uint ], :int
|
15
|
+
attach_function :rm_watch, :inotify_rm_watch, [ :int, :uint ], :int
|
16
|
+
attach_function :read, [ :int, :buffer_out, :uint ], :int
|
17
|
+
IN_ACCESS=0x00000001
|
18
|
+
IN_MODIFY=0x00000002
|
19
|
+
IN_ATTRIB=0x00000004
|
20
|
+
IN_CLOSE_WRITE=0x00000008
|
21
|
+
IN_CLOSE_NOWRITE=0x00000010
|
22
|
+
IN_CLOSE=(IN_CLOSE_WRITE | IN_CLOSE_NOWRITE)
|
23
|
+
IN_OPEN=0x00000020
|
24
|
+
IN_MOVED_FROM=0x00000040
|
25
|
+
IN_MOVED_TO=0x00000080
|
26
|
+
IN_MOVE= (IN_MOVED_FROM | IN_MOVED_TO)
|
27
|
+
IN_CREATE=0x00000100
|
28
|
+
IN_DELETE=0x00000200
|
29
|
+
IN_DELETE_SELF=0x00000400
|
30
|
+
IN_MOVE_SELF=0x00000800
|
31
|
+
# Events sent by the kernel.
|
32
|
+
IN_UNMOUNT=0x00002000
|
33
|
+
IN_Q_OVERFLOW=0x00004000
|
34
|
+
IN_IGNORED=0x00008000
|
35
|
+
IN_ONLYDIR=0x01000000
|
36
|
+
IN_DONT_FOLLOW=0x02000000
|
37
|
+
IN_MASK_ADD=0x20000000
|
38
|
+
IN_ISDIR=0x40000000
|
39
|
+
IN_ONESHOT=0x80000000
|
40
|
+
IN_ALL_EVENTS=(IN_ACCESS | IN_MODIFY | IN_ATTRIB | IN_CLOSE_WRITE \
|
41
|
+
| IN_CLOSE_NOWRITE | IN_OPEN | IN_MOVED_FROM \
|
42
|
+
| IN_MOVED_TO | IN_CREATE | IN_DELETE \
|
43
|
+
| IN_DELETE_SELF | IN_MOVE_SELF)
|
44
|
+
|
45
|
+
end
|
46
|
+
if $0 == __FILE__
|
47
|
+
fd = Inotify.init
|
48
|
+
puts "fd=#{fd}"
|
49
|
+
wd = Inotify.add_watch(fd, "/tmp/", Inotify::IN_ALL_EVENTS)
|
50
|
+
fp = FFI::IO.for_fd(fd)
|
51
|
+
puts "wfp=#{fp}"
|
52
|
+
while true
|
53
|
+
buf = FFI::Buffer.alloc_out(Inotify::Event.size + 4096, 1, false)
|
54
|
+
ev = Inotify::Event.new buf
|
55
|
+
ready = IO.select([ fp ], nil, nil, nil)
|
56
|
+
n = Inotify.read(fd, buf, buf.total)
|
57
|
+
puts "Read #{n} bytes from inotify fd"
|
58
|
+
puts "event.wd=#{ev[:wd]} mask=#{ev[:mask]} len=#{ev[:len]} name=#{ev[:len] > 0 ? buf.get_string(16) : 'unknown'}"
|
59
|
+
end
|
60
|
+
end
|
data/samples/pty.rb
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
|
3
|
+
module PTY
|
4
|
+
private
|
5
|
+
module LibC
|
6
|
+
extend FFI::Library
|
7
|
+
ffi_lib FFI::Library::LIBC
|
8
|
+
attach_function :forkpty, [ :buffer_out, :buffer_out, :buffer_in, :buffer_in ], :int
|
9
|
+
attach_function :openpty, [ :buffer_out, :buffer_out, :buffer_out, :buffer_in, :buffer_in ], :int
|
10
|
+
attach_function :login_tty, [ :int ], :int
|
11
|
+
attach_function :close, [ :int ], :int
|
12
|
+
attach_function :strerror, [ :int ], :string
|
13
|
+
attach_function :fork, [], :int
|
14
|
+
attach_function :execv, [ :string, :buffer_in ], :int
|
15
|
+
attach_function :execvp, [ :string, :buffer_in ], :int
|
16
|
+
attach_function :dup2, [ :int, :int ], :int
|
17
|
+
attach_function :dup, [ :int ], :int
|
18
|
+
end
|
19
|
+
Buffer = FFI::Buffer
|
20
|
+
def self.build_args(args)
|
21
|
+
cmd = args.shift
|
22
|
+
cmd_args = args.map do |arg|
|
23
|
+
MemoryPointer.from_string(arg)
|
24
|
+
end
|
25
|
+
exec_args = MemoryPointer.new(:pointer, 1 + cmd_args.length + 1)
|
26
|
+
exec_cmd = MemoryPointer.from_string(cmd)
|
27
|
+
exec_args[0].put_pointer(0, exec_cmd)
|
28
|
+
cmd_args.each_with_index do |arg, i|
|
29
|
+
exec_args[i + 1].put_pointer(0, arg)
|
30
|
+
end
|
31
|
+
[ cmd, exec_args ]
|
32
|
+
end
|
33
|
+
public
|
34
|
+
def self.getpty(*args)
|
35
|
+
mfdp = Buffer.new :int
|
36
|
+
name = Buffer.new 1024
|
37
|
+
#
|
38
|
+
# All the execv setup is done in the parent, since doing anything other than
|
39
|
+
# execv in the child after fork is really flakey
|
40
|
+
#
|
41
|
+
exec_cmd, exec_args = build_args(args)
|
42
|
+
pid = LibC.forkpty(mfdp, name, nil, nil)
|
43
|
+
raise "forkpty failed: #{LibC.strerror(FFI.errno)}" if pid < 0
|
44
|
+
if pid == 0
|
45
|
+
LibC.execvp(exec_cmd, exec_args)
|
46
|
+
exit 1
|
47
|
+
end
|
48
|
+
masterfd = mfdp.get_int(0)
|
49
|
+
rfp = FFI::IO.for_fd(masterfd, "r")
|
50
|
+
wfp = FFI::IO.for_fd(LibC.dup(masterfd), "w")
|
51
|
+
if block_given?
|
52
|
+
yield rfp, wfp, pid
|
53
|
+
rfp.close unless rfp.closed?
|
54
|
+
wfp.close unless wfp.closed?
|
55
|
+
else
|
56
|
+
[ rfp, wfp, pid ]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
def self.spawn(*args, &block)
|
60
|
+
self.getpty("/bin/sh", "-c", args[0], &block)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
module LibC
|
64
|
+
extend FFI::Library
|
65
|
+
attach_function :close, [ :int ], :int
|
66
|
+
attach_function :write, [ :int, :buffer_in, :ulong ], :long
|
67
|
+
attach_function :read, [ :int, :buffer_out, :ulong ], :long
|
68
|
+
end
|
69
|
+
PTY.getpty("/bin/ls", "-alR", "/") { |rfd, wfd, pid|
|
70
|
+
#PTY.spawn("ls -laR /") { |rfd, wfd, pid|
|
71
|
+
puts "child pid=#{pid}"
|
72
|
+
while !rfd.eof? && (buf = rfd.gets)
|
73
|
+
puts "child: '#{buf.strip}'"
|
74
|
+
end
|
75
|
+
}
|
data/samples/qsort.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
|
3
|
+
module LibC
|
4
|
+
extend FFI::Library
|
5
|
+
ffi_lib FFI::Library::LIBC
|
6
|
+
callback :qsort_cmp, [ :pointer, :pointer ], :int
|
7
|
+
attach_function :qsort, [ :pointer, :ulong, :ulong, :qsort_cmp ], :int
|
8
|
+
end
|
9
|
+
|
10
|
+
p = FFI::MemoryPointer.new(:int, 2)
|
11
|
+
p.put_array_of_int32(0, [ 2, 1 ])
|
12
|
+
puts "ptr=#{p.inspect}"
|
13
|
+
puts "Before qsort #{p.get_array_of_int32(0, 2).join(', ')}"
|
14
|
+
LibC.qsort(p, 2, 4) do |p1, p2|
|
15
|
+
i1 = p1.get_int32(0)
|
16
|
+
i2 = p2.get_int32(0)
|
17
|
+
puts "In block: comparing #{i1} and #{i2}"
|
18
|
+
i1 < i2 ? -1 : i1 > i2 ? 1 : 0
|
19
|
+
end
|
20
|
+
puts "After qsort #{p.get_array_of_int32(0, 2).join(', ')}"
|