blackwinter-rake-compiler 0.9.2

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.
Files changed (44) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +8 -0
  3. data/History.txt +308 -0
  4. data/LICENSE.txt +20 -0
  5. data/README.rdoc +415 -0
  6. data/Rakefile +15 -0
  7. data/bin/rake-compiler +24 -0
  8. data/cucumber.yml +4 -0
  9. data/features/compile.feature +79 -0
  10. data/features/cross-compile.feature +23 -0
  11. data/features/cross-package-multi.feature +15 -0
  12. data/features/cross-package.feature +14 -0
  13. data/features/java-compile.feature +22 -0
  14. data/features/java-no-native-compile.feature +33 -0
  15. data/features/java-package.feature +24 -0
  16. data/features/package.feature +40 -0
  17. data/features/step_definitions/compilation.rb +70 -0
  18. data/features/step_definitions/cross_compilation.rb +27 -0
  19. data/features/step_definitions/execution.rb +52 -0
  20. data/features/step_definitions/folders.rb +32 -0
  21. data/features/step_definitions/gem.rb +46 -0
  22. data/features/step_definitions/java_compilation.rb +7 -0
  23. data/features/support/env.rb +10 -0
  24. data/features/support/file_template_helpers.rb +137 -0
  25. data/features/support/generator_helpers.rb +123 -0
  26. data/features/support/platform_extension_helpers.rb +27 -0
  27. data/lib/rake/baseextensiontask.rb +90 -0
  28. data/lib/rake/extensioncompiler.rb +53 -0
  29. data/lib/rake/extensiontask.rb +513 -0
  30. data/lib/rake/javaextensiontask.rb +226 -0
  31. data/spec/lib/rake/extensiontask_spec.rb +501 -0
  32. data/spec/lib/rake/javaextensiontask_spec.rb +182 -0
  33. data/spec/spec.opts +3 -0
  34. data/spec/spec_helper.rb +15 -0
  35. data/spec/support/capture_output_helper.rb +22 -0
  36. data/tasks/bin/cross-ruby.rake +213 -0
  37. data/tasks/bootstrap.rake +11 -0
  38. data/tasks/common.rake +10 -0
  39. data/tasks/cucumber.rake +23 -0
  40. data/tasks/gem.rake +52 -0
  41. data/tasks/news.rake +39 -0
  42. data/tasks/release.rake +26 -0
  43. data/tasks/rspec.rake +9 -0
  44. metadata +138 -0
@@ -0,0 +1,226 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rake/baseextensiontask'
4
+
5
+ # Define a series of tasks to aid in the compilation of Java extensions for
6
+ # gem developer/creators.
7
+
8
+ module Rake
9
+ class JavaExtensionTask < BaseExtensionTask
10
+
11
+ attr_accessor :classpath
12
+ attr_accessor :debug
13
+
14
+ # Provide source compatibility with specified release
15
+ attr_accessor :source_version
16
+
17
+ # Generate class files for specific VM version
18
+ attr_accessor :target_version
19
+
20
+ def platform
21
+ @platform ||= 'java'
22
+ end
23
+
24
+ def java_compiling(&block)
25
+ @java_compiling = block if block_given?
26
+ end
27
+
28
+ def init(name = nil, gem_spec = nil)
29
+ super
30
+ @source_pattern = '**/*.java'
31
+ @classpath = nil
32
+ @java_compiling = nil
33
+ @debug = false
34
+ @source_version = '1.5'
35
+ @target_version = '1.5'
36
+ end
37
+
38
+ def define
39
+ super
40
+
41
+ define_java_platform_tasks
42
+ end
43
+
44
+ private
45
+ def define_compile_tasks(for_platform = nil, ruby_ver = RUBY_VERSION)
46
+ # platform usage
47
+ platf = for_platform || platform
48
+
49
+ # lib_path
50
+ lib_path = lib_dir
51
+
52
+ # tmp_path
53
+ tmp_path = "#{@tmp_dir}/#{platf}/#{@name}"
54
+
55
+ # cleanup and clobbering
56
+ CLEAN.include(tmp_path)
57
+ CLOBBER.include("#{lib_path}/#{binary(platf)}")
58
+ CLOBBER.include("#{@tmp_dir}")
59
+
60
+ # directories we need
61
+ directory tmp_path
62
+ directory lib_dir
63
+
64
+ # copy binary from temporary location to final lib
65
+ # tmp/extension_name/extension_name.{so,bundle} => lib/
66
+ task "copy:#{@name}:#{platf}" => [lib_path, "#{tmp_path}/#{binary(platf)}"] do
67
+ install "#{tmp_path}/#{binary(platf)}", "#{lib_path}/#{binary(platf)}"
68
+ end
69
+
70
+ file "#{tmp_path}/#{binary(platf)}" => "#{tmp_path}/.build" do
71
+
72
+ class_files = FileList["#{tmp_path}/**/*.class"].
73
+ gsub("#{tmp_path}/", '')
74
+
75
+ # avoid environment variable expansion using backslash
76
+ class_files.gsub!('$', '\$') unless windows?
77
+
78
+ args = class_files.map { |path|
79
+ ["-C #{tmp_path}", path]
80
+ }.flatten
81
+
82
+ sh "jar cf #{tmp_path}/#{binary(platf)} #{args.join(' ')}"
83
+ end
84
+
85
+ file "#{tmp_path}/.build" => [tmp_path] + source_files do
86
+ not_jruby_compile_msg = <<-EOF
87
+ WARNING: You're cross-compiling a binary extension for JRuby, but are using
88
+ another interpreter. If your Java classpath or extension dir settings are not
89
+ correctly detected, then either check the appropriate environment variables or
90
+ execute the Rake compilation task using the JRuby interpreter.
91
+ (e.g. `jruby -S rake compile:java`)
92
+ EOF
93
+ warn_once(not_jruby_compile_msg) unless defined?(JRUBY_VERSION)
94
+
95
+ classpath_arg = java_classpath_arg(@classpath)
96
+ debug_arg = @debug ? '-g' : ''
97
+
98
+ sh "javac #{java_extdirs_arg} -target #{@target_version} -source #{@source_version} -Xlint:unchecked #{debug_arg} #{classpath_arg} -d #{tmp_path} #{source_files.join(' ')}"
99
+
100
+ # Checkpoint file
101
+ touch "#{tmp_path}/.build"
102
+ end
103
+
104
+ # compile tasks
105
+ unless Rake::Task.task_defined?('compile') then
106
+ desc "Compile all the extensions"
107
+ task "compile"
108
+ end
109
+
110
+ # compile:name
111
+ unless Rake::Task.task_defined?("compile:#{@name}") then
112
+ desc "Compile #{@name}"
113
+ task "compile:#{@name}"
114
+ end
115
+
116
+ # Allow segmented compilation by platform (open door for 'cross compile')
117
+ task "compile:#{@name}:#{platf}" => ["copy:#{@name}:#{platf}"]
118
+ task "compile:#{platf}" => ["compile:#{@name}:#{platf}"]
119
+
120
+ # Only add this extension to the compile chain if current
121
+ # platform matches the indicated one.
122
+ if platf == RUBY_PLATFORM then
123
+ # ensure file is always copied
124
+ file "#{lib_path}/#{binary(platf)}" => ["copy:#{name}:#{platf}"]
125
+
126
+ task "compile:#{@name}" => ["compile:#{@name}:#{platf}"]
127
+ task "compile" => ["compile:#{platf}"]
128
+ end
129
+ end
130
+
131
+ def define_java_platform_tasks
132
+ # lib_path
133
+ lib_path = lib_dir
134
+
135
+ if @gem_spec && !Rake::Task.task_defined?("java:#{@gem_spec.name}")
136
+ task "java:#{@gem_spec.name}" do |t|
137
+ # FIXME: workaround Gem::Specification limitation around cache_file:
138
+ # http://github.com/rubygems/rubygems/issues/78
139
+ spec = gem_spec.dup
140
+ spec.instance_variable_set(:"@cache_file", nil) if spec.respond_to?(:cache_file)
141
+
142
+ # adjust to specified platform
143
+ spec.platform = Gem::Platform.new('java')
144
+
145
+ # clear the extensions defined in the specs
146
+ spec.extensions.clear
147
+
148
+ # add the binaries that this task depends on
149
+ ext_files = []
150
+
151
+ # go through native prerequisites and grab the real extension files from there
152
+ t.prerequisites.each do |ext|
153
+ ext_files << ext
154
+ end
155
+
156
+ # include the files in the gem specification
157
+ spec.files += ext_files
158
+
159
+ # expose gem specification for customization
160
+ if @java_compiling
161
+ @java_compiling.call(spec)
162
+ end
163
+
164
+ # Generate a package for this gem
165
+ Gem::PackageTask.new(spec) do |pkg|
166
+ pkg.need_zip = false
167
+ pkg.need_tar = false
168
+ end
169
+ end
170
+
171
+ # add binaries to the dependency chain
172
+ task "java:#{@gem_spec.name}" => ["#{lib_path}/#{binary(platform)}"]
173
+
174
+ # ensure the extension get copied
175
+ unless Rake::Task.task_defined?("#{lib_path}/#{binary(platform)}") then
176
+ file "#{lib_path}/#{binary(platform)}" => ["copy:#{name}:#{platform}"]
177
+ end
178
+
179
+ task 'java' => ["java:#{@gem_spec.name}"]
180
+ end
181
+
182
+ task 'java' do
183
+ task 'compile' => 'compile:java'
184
+ end
185
+ end
186
+
187
+ #
188
+ # Discover Java Extension Directories and build an extdirs argument
189
+ #
190
+ def java_extdirs_arg
191
+ extdirs = Java::java.lang.System.getProperty('java.ext.dirs') rescue nil
192
+ extdirs = ENV['JAVA_EXT_DIR'] unless extdirs
193
+ java_extdir = extdirs.nil? ? "" : "-extdirs \"#{extdirs}\""
194
+ end
195
+
196
+ #
197
+ # Discover the Java/JRuby classpath and build a classpath argument
198
+ #
199
+ # @params
200
+ # *args:: Additional classpath arguments to append
201
+ #
202
+ # Copied verbatim from the ActiveRecord-JDBC project. There are a small myriad
203
+ # of ways to discover the Java classpath correctly.
204
+ #
205
+ def java_classpath_arg(*args)
206
+ jruby_cpath = nil
207
+ if RUBY_PLATFORM =~ /java/
208
+ begin
209
+ cpath = Java::java.lang.System.getProperty('java.class.path').split(File::PATH_SEPARATOR)
210
+ cpath += Java::java.lang.System.getProperty('sun.boot.class.path').split(File::PATH_SEPARATOR)
211
+ jruby_cpath = cpath.compact.join(File::PATH_SEPARATOR)
212
+ rescue => e
213
+ end
214
+ end
215
+ unless jruby_cpath
216
+ jruby_cpath = ENV['JRUBY_PARENT_CLASSPATH'] || ENV['JRUBY_HOME'] &&
217
+ Dir.glob("#{File.expand_path(ENV['JRUBY_HOME'])}/lib/*.jar").
218
+ join(File::PATH_SEPARATOR)
219
+ end
220
+ raise "JRUBY_HOME or JRUBY_PARENT_CLASSPATH are not set" unless jruby_cpath
221
+ jruby_cpath += File::PATH_SEPARATOR + args.join(File::PATH_SEPARATOR) unless args.empty?
222
+ jruby_cpath ? "-cp \"#{jruby_cpath}\"" : ""
223
+ end
224
+
225
+ end
226
+ end
@@ -0,0 +1,501 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+
3
+ require 'rake/extensiontask'
4
+ require 'rbconfig'
5
+
6
+ describe Rake::ExtensionTask do
7
+ context '#new' do
8
+ context '(basic)' do
9
+ it 'should raise an error if no name is provided' do
10
+ lambda {
11
+ Rake::ExtensionTask.new
12
+ }.should raise_error(RuntimeError, /Extension name must be provided/)
13
+ end
14
+
15
+ it 'should allow string as extension name assignation' do
16
+ ext = Rake::ExtensionTask.new('extension_one')
17
+ ext.name.should == 'extension_one'
18
+ end
19
+
20
+ it 'should allow string as extension name using block assignation' do
21
+ ext = Rake::ExtensionTask.new do |ext|
22
+ ext.name = 'extension_two'
23
+ end
24
+ ext.name.should == 'extension_two'
25
+ end
26
+
27
+ it 'should return itself for the block' do
28
+ from_block = nil
29
+ from_lasgn = Rake::ExtensionTask.new('extension_three') do |ext|
30
+ from_block = ext
31
+ end
32
+ from_block.should == from_lasgn
33
+ end
34
+
35
+ it 'should accept a gem specification as parameter' do
36
+ spec = mock_gem_spec
37
+ ext = Rake::ExtensionTask.new('extension_three', spec)
38
+ ext.gem_spec.should == spec
39
+ end
40
+
41
+ it 'should allow gem specification be defined using block assignation' do
42
+ spec = mock_gem_spec
43
+ ext = Rake::ExtensionTask.new('extension_four') do |ext|
44
+ ext.gem_spec = spec
45
+ end
46
+ ext.gem_spec.should == spec
47
+ end
48
+
49
+ it 'should allow forcing of platform' do
50
+ ext = Rake::ExtensionTask.new('weird_extension') do |ext|
51
+ ext.platform = 'universal-foo-bar-10.5'
52
+ end
53
+ ext.platform.should == 'universal-foo-bar-10.5'
54
+ end
55
+ end
56
+ end
57
+
58
+ context '(defaults)' do
59
+ before :each do
60
+ @ext = Rake::ExtensionTask.new('extension_one')
61
+ end
62
+
63
+ it 'should look for extconf script' do
64
+ @ext.config_script.should == 'extconf.rb'
65
+ end
66
+
67
+ it 'should dump intermediate files to tmp/' do
68
+ @ext.tmp_dir.should == 'tmp'
69
+ end
70
+
71
+ it 'should copy build extension into lib/' do
72
+ @ext.lib_dir.should == 'lib'
73
+ end
74
+
75
+ it 'should look for C files pattern (.c)' do
76
+ @ext.source_pattern.should == "*.c"
77
+ end
78
+
79
+ it 'should have no configuration options preset to delegate' do
80
+ @ext.config_options.should be_empty
81
+ end
82
+
83
+ it "should have no includes preset to delegate" do
84
+ @ext.config_includes.should be_empty
85
+ end
86
+
87
+ it 'should default to current platform' do
88
+ @ext.platform.should == RUBY_PLATFORM
89
+ end
90
+
91
+ it 'should default to no cross compilation' do
92
+ @ext.cross_compile.should be_false
93
+ end
94
+
95
+ it 'should have no configuration options for cross compilation' do
96
+ @ext.cross_config_options.should be_empty
97
+ end
98
+
99
+ it "should have cross platform defined to 'i386-mingw32'" do
100
+ @ext.cross_platform.should == 'i386-mingw32'
101
+ end
102
+ end
103
+
104
+ context '(tasks)' do
105
+ before :each do
106
+ Rake.application.clear
107
+ CLEAN.clear
108
+ CLOBBER.clear
109
+ end
110
+
111
+ context '(one extension)' do
112
+ before :each do
113
+ Rake::FileList.stub!(:[]).and_return(["ext/extension_one/source.c"], [])
114
+ @ext = Rake::ExtensionTask.new('extension_one')
115
+ @ext_bin = ext_bin('extension_one')
116
+ @platform = RUBY_PLATFORM
117
+ @ruby_ver = RUBY_VERSION
118
+ end
119
+
120
+ context 'compile' do
121
+ it 'should define as task' do
122
+ Rake::Task.task_defined?('compile').should be_true
123
+ end
124
+
125
+ it "should depend on 'compile:{platform}'" do
126
+ Rake::Task['compile'].prerequisites.should include("compile:#{@platform}")
127
+ end
128
+ end
129
+
130
+ context 'compile:extension_one' do
131
+ it 'should define as task' do
132
+ Rake::Task.task_defined?('compile:extension_one').should be_true
133
+ end
134
+
135
+ it "should depend on 'compile:extension_one:{platform}'" do
136
+ Rake::Task['compile:extension_one'].prerequisites.should include("compile:extension_one:#{@platform}")
137
+ end
138
+ end
139
+
140
+ context 'lib/extension_one.{so,bundle}' do
141
+ it 'should define as task' do
142
+ Rake::Task.task_defined?("lib/#{@ext_bin}").should be_true
143
+ end
144
+
145
+ it "should depend on 'copy:extension_one:{platform}:{ruby_ver}'" do
146
+ Rake::Task["lib/#{@ext_bin}"].prerequisites.should include("copy:extension_one:#{@platform}:#{@ruby_ver}")
147
+ end
148
+ end
149
+
150
+ context 'tmp/{platform}/extension_one/{ruby_ver}/extension_one.{so,bundle}' do
151
+ it 'should define as task' do
152
+ Rake::Task.task_defined?("tmp/#{@platform}/extension_one/#{@ruby_ver}/#{@ext_bin}").should be_true
153
+ end
154
+
155
+ it "should depend on 'tmp/{platform}/extension_one/{ruby_ver}/Makefile'" do
156
+ Rake::Task["tmp/#{@platform}/extension_one/#{@ruby_ver}/#{@ext_bin}"].prerequisites.should include("tmp/#{@platform}/extension_one/#{@ruby_ver}/Makefile")
157
+ end
158
+
159
+ it "should depend on 'ext/extension_one/source.c'" do
160
+ Rake::Task["tmp/#{@platform}/extension_one/#{@ruby_ver}/#{@ext_bin}"].prerequisites.should include("ext/extension_one/source.c")
161
+ end
162
+
163
+ it "should not depend on 'ext/extension_one/source.h'" do
164
+ Rake::Task["tmp/#{@platform}/extension_one/#{@ruby_ver}/#{@ext_bin}"].prerequisites.should_not include("ext/extension_one/source.h")
165
+ end
166
+ end
167
+
168
+ context 'tmp/{platform}/extension_one/{ruby_ver}/Makefile' do
169
+ it 'should define as task' do
170
+ Rake::Task.task_defined?("tmp/#{@platform}/extension_one/#{@ruby_ver}/Makefile").should be_true
171
+ end
172
+
173
+ it "should depend on 'tmp/{platform}/extension_one/{ruby_ver}'" do
174
+ Rake::Task["tmp/#{@platform}/extension_one/#{@ruby_ver}/Makefile"].prerequisites.should include("tmp/#{@platform}/extension_one/#{@ruby_ver}")
175
+ end
176
+
177
+ it "should depend on 'ext/extension_one/extconf.rb'" do
178
+ Rake::Task["tmp/#{@platform}/extension_one/#{@ruby_ver}/Makefile"].prerequisites.should include("ext/extension_one/extconf.rb")
179
+ end
180
+ end
181
+
182
+ context 'clean' do
183
+ it "should include 'tmp/{platform}/extension_one/{ruby_ver}' in the pattern" do
184
+ CLEAN.should include("tmp/#{@platform}/extension_one/#{@ruby_ver}")
185
+ end
186
+ end
187
+
188
+ context 'clobber' do
189
+ it "should include 'lib/extension_one.{so,bundle}'" do
190
+ CLOBBER.should include("lib/#{@ext_bin}")
191
+ end
192
+
193
+ it "should include 'tmp'" do
194
+ CLOBBER.should include('tmp')
195
+ end
196
+ end
197
+
198
+ it "should warn when pre-compiled files exist in extension directory" do
199
+ Rake::FileList.stub!(:[]).
200
+ and_return(["ext/extension_one/source.c"],
201
+ ["ext/extension_one/source.o"])
202
+
203
+ _, err = capture_output do
204
+ Rake::ExtensionTask.new('extension_one')
205
+ end
206
+ err.should match(/rake-compiler found compiled files in 'ext\/extension_one' directory. Please remove them./)
207
+ end
208
+ end
209
+
210
+ context '(extension in custom location)' do
211
+ before :each do
212
+ Rake::FileList.stub!(:[]).and_return(["ext/extension_one/source.c"], [])
213
+ @ext = Rake::ExtensionTask.new('extension_one') do |ext|
214
+ ext.ext_dir = 'custom/ext/foo'
215
+ end
216
+ @ext_bin = ext_bin('extension_one')
217
+ @platform = RUBY_PLATFORM
218
+ @ruby_ver = RUBY_VERSION
219
+ end
220
+
221
+ context 'tmp/{platform}/extension_one/{ruby_ver}/Makefile' do
222
+ it "should depend on 'custom/ext/foo/extconf.rb'" do
223
+ Rake::Task["tmp/#{@platform}/extension_one/#{@ruby_ver}/Makefile"].prerequisites.should include("custom/ext/foo/extconf.rb")
224
+ end
225
+ end
226
+ end
227
+
228
+ context '(native tasks)' do
229
+ before :each do
230
+ Rake::FileList.stub!(:[]).and_return(["ext/extension_one/source.c"], [])
231
+ @spec = mock_gem_spec
232
+ @ext_bin = ext_bin('extension_one')
233
+ @platform = RUBY_PLATFORM
234
+ @ruby_ver = RUBY_VERSION
235
+ end
236
+
237
+ context 'native' do
238
+ before :each do
239
+ @spec.stub!(:platform=).and_return('ruby')
240
+ end
241
+
242
+ it 'should define a task for building the supplied gem' do
243
+ Rake::ExtensionTask.new('extension_one', @spec)
244
+ Rake::Task.task_defined?('native:my_gem').should be_true
245
+ end
246
+
247
+ it 'should define as task for pure ruby gems' do
248
+ Rake::Task.task_defined?('native').should be_false
249
+ Rake::ExtensionTask.new('extension_one', @spec)
250
+ Rake::Task.task_defined?('native').should be_true
251
+ end
252
+
253
+ it 'should not define a task for already native gems' do
254
+ @spec.stub!(:platform).and_return('current')
255
+ Rake::ExtensionTask.new('extension_one', @spec)
256
+ Rake::Task.task_defined?('native').should be_false
257
+ end
258
+
259
+ it 'should depend on platform specific native tasks' do
260
+ Rake::ExtensionTask.new('extension_one', @spec)
261
+ Rake::Task["native"].prerequisites.should include("native:#{@platform}")
262
+ end
263
+
264
+ context 'native:my_gem:{platform}' do
265
+ it 'should depend on binary extension' do
266
+ Rake::ExtensionTask.new('extension_one', @spec)
267
+ Rake::Task["native:my_gem:#{@platform}"].prerequisites.should include("tmp/#{@platform}/stage/lib/#{@ext_bin}")
268
+ end
269
+ end
270
+ end
271
+ end
272
+
273
+ context '(cross platform tasks)' do
274
+ before :each do
275
+ File.stub!(:exist?).and_return(true)
276
+ YAML.stub!(:load_file).and_return(mock_config_yml)
277
+ Rake::FileList.stub!(:[]).and_return(["ext/extension_one/source.c"], [])
278
+ @spec = mock_gem_spec
279
+ @config_file = File.expand_path("~/.rake-compiler/config.yml")
280
+ @ruby_ver = RUBY_VERSION
281
+ @platform = 'i386-mingw32'
282
+ @config_path = mock_config_yml["rbconfig-#{@platform}-#{@ruby_ver}"]
283
+
284
+ File.stub!(:open).and_yield(mock_fake_rb)
285
+ end
286
+
287
+ context 'if no rake-compiler configuration exists' do
288
+ before :each do
289
+ File.should_receive(:exist?).with(@config_file).and_return(false)
290
+
291
+ _, @err = capture_output do
292
+ Rake::ExtensionTask.new('extension_one') do |ext|
293
+ ext.cross_compile = true
294
+ end
295
+ end
296
+ end
297
+
298
+ it 'should not generate a warning' do
299
+ @err.should eq("")
300
+ end
301
+
302
+ it 'should create a dummy nested cross-compile target that raises an error' do
303
+ Rake::Task.should have_defined("cross")
304
+ Rake::Task["cross"].invoke
305
+ lambda {
306
+ Rake::Task["compile"].invoke
307
+ }.should raise_error(RuntimeError,
308
+ /rake-compiler must be configured first to enable cross-compilation/)
309
+ end
310
+ end
311
+
312
+ it 'should parse the config file using YAML' do
313
+ YAML.should_receive(:load_file).with(@config_file).and_return(mock_config_yml)
314
+ Rake::ExtensionTask.new('extension_one') do |ext|
315
+ ext.cross_compile = true
316
+ end
317
+ end
318
+
319
+ it 'should warn if no section of config file defines running version of ruby' do
320
+ config = mock(Hash)
321
+ config.should_receive(:[]).with("rbconfig-#{@platform}-#{@ruby_ver}").and_return(nil)
322
+ YAML.stub!(:load_file).and_return(config)
323
+ out, err = capture_output do
324
+ Rake::ExtensionTask.new('extension_one') do |ext|
325
+ ext.cross_compile = true
326
+ end
327
+ end
328
+ err.should match(/no configuration section for specified version of Ruby/)
329
+ end
330
+
331
+ it 'should capture an action block to be executed when cross compiling' do
332
+ lambda {
333
+ Rake::ExtensionTask.new('extension_one') do |ext|
334
+ ext.cross_compiling do |gem_spec|
335
+ gem_spec.post_install_message = "Cross compiled gem"
336
+ end
337
+ end
338
+ }.should_not raise_error
339
+ end
340
+
341
+ it 'should allow usage of RUBY_CC_VERSION to indicate a different version of ruby' do
342
+ config = mock(Hash)
343
+ config.should_receive(:[]).with("rbconfig-i386-mingw32-1.9.1").and_return('/path/to/ruby/1.9.1/rbconfig.rb')
344
+ YAML.stub!(:load_file).and_return(config)
345
+
346
+ ENV['RUBY_CC_VERSION'] = '1.9.1'
347
+ Rake::ExtensionTask.new('extension_one') do |ext|
348
+ ext.cross_compile = true
349
+ end
350
+ end
351
+
352
+ it 'should allow multiple versions be supplied to RUBY_CC_VERSION' do
353
+ config = mock(Hash)
354
+ config.should_receive(:[]).once.with("rbconfig-i386-mingw32-1.8.6").and_return('/path/to/ruby/1.8.6/rbconfig.rb')
355
+ config.should_receive(:[]).once.with("rbconfig-i386-mingw32-1.9.1").and_return('/path/to/ruby/1.9.1/rbconfig.rb')
356
+ YAML.stub!(:load_file).and_return(config)
357
+
358
+ ENV['RUBY_CC_VERSION'] = '1.8.6:1.9.1'
359
+ Rake::ExtensionTask.new('extension_one') do |ext|
360
+ ext.cross_compile = true
361
+ end
362
+ end
363
+
364
+ after :each do
365
+ ENV.delete('RUBY_CC_VERSION')
366
+ end
367
+
368
+ context "(cross compile for multiple versions)" do
369
+ before :each do
370
+ config = mock(Hash)
371
+ config.stub!(:[]).and_return('/path/to/ruby/1.8.6/rbconfig.rb', '/path/to/ruby/1.9.1/rbconfig.rb')
372
+ YAML.stub!(:load_file).and_return(config)
373
+
374
+ ENV['RUBY_CC_VERSION'] = '1.8.6:1.9.1'
375
+ @ext = Rake::ExtensionTask.new('extension_one') do |ext|
376
+ ext.cross_compile = true
377
+ ext.cross_platform = 'universal-unknown'
378
+ end
379
+ end
380
+
381
+ it 'should create specific copy of binaries for each version' do
382
+ Rake::Task.should have_defined("copy:extension_one:universal-unknown:1.8.6")
383
+ Rake::Task.should have_defined("copy:extension_one:universal-unknown:1.9.1")
384
+ end
385
+ end
386
+
387
+ context "(cross for 'universal-unknown' platform)" do
388
+ before :each do
389
+ @ext = Rake::ExtensionTask.new('extension_one', @spec) do |ext|
390
+ ext.cross_compile = true
391
+ ext.cross_platform = 'universal-unknown'
392
+ end
393
+ end
394
+
395
+ context 'fake' do
396
+ it 'should chain fake task to Makefile generation' do
397
+ Rake::Task["tmp/universal-unknown/extension_one/#{@ruby_ver}/Makefile"].prerequisites.should include("tmp/universal-unknown/extension_one/#{@ruby_ver}/fake.rb")
398
+ end
399
+ end
400
+
401
+ context 'rbconfig' do
402
+ it 'should chain rbconfig tasks to Makefile generation' do
403
+ Rake::Task["tmp/universal-unknown/extension_one/#{@ruby_ver}/Makefile"].prerequisites.should include("tmp/universal-unknown/extension_one/#{@ruby_ver}/rbconfig.rb")
404
+ end
405
+
406
+ it 'should take rbconfig from rake-compiler configuration' do
407
+ Rake::Task["tmp/universal-unknown/extension_one/#{@ruby_ver}/rbconfig.rb"].prerequisites.should include(@config_path)
408
+ end
409
+ end
410
+
411
+ context 'mkmf' do
412
+ it 'should chain mkmf tasks to Makefile generation' do
413
+ Rake::Task["tmp/universal-unknown/extension_one/#{@ruby_ver}/Makefile"].prerequisites.should include("tmp/universal-unknown/extension_one/#{@ruby_ver}/mkmf.rb")
414
+ end
415
+
416
+ it 'should take mkmf from rake-compiler configuration' do
417
+ mkmf_path = File.expand_path(File.join(File.dirname(@config_path), '..', 'mkmf.rb'))
418
+ Rake::Task["tmp/universal-unknown/extension_one/#{@ruby_ver}/mkmf.rb"].prerequisites.should include(mkmf_path)
419
+ end
420
+ end
421
+
422
+ context 'compile:universal-unknown' do
423
+ it "should be defined" do
424
+ Rake::Task.task_defined?('compile:universal-unknown').should be_true
425
+ end
426
+
427
+ it "should depend on 'compile:extension_one:universal-unknown'" do
428
+ Rake::Task['compile:universal-unknown'].prerequisites.should include('compile:extension_one:universal-unknown')
429
+ end
430
+ end
431
+
432
+ context 'native:universal-unknown' do
433
+ it "should be defined" do
434
+ Rake::Task.task_defined?('native:universal-unknown').should be_true
435
+ end
436
+
437
+ it "should depend on 'native:my_gem:universal-unknown'" do
438
+ Rake::Task['native:universal-unknown'].prerequisites.should include('native:my_gem:universal-unknown')
439
+ end
440
+ end
441
+ end
442
+
443
+ context '(cross for multiple platforms)' do
444
+ before :each do
445
+ @ext = Rake::ExtensionTask.new('extension_one', @spec) do |ext|
446
+ ext.cross_compile = true
447
+ ext.cross_platform = ['universal-known', 'universal-unknown']
448
+ ext.cross_config_options << '--with-something'
449
+ ext.cross_config_options << {'universal-known' => '--with-known'}
450
+ end
451
+ end
452
+
453
+ it 'should define task for each supplied platform' do
454
+ Rake::Task.should have_defined('compile:universal-known')
455
+ Rake::Task.should have_defined('compile:universal-unknown')
456
+ end
457
+
458
+ it 'should filter options for each supplied platform' do
459
+ @ext.cross_config_options('universal-unknown').should eq(%w[--with-something])
460
+ @ext.cross_config_options('universal-known').should eq(%w[--with-something --with-known])
461
+ end
462
+ end
463
+ end
464
+ end
465
+
466
+ private
467
+ def ext_bin(extension_name)
468
+ "#{extension_name}.#{RbConfig::CONFIG['DLEXT']}"
469
+ end
470
+
471
+ def mock_gem_spec(stubs = {})
472
+ mock(Gem::Specification,
473
+ { :name => 'my_gem', :platform => 'ruby', :files => [] }.merge(stubs)
474
+ )
475
+ end
476
+
477
+ def mock_config_yml
478
+ {
479
+ 'rbconfig-i386-mingw32-1.8.6' => '/some/path/version/1.8/to/rbconfig.rb',
480
+ 'rbconfig-universal-unknown-1.8.6' => '/some/path/version/1.8/to/rbconfig.rb',
481
+ 'rbconfig-i386-mingw32-1.8.7' => '/some/path/version/1.8/to/rbconfig.rb',
482
+ 'rbconfig-universal-known-1.8.7' => '/some/path/version/1.8/to/rbconfig.rb',
483
+ 'rbconfig-universal-unknown-1.8.7' => '/some/path/version/1.8/to/rbconfig.rb',
484
+ 'rbconfig-universal-unknown-1.9.1' => '/some/path/version/1.9.1/to/rbconfig.rb',
485
+ 'rbconfig-universal-unknown-1.9.2' => '/some/path/version/1.9.1/to/rbconfig.rb',
486
+ 'rbconfig-universal-unknown-1.9.3' => '/some/path/version/1.9.1/to/rbconfig.rb',
487
+ 'rbconfig-i386-mingw32-1.9.3' => '/some/path/version/1.9.1/to/rbconfig.rb',
488
+ 'rbconfig-universal-known-1.9.3' => '/some/path/version/1.9.1/to/rbconfig.rb',
489
+ 'rbconfig-universal-known-2.0.0' => '/some/path/version/2.0.0/to/rbconfig.rb',
490
+ 'rbconfig-universal-unknown-1.9.3' => '/some/path/version/1.9.1/to/rbconfig.rb',
491
+ 'rbconfig-universal-unknown-2.0.0' => '/some/path/version/2.0.0/to/rbconfig.rb',
492
+ 'rbconfig-i386-mingw32-2.0.0' => '/some/path/version/2.0.0/to/rbconfig.rb',
493
+ 'rbconfig-x64-mingw32-2.0.0' => '/some/path/version/2.0.0/to/rbconfig.rb',
494
+ 'rbconfig-x64-mingw32-3.0.0' => '/some/fake/version/3.0.0/to/rbconfig.rb'
495
+ }
496
+ end
497
+
498
+ def mock_fake_rb
499
+ mock(File, :write => 45)
500
+ end
501
+ end