ffi-compiler 0.0.1

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.
@@ -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: []