ffi-compiler 0.0.3 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -33,13 +33,13 @@ Example
33
33
  long
34
34
  example(void)
35
35
  {
36
- return 0xdeadbeef;
36
+ return 0xdeadbeef;
37
37
  }
38
38
 
39
39
  ###### ext/Rakefile
40
- require 'ffi-compiler/task'
40
+ require 'ffi-compiler/compile_task'
41
41
 
42
- FFI::Compiler::Task.new('example') do |c|
42
+ FFI::Compiler::CompileTask.new('example') do |c|
43
43
  c.have_header?('stdio.h', '/usr/local/include')
44
44
  c.have_func?('puts')
45
45
  c.have_library?('z')
data/ffi-compiler.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'ffi-compiler'
3
- s.version = '0.0.3'
3
+ s.version = '0.1.0'
4
4
  s.author = 'Wayne Meissner'
5
5
  s.email = 'wmeissner@gmail.com'
6
6
  s.homepage = 'http://wiki.github.com/ffi/ffi'
@@ -0,0 +1,216 @@
1
+ require 'rake'
2
+ require 'rake/tasklib'
3
+ require 'rake/clean'
4
+ require 'ffi'
5
+ require 'tmpdir'
6
+ require 'rbconfig'
7
+ require_relative 'platform'
8
+
9
+ module FFI
10
+ module Compiler
11
+ DEFAULT_CFLAGS = %w(-fexceptions -O -fno-omit-frame-pointer -fno-strict-aliasing)
12
+ DEFAULT_LDFLAGS = %w(-fexceptions)
13
+
14
+ class CompileTask < Rake::TaskLib
15
+ attr_reader :cflags, :cxxflags, :ldflags, :libs, :platform
16
+
17
+ def initialize(name)
18
+ @name = File.basename(name)
19
+ @ext_dir = File.dirname(name)
20
+ @defines = []
21
+ @include_paths = []
22
+ @library_paths = []
23
+ @libraries = []
24
+ @headers = []
25
+ @functions = []
26
+ @cflags = DEFAULT_CFLAGS.dup
27
+ @cxxflags = DEFAULT_CFLAGS.dup
28
+ @ldflags = DEFAULT_LDFLAGS.dup
29
+ @libs = []
30
+ @platform = Platform.system
31
+ @exports = []
32
+
33
+ yield self if block_given?
34
+ define_task!
35
+ end
36
+
37
+ def have_func?(func)
38
+ main = <<-C_FILE
39
+ extern void #{func}();
40
+ int main(int argc, char **argv) { #{func}(); return 0; }
41
+ C_FILE
42
+
43
+ if try_compile(main)
44
+ @functions << func
45
+ return true
46
+ end
47
+ false
48
+ end
49
+
50
+ def have_header?(header, *paths)
51
+ try_header(header, @include_paths) || try_header(header, paths)
52
+ end
53
+
54
+ def have_library?(libname, *paths)
55
+ try_library(libname, paths: @library_paths) || try_library(libname, paths: paths)
56
+ end
57
+
58
+ def have_library(lib, func = nil, headers = nil, &b)
59
+ try_library(lib, function: func, headers: headers, paths: @library_paths)
60
+ end
61
+
62
+ def find_library(lib, func, *paths)
63
+ try_library(lib, function: func, paths: @library_paths) || try_library(libname, function: func, paths: paths)
64
+ end
65
+
66
+ def export(rb_file)
67
+ @exports << { :rb_file => rb_file, :header => File.join(@ext_dir, File.basename(rb_file).sub(/\.rb$/, '.h')) }
68
+ end
69
+
70
+ private
71
+ def define_task!
72
+ pic_flags = %w(-fPIC)
73
+ so_flags = []
74
+
75
+ if @platform.mac?
76
+ pic_flags = []
77
+ so_flags << '-bundle'
78
+
79
+ elsif @platform.name =~ /linux/
80
+ so_flags << "-shared -Wl,-soname,#{lib_name}"
81
+
82
+ else
83
+ so_flags << '-shared'
84
+ end
85
+ so_flags = so_flags.join(' ')
86
+
87
+ out_dir = "#{@platform.arch}-#{@platform.os}"
88
+ if @ext_dir != '.'
89
+ out_dir = File.join(@ext_dir, out_dir)
90
+ end
91
+
92
+ directory(out_dir)
93
+ CLOBBER.include(out_dir)
94
+
95
+ lib_name = File.join(out_dir, Platform.system.map_library_name(@name))
96
+
97
+ iflags = @include_paths.uniq.map { |p| "-I#{p}" }
98
+ defines = @functions.uniq.map { |f| "-DHAVE_#{f.upcase}=1" }
99
+ defines << @headers.uniq.map { |h| "-DHAVE_#{h.upcase.sub(/\./, '_')}=1" }
100
+
101
+ cflags = (@cflags + pic_flags + iflags + defines).join(' ')
102
+ cxxflags = (@cxxflags + @cflags + pic_flags + iflags + defines).join(' ')
103
+ ld_flags = (@library_paths.map { |path| "-L#{path}" } + @ldflags).join(' ')
104
+ libs = (@libraries.map { |l| "-l#{l}" } + @libs).join(' ')
105
+
106
+ src_files = FileList["#{@ext_dir}/**/*.{c,cpp}"]
107
+ obj_files = src_files.ext('.o').map { |f| File.join(out_dir, f.sub(/^#{@ext_dir}\//, '')) }
108
+ ld = src_files.detect { |f| f =~ /\.cpp$/ } ? cxx : cc
109
+
110
+ src_files.each do |src|
111
+ obj_file = File.join(out_dir, src.sub(/\.(c|cpp)$/, '.o').sub(/^#{@ext_dir}\//, ''))
112
+ if src =~ /\.c$/
113
+ file obj_file => [ src, File.dirname(obj_file) ] do |t|
114
+ sh "#{cc} #{cflags} -o #{t.name} -c #{t.prerequisites[0]}"
115
+ end
116
+
117
+ else
118
+ file obj_file => [ src, File.dirname(obj_file) ] do |t|
119
+ sh "#{cxx} #{cxxflags} -o #{t.name} -c #{t.prerequisites[0]}"
120
+ end
121
+ end
122
+
123
+ CLEAN.include(obj_file)
124
+ end
125
+
126
+ desc "Build dynamic library"
127
+ file lib_name => obj_files do |t|
128
+ sh "#{ld} #{so_flags} -o #{t.name} #{t.prerequisites.join(' ')} #{ld_flags} #{libs}"
129
+ end
130
+ CLEAN.include(lib_name)
131
+
132
+ @exports.each do |e|
133
+ desc "Export #{e[:rb_file]}"
134
+ file e[:header] => [ e[:rb_file] ] do |t|
135
+ ruby "-I#{File.join(File.dirname(__FILE__), 'fake_ffi')} #{File.join(File.dirname(__FILE__), 'exporter.rb')} #{t.prerequisites[0]} #{t.name}"
136
+ end
137
+
138
+ obj_files.each { |o| file o => [ e[:header] ] }
139
+ CLEAN.include(e[:header])
140
+
141
+ desc "Export API headers"
142
+ task :api_headers => [ e[:header] ]
143
+ end
144
+
145
+ task :default => [ lib_name ]
146
+ task :package => [ :api_headers ]
147
+ end
148
+
149
+ def try_header(header, paths)
150
+ main = <<-C_FILE
151
+ #include <#{header}>
152
+ int main(int argc, char **argv) { return 0; }
153
+ C_FILE
154
+
155
+ if paths.empty? && try_compile(main)
156
+ @headers << header
157
+ return true
158
+ end
159
+
160
+ paths.each do |path|
161
+ if try_compile(main, "-I#{path}")
162
+ @include_paths << path
163
+ @headers << header
164
+ return true
165
+ end
166
+ end
167
+ false
168
+ end
169
+
170
+
171
+ def try_library(libname, options = {})
172
+ func = options[:function] || 'main'
173
+ paths = options[:paths] || ''
174
+ main = <<-C_FILE
175
+ #{(options[:headers] || []).map {|h| "#include <#{h}>"}.join('\n')}
176
+ extern int #{func}();
177
+ int main() { return #{func}(); }
178
+ C_FILE
179
+
180
+ if paths.empty? && try_compile(main)
181
+ @libraries << libname
182
+ return true
183
+ end
184
+
185
+ paths.each do |path|
186
+ if try_compile(main, "-L#{path}", "-l#{libname}")
187
+ @library_paths << path
188
+ @libraries << libname
189
+ end
190
+ end
191
+ end
192
+
193
+ def try_compile(src, *opts)
194
+ Dir.mktmpdir do |dir|
195
+ path = File.join(dir, 'ffi-test.c')
196
+ File.open(path, 'w') do |f|
197
+ f << src
198
+ end
199
+ begin
200
+ return system "#{cc} #{opts.join(' ')} -o #{File.join(dir, 'ffi-test')} #{path} >& /dev/null"
201
+ rescue
202
+ return false
203
+ end
204
+ end
205
+ end
206
+
207
+ def cc
208
+ @cc ||= (ENV['CC'] || RbConfig::CONFIG['CC'] || 'cc')
209
+ end
210
+
211
+ def cxx
212
+ @cxx ||= (ENV['CXX'] || RbConfig::CONFIG['CXX'] || 'c++')
213
+ end
214
+ end
215
+ end
216
+ end
@@ -0,0 +1,49 @@
1
+ require 'rake'
2
+ require 'rake/tasklib'
3
+ require 'rake/clean'
4
+
5
+ module FFI
6
+ module Compiler
7
+ class ExportTask < Rake::TaskLib
8
+
9
+ def initialize(rb_dir, out_dir, options = {})
10
+ @rb_dir = rb_dir
11
+ @out_dir = out_dir
12
+ @gem_spec = options[:gem_spec]
13
+ @exports = []
14
+
15
+ if block_given?
16
+ yield self
17
+ define_tasks!
18
+ end
19
+ end
20
+
21
+ def export(rb_file)
22
+ @exports << { :rb_file => File.join(@rb_dir, rb_file), :header => File.join(@out_dir, File.basename(rb_file).sub(/\.rb$/, '.h')) }
23
+ end
24
+
25
+ def export_all
26
+ Dir["#@rb_dir/**/*rb"].each do |rb_file|
27
+ @exports << { :rb_file => rb_file, :header => File.join(@out_dir, File.basename(rb_file).sub(/\.rb$/, '.h')) }
28
+ end
29
+ end
30
+
31
+ private
32
+ def define_tasks!
33
+ @exports.each do |e|
34
+ file e[:header] => [ e[:rb_file] ] do |t|
35
+ ruby "-I#{File.join(File.dirname(__FILE__), 'fake_ffi')} #{File.join(File.dirname(__FILE__), 'exporter.rb')} #{t.prerequisites[0]} #{t.name}"
36
+ end
37
+ CLEAN.include(e[:header])
38
+
39
+ desc "Export API headers"
40
+ task :api_headers => [ e[:header] ]
41
+ @gem_spec.files << e[:header] unless @gem_spec.nil?
42
+ end
43
+
44
+ task :gem => [ :api_headers ] unless @gem_spec.nil?
45
+ end
46
+
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,4 @@
1
+ require 'ffi'
2
+
3
+ load ARGV[0]
4
+ FFI.exporter.dump(ARGV[1])
@@ -0,0 +1,8 @@
1
+ module FFI
2
+ module Compiler
3
+ module Loader
4
+ def self.find(*args)
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,170 @@
1
+ module FFI
2
+
3
+ def self.exporter=(exporter)
4
+ @@exporter = exporter
5
+ end
6
+
7
+ def self.exporter
8
+ @@exporter
9
+ end
10
+
11
+ class Type
12
+ attr_reader :name
13
+ def initialize(name)
14
+ @name = name
15
+ end
16
+ end
17
+
18
+ class StructByReference < Type
19
+ def initialize(struct_class)
20
+ super("struct #{struct_class.to_s.gsub('::', '_')} *")
21
+ end
22
+ end
23
+
24
+ class StructByValue < Type
25
+ def initialize(struct_class)
26
+ super("struct #{struct_class.to_s.gsub('::', '_')}")
27
+ end
28
+ end
29
+
30
+ PrimitiveTypes = {
31
+ :char => 'char',
32
+ :uchar => 'unsigned char',
33
+ :short => 'short',
34
+ :ushort => 'unsigned short',
35
+ :int => 'int',
36
+ :uint => 'unsigned int',
37
+ :long => 'long',
38
+ :ulong => 'unsigned long',
39
+ :float => 'float',
40
+ :double => 'double',
41
+ :pointer => 'void *',
42
+ :string => 'const char *',
43
+ }
44
+
45
+ TypeMap = {}
46
+ def self.find_type(type)
47
+ return type if type.is_a?(Type)
48
+
49
+ t = TypeMap[type]
50
+ return t unless t.nil?
51
+
52
+ if PrimitiveTypes.has_key?(type)
53
+ return TypeMap[type] = Type.new(PrimitiveTypes[type])
54
+ end
55
+ raise TypeError.new("cannot resolve type #{type}")
56
+ end
57
+
58
+ class Exporter
59
+ attr_reader :mod, :functions
60
+
61
+ def initialize(mod)
62
+ @mod = mod
63
+ @functions = []
64
+ @structs = []
65
+ end
66
+
67
+ def attach(mname, fname, result_type, param_types)
68
+ @functions << { mname: mname, fname: fname, result_type: result_type, params: param_types.dup }
69
+ end
70
+
71
+ def struct(name, fields)
72
+ @structs << { name: name, fields: fields.dup }
73
+ end
74
+
75
+ def dump(out_file)
76
+ File.open(out_file, 'w') do |f|
77
+ guard = File.basename(out_file).upcase.gsub('.', '_').gsub('/', '_')
78
+ f.puts <<-HEADER
79
+ #ifndef #{guard}
80
+ #define #{guard} 1
81
+
82
+ #ifndef RBFFI_EXPORT
83
+ # ifdef __cplusplus
84
+ # define RBFFI_EXPORT extern "C"
85
+ # else
86
+ # define RBFFI_EXPORT
87
+ # endif
88
+ #endif
89
+
90
+ HEADER
91
+
92
+ @structs.each do |s|
93
+ f.puts "struct #{s[:name].gsub('::', '_')} {"
94
+ s[:fields].each do |field|
95
+ f.puts "#{' ' * 4}#{field[:type].name} #{field[:name].to_s};"
96
+ end
97
+ f.puts '};'
98
+ f.puts
99
+ end
100
+ @functions.each do |fn|
101
+ param_string = fn[:params].empty? ? 'void' : fn[:params].map(&:name).join(', ')
102
+ f.puts "RBFFI_EXPORT #{fn[:result_type].name} #{fn[:fname]}(#{param_string});"
103
+ end
104
+ f.puts <<-EPILOG
105
+
106
+ #endif /* #{guard} */
107
+ EPILOG
108
+ end
109
+ end
110
+
111
+ end
112
+
113
+ module Library
114
+ def self.extended(mod)
115
+ FFI.exporter = Exporter.new(mod)
116
+ end
117
+
118
+ def attach_function(*args)
119
+ FFI.exporter.attach(args[0], args[0], find_type(args[2]), args[1].map { |t| find_type(t) })
120
+ end
121
+
122
+ def ffi_lib(*args)
123
+
124
+ end
125
+
126
+ TypeMap = {}
127
+ def find_type(type)
128
+ t = TypeMap[type]
129
+ return t unless t.nil?
130
+
131
+ if type.is_a?(Class) && type < Struct
132
+ return TypeMap[type] = StructByReference.new(type)
133
+ end
134
+
135
+ TypeMap[type] = FFI.find_type(type)
136
+ end
137
+ end
138
+
139
+ class Struct
140
+ def self.layout(*args)
141
+ fields = []
142
+ i = 0
143
+ while i < args.length
144
+ fields << { name: args[i], type: find_type(args[i+1]) }
145
+ i += 2
146
+ end
147
+ FFI.exporter.struct(self.to_s, fields)
148
+ end
149
+
150
+ TypeMap = {}
151
+ def self.find_type(type)
152
+ t = TypeMap[type]
153
+ return t unless t.nil?
154
+
155
+ if type.is_a?(Class) && type < Struct
156
+ return TypeMap[type] = StructByValue.new(type)
157
+ end
158
+
159
+ TypeMap[type] = FFI.find_type(type)
160
+ end
161
+
162
+ def self.by_value
163
+ StructByValue.new(self)
164
+ end
165
+
166
+ def self.by_ref
167
+ StructByReference.new(self)
168
+ end
169
+ end
170
+ end
@@ -1,14 +1,15 @@
1
1
  require 'pathname'
2
2
  require 'ffi'
3
+ require_relative 'platform'
3
4
 
4
5
  module FFI
5
6
  module Compiler
6
7
  module Loader
7
8
  def self.find(name, start_path = nil)
8
- library = FFI.map_library_name(name)
9
+ library = Platform.system.map_library_name(name)
9
10
  root = false
10
11
  Pathname.new(start_path || File.dirname(caller[0].split(/:/)[0])).ascend do |path|
11
- Dir.glob("#{path}/**/#{library}") do |f|
12
+ Dir.glob("#{path}/**/{#{FFI::Platform::ARCH}-#{FFI::Platform::OS}/#{library},#{library}}") do |f|
12
13
  return f
13
14
  end
14
15
 
@@ -0,0 +1,29 @@
1
+ module FFI::Compiler
2
+ class Platform
3
+ LIBSUFFIX = FFI::Platform.mac? ? 'bundle' : FFI::Platform::LIBSUFFIX
4
+
5
+ def self.system
6
+ @@system ||= Platform.new
7
+ end
8
+
9
+ def map_library_name(name)
10
+ "#{FFI::Platform::LIBPREFIX}#{name}.#{LIBSUFFIX}"
11
+ end
12
+
13
+ def arch
14
+ FFI::Platform::ARCH
15
+ end
16
+
17
+ def os
18
+ FFI::Platform::OS
19
+ end
20
+
21
+ def name
22
+ FFI::Platform.name
23
+ end
24
+
25
+ def mac?
26
+ FFI::Platform.mac?
27
+ end
28
+ end
29
+ end
@@ -1,167 +1,15 @@
1
+ require 'rake'
1
2
  require 'rake/tasklib'
2
3
  require 'rake/clean'
3
4
  require 'ffi'
4
5
  require 'tmpdir'
5
6
  require 'rbconfig'
7
+ require_relative 'compile_task'
6
8
 
7
9
  module FFI
8
- class Compiler
9
- DEFAULT_CFLAGS = %w(-fexceptions -O -fno-omit-frame-pointer -fno-strict-aliasing)
10
- DEFAULT_LDFLAGS = %w(-fexceptions)
11
-
12
- class Task < Rake::TaskLib
13
- attr_reader :cflags, :cxxflags, :ldflags, :libs
14
-
15
- def initialize(name)
16
- @name = File.basename(name)
17
- @defines = []
18
- @include_paths = []
19
- @library_paths = []
20
- @libraries = []
21
- @headers = []
22
- @functions = []
23
- @cflags = DEFAULT_CFLAGS.dup
24
- @cxxflags = DEFAULT_CFLAGS.dup
25
- @ldflags = DEFAULT_LDFLAGS.dup
26
- @libs = []
27
-
28
- yield self if block_given?
29
- define_task!
30
- end
31
-
32
- def have_func?(func)
33
- main = <<-C_FILE
34
- extern void #{func}();
35
- int main(int argc, char **argv) { #{func}(); return 0; }
36
- C_FILE
37
-
38
- if try_compile(main)
39
- @functions << func
40
- return true
41
- end
42
- false
43
- end
44
-
45
- def have_header?(header, *paths)
46
- try_header(header, @include_paths) || try_header(header, paths)
47
- end
48
-
49
- def have_library?(libname, *paths)
50
- try_library(libname, @library_paths) || try_library(libname, paths)
51
- end
52
-
53
- private
54
- def define_task!
55
- pic_flags = %w(-fPIC)
56
- so_flags = []
57
-
58
- if FFI::Platform.mac?
59
- pic_flags = []
60
- so_flags << '-dynamiclib'
61
-
62
- elsif FFI::Platform.name =~ /linux/
63
- so_flags << "-shared -Wl,-soname,#{lib_name}"
64
-
65
- else
66
- so_flags << '-shared'
67
- end
68
- so_flags = so_flags.join(' ')
69
-
70
- lib_name = FFI.map_library_name(@name)
71
-
72
- iflags = @include_paths.uniq.map { |p| "-I#{p}" }
73
- defines = @functions.uniq.map { |f| "-DHAVE_#{f.upcase}=1" }
74
- defines << @headers.uniq.map { |h| "-DHAVE_#{h.upcase.sub(/\./, '_')}=1" }
75
-
76
- cflags = (@cflags + pic_flags + iflags + defines).join(' ')
77
- cxxflags = (@cxxflags + @cflags + pic_flags + iflags + defines).join(' ')
78
- ld_flags = (@library_paths.map { |path| "-L#{path}" } + @ldflags).join(' ')
79
- libs = (@libraries.map { |l| "-l#{l}" } + @libs).join(' ')
80
-
81
- src_files = FileList['*.{c,cpp}']
82
- obj_files = src_files.ext '.o'
83
- ld = src_files.detect { |f| f =~ /\.cpp$/ } ? cxx : cc
84
-
85
- CLEAN.include(obj_files)
86
-
87
- rule '.o' => '.c' do |t|
88
- sh "#{cc} #{cflags} -o #{t.name} -c #{t.source}"
89
- end
90
-
91
- rule '.o' => '.cpp' do |t|
92
- sh "#{cxx} #{cxxflags} -o #{t.name} -c #{t.source}"
93
- end
94
-
95
- desc "Build dynamic library"
96
- file lib_name => obj_files do |t|
97
- sh "#{ld} #{so_flags} -o #{t.name} #{t.prerequisites.join(' ')} #{ld_flags} #{libs}"
98
- end
99
- CLEAN.include(lib_name)
100
-
101
- task :default => [ lib_name ]
102
- end
103
-
104
- def try_header(header, paths)
105
- main = <<-C_FILE
106
- #include <#{header}>
107
- int main(int argc, char **argv) { return 0; }
108
- C_FILE
109
-
110
- if paths.empty? && try_compile(main)
111
- @headers << header
112
- return true
113
- end
114
-
115
- paths.each do |path|
116
- if try_compile(main, "-I#{path}")
117
- @include_paths << path
118
- @headers << header
119
- return true
120
- end
121
- end
122
- false
123
- end
124
-
125
-
126
- def try_library(libname, paths)
127
- main = <<-C_FILE
128
- int main(int argc, char **argv) { return 0; }
129
- C_FILE
130
-
131
- if paths.empty? && try_compile(main)
132
- @libraries << libname
133
- return true
134
- end
135
-
136
- paths.each do |path|
137
- if try_compile(main, "-L#{path}", "-l#{libname}")
138
- @library_paths << path
139
- @libraries << libname
140
- end
141
- end
142
- end
143
-
144
- def try_compile(src, *opts)
145
- Dir.mktmpdir do |dir|
146
- path = File.join(dir, 'ffi-test.c')
147
- File.open(path, 'w') do |f|
148
- f << src
149
- end
150
- begin
151
- return system "#{cc} #{opts.join(' ')} -o #{File.join(dir, 'ffi-test')} #{path} >& /dev/null"
152
- rescue
153
- return false
154
- end
155
- end
156
- end
157
-
158
- def cc
159
- @cc ||= (ENV['CC'] || RbConfig::CONFIG['CC'] || 'cc')
160
- end
161
-
162
- def cxx
163
- @cxx ||= (ENV['CXX'] || RbConfig::CONFIG['CXX'] || 'c++')
164
- end
10
+ module Compiler
11
+ class Task < CompileTask
12
+ warn "#{self} is deprecated"
165
13
  end
166
14
  end
167
15
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ffi-compiler
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-01-19 00:00:00.000000000 Z
12
+ date: 2013-01-28 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -69,7 +69,13 @@ files:
69
69
  - README.md
70
70
  - Rakefile
71
71
  - LICENSE
72
+ - lib/ffi-compiler/compile_task.rb
73
+ - lib/ffi-compiler/export_task.rb
74
+ - lib/ffi-compiler/exporter.rb
75
+ - lib/ffi-compiler/fake_ffi/ffi-compiler/loader.rb
76
+ - lib/ffi-compiler/fake_ffi/ffi.rb
72
77
  - lib/ffi-compiler/loader.rb
78
+ - lib/ffi-compiler/platform.rb
73
79
  - lib/ffi-compiler/task.rb
74
80
  homepage: http://wiki.github.com/ffi/ffi
75
81
  licenses: