ffi-compiler 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,16 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'ffi-compiler'
3
+ s.version = '0.0.1'
4
+ s.author = 'Wayne Meissner'
5
+ s.email = 'wmeissner@gmail.com'
6
+ s.homepage = 'http://wiki.github.com/ffi/ffi'
7
+ s.summary = 'Ruby FFI Rakefile generator'
8
+ s.description = 'Ruby FFI library'
9
+ s.files = %w(ffi-compiler.gemspec) + Dir.glob("{lib,spec}/**/*")
10
+ s.has_rdoc = false
11
+ s.license = 'Apache 2.0'
12
+ s.required_ruby_version = '>= 1.9.3'
13
+ s.add_dependency 'rake'
14
+ s.add_dependency 'ffi', '>= 1.0.0'
15
+ s.add_development_dependency 'rspec'
16
+ end
@@ -0,0 +1,168 @@
1
+ require 'ffi'
2
+ require 'tmpdir'
3
+
4
+ module FFI
5
+ class Compiler
6
+ def initialize(name, &block)
7
+ @name = name
8
+ @defines = []
9
+ @include_paths = []
10
+ @library_paths = []
11
+ @libraries = []
12
+ @headers = []
13
+ @functions = []
14
+
15
+ if block_given?
16
+ yield self
17
+ create_rakefile!
18
+ end
19
+ end
20
+
21
+ def have_func?(func)
22
+ main = <<-C_FILE
23
+ extern void #{func}();
24
+ int main(int argc, char **argv) { #{func}(); return 0; }
25
+ C_FILE
26
+
27
+ if try_compile(main)
28
+ @functions << func
29
+ return true
30
+ end
31
+ false
32
+ end
33
+
34
+ def have_header?(header, *paths)
35
+ try_header(header, @include_paths) || try_header(header, paths)
36
+ end
37
+
38
+ def have_library?(libname, *paths)
39
+ try_library(libname, @library_paths) || try_library(libname, paths)
40
+ end
41
+
42
+ def create_rakefile!
43
+ create_rakefile(@name)
44
+ end
45
+
46
+ private
47
+
48
+ def try_header(header, paths)
49
+ main = <<-C_FILE
50
+ #include <#{header}>
51
+ int main(int argc, char **argv) { return 0; }
52
+ C_FILE
53
+
54
+ if paths.empty? && try_compile(main)
55
+ @headers << header
56
+ return true
57
+ end
58
+
59
+ paths.each do |path|
60
+ if try_compile(main, "-I#{path}")
61
+ @include_paths << path
62
+ @headers << header
63
+ return true
64
+ end
65
+ end
66
+ false
67
+ end
68
+
69
+
70
+ def try_library(libname, paths)
71
+ main = <<-C_FILE
72
+ int main(int argc, char **argv) { return 0; }
73
+ C_FILE
74
+
75
+ if paths.empty? && try_compile(main)
76
+ @libraries << libname
77
+ return true
78
+ end
79
+
80
+ paths.each do |path|
81
+ if try_compile(main, "-L#{path}", "-l#{libname}")
82
+ @library_paths << path
83
+ @libraries << libname
84
+ end
85
+ end
86
+ end
87
+
88
+ def try_compile(src, *opts)
89
+ Dir.mktmpdir do |dir|
90
+ path = File.join(dir, 'ffi-test.c')
91
+ File.open(path, "w") do |f|
92
+ f << src
93
+ end
94
+ begin
95
+ return system "cc #{opts.join(' ')} -o #{File.join(dir, 'ffi-test')} #{path} >& /dev/null"
96
+ rescue
97
+ return false
98
+ end
99
+ end
100
+ end
101
+
102
+ def create_rakefile(name)
103
+ lib_name = FFI.map_library_name(name)
104
+ pic_flags = '-fPIC'
105
+ so_flags = ''
106
+ ld_flags = ''
107
+ cc = 'cc'
108
+ cxx = 'c++'
109
+ iflags = @include_paths.uniq.map{ |p| "-I#{p}" }.join(' ')
110
+ defines = @functions.uniq.map { |f| "-DHAVE_#{f.upcase}=1" }.join(' ')
111
+ defines << " " + @headers.uniq.map { |h| "-DHAVE_#{h.upcase.sub(/\./, '_')}=1" }.join(' ')
112
+
113
+ if FFI::Platform.mac?
114
+ pic_flags = ''
115
+ ld_flags += ' -dynamiclib '
116
+
117
+ elsif FFI::Platform.name =~ /linux/
118
+ so_flags += " -shared -Wl,-soname,#{lib_name} "
119
+ end
120
+
121
+ cflags = "#{pic_flags} #{iflags} #{defines}".strip
122
+ ld_flags += so_flags
123
+ ld_flags += @library_paths.map { |path| "-L#{path}" }.join(' ')
124
+ ld_flags.strip!
125
+
126
+ File.open('Rakefile', 'w') do |f|
127
+ f.puts <<-RAKEFILE
128
+
129
+ require 'rake/clean'
130
+
131
+ CC = '#{cc}'
132
+ CXX = '#{cxx}'
133
+ LD = FileList['*.cpp'].empty? ? CC : CXX
134
+ CFLAGS = '#{cflags}'
135
+ CXXFLAGS = '#{cflags}'
136
+ LDFLAGS = '#{ld_flags}'
137
+ LIBS = '#{@libraries.map {|l| "-l#{l}" }.join(" ")}'
138
+
139
+ OBJ_FILES = FileList['*.c', '*.cpp'].map { |f| f.gsub(/\.(c|cpp)$/, '.o') }
140
+
141
+ CLEAN.include(OBJ_FILES)
142
+
143
+ desc "Compile C file to object file"
144
+ rule '.o' => [ '.c' ] do |t|
145
+ sh "\#{CC} \#{CFLAGS} -o \#{t.name} -c \#{t.source}"
146
+ end
147
+
148
+ desc "Compile C++ file to object file"
149
+ rule '.o' => [ '.cpp' ] do |t|
150
+ sh "\#{CXX} \#{CXXFLAGS} -o \#{t.name} -c \#{t.source} "
151
+ end
152
+
153
+ desc "Compile to dynamic library"
154
+ task :compile => "#{lib_name}"
155
+
156
+ file "#{lib_name}" => OBJ_FILES do |t|
157
+ sh "\#{LD} \#{LDFLAGS} -o \#{t.name} \#{t.prerequisites.join(' ')} \#{LIBS}"
158
+ end
159
+
160
+ task :default => :compile
161
+
162
+ RAKEFILE
163
+ end
164
+ end
165
+
166
+ end
167
+ end
168
+
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ffi-compiler
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Wayne Meissner
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-01-15 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ">="
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: ffi
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ">="
36
+ - !ruby/object:Gem::Version
37
+ version: 1.0.0
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: 1.0.0
46
+ - !ruby/object:Gem::Dependency
47
+ name: rspec
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ description: Ruby FFI library
63
+ email: wmeissner@gmail.com
64
+ executables: []
65
+ extensions: []
66
+ extra_rdoc_files: []
67
+ files:
68
+ - ffi-compiler.gemspec
69
+ - lib/ffi-compiler/mkrf.rb
70
+ homepage: http://wiki.github.com/ffi/ffi
71
+ licenses:
72
+ - Apache 2.0
73
+ post_install_message:
74
+ rdoc_options: []
75
+ require_paths:
76
+ - lib
77
+ required_ruby_version: !ruby/object:Gem::Requirement
78
+ none: false
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 1.9.3
83
+ required_rubygems_version: !ruby/object:Gem::Requirement
84
+ none: false
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ requirements: []
90
+ rubyforge_project:
91
+ rubygems_version: 1.8.24
92
+ signing_key:
93
+ specification_version: 3
94
+ summary: Ruby FFI Rakefile generator
95
+ test_files: []