rake-compiler 0.3.0 → 0.5.0

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.
data/History.txt CHANGED
@@ -1,32 +1,85 @@
1
- === 0.3.0 / 2008-12-07
1
+ === 0.5.0 / 2009-04-25
2
+
3
+ * Enhancements
4
+ * Allow generation of multiple gems for Windows (EXPERIMENTAL)
5
+ This allows build gems for both VC6 and MinGW builts of Ruby
6
+ (Thanks to Jonathan Stott for the suggestion)
7
+
8
+ Rake::ExtensionTask.new('my_extension', GEM_SPEC) do |ext|
9
+ ext.cross_compile = true
10
+ ext.cross_platform = ['i386-mswin32', 'i386-mingw32']
11
+ end
12
+
13
+ === 0.4.1 / 2009-04-09
14
+
15
+ * Enhancements
16
+ * Target specific versions of Ruby when generating binaries.
17
+ This avoids installing a 1.8.x binary gem in 1.9.x and viceversa.
18
+ (Thanks to Aaron Patterson for the patches)
19
+
20
+ * Bugfixes
21
+ * No longer raises error if rake-compiler configuration is missing.
22
+ Not all users of a project would have it installed.
23
+ (Thanks to Aaron Patterson for the patch)
24
+
25
+ === 0.4.0 / 2009-04-03
26
+
27
+ * Enhancements
28
+ * Bended the convention for extension folder.
29
+ Defining <tt>ext_dir</tt> for custom extension location.
30
+
31
+ Rake::ExtensionTask.new('my_extension') do |ext|
32
+ ext.ext_dir = 'custom/location' # look into custom/location
33
+ end # instead of ext/my_extension
2
34
 
3
- * 1 Major Enhancement:
35
+ * Better detection of mingw target across Linux/OSX.
36
+ Exposed it as Rake::ExtensionCompiler
37
+ * Display list of available tasks when calling rake-compiler script
38
+ * Track Ruby full versioning (x.y.z).
39
+ This will help the compilation of extensions targetting 1.8.6/7 and 1.9.1
4
40
 
41
+ * Bugfixes
42
+ * Better output of Rake development tasks (Thanks to Luis Parravicini).
43
+ * Proper usage of Gem::Platform for native gems (Thanks to Dirkjan Bussink).
44
+ * Don't use autoload for YAML (present problems with Ruby 1.9.1).
45
+
46
+ === 0.3.1 / 2009-01-09
47
+
48
+ * Enhancements
49
+ * Download cross-ruby source code using HTTP instead of FTP.
50
+ * Disabled Tcl/Tk extension building on cross-ruby (helps with 1.9).
51
+
52
+ * Bugfixes
53
+ * Workaround bug introduced by lack of Gem::Specification cloning. Fixes DM LH #757.
54
+ * Use proper binary extension on OSX (reported by Dirkjan Bussink).
55
+ * Ensure lib/binary task is defined prior clear of requisites.
56
+
57
+ === 0.3.0 / 2008-12-07
58
+
59
+ * New features
5
60
  * Let you specify the Ruby version used for cross compilation instead
6
61
  of default one.
7
62
 
8
63
  rake cross compile RUBY_CC_VERSION=1.8
9
64
 
10
- * 2 Minor Enhancements:
11
-
65
+ * Enhancements
12
66
  * Properly update rake-compiler configuration when new version is installed.
13
67
  * Automated release process to RubyForge, yay!
14
68
 
15
- * 1 Bug fix:
16
-
69
+ * Bugfixes
17
70
  * Corrected documentation to reflect the available options
18
71
 
19
72
  === 0.2.1 / 2008-11-30
20
73
 
21
- * 2 Major Enhancements:
74
+ * New features
22
75
 
23
76
  * Allow cross compilation (cross compile) using mingw32 on Linux or OSX.
24
77
  * Allow packaging of gems for Windows on Linux or OSX.
25
78
 
26
- * 1 Minor Enhancement:
79
+ * Enhancements
27
80
 
28
81
  * Made generation of extensions safe and target folders per-platform
29
82
 
30
- * 1 Bug Fix:
83
+ * Bugfixes
31
84
 
32
85
  * Ensure binaries for the specific platform are copied before packaging.
data/Rakefile CHANGED
@@ -20,4 +20,4 @@ rescue LoadError
20
20
  end
21
21
 
22
22
  # load rakefile extensions (tasks)
23
- Dir['tasks/*.rake'].each { |f| import f }
23
+ Dir['tasks/*.rake'].sort.each { |f| load f }
@@ -0,0 +1,15 @@
1
+ Feature: Generate multiple Windows gems from Linux
2
+
3
+ In order to keep compatibility with versions of Ruby on Windows
4
+ As a Gem developer on Linux
5
+ I want to build binary gems for One-Click Installer (old and new versions)
6
+
7
+ Scenario: package multiple gems for Windows
8
+ Given that my gem source is all in place to target two platforms
9
+ And I'm running a POSIX operating system
10
+ And I've installed cross compile toolchain
11
+ And I've already successfully executed rake task 'cross compile'
12
+ When rake task 'cross native gem' is invoked
13
+ Then rake task 'cross native gem' succeeded
14
+ And gem for platform 'x86-mswin32' get generated
15
+ And gem for platform 'x86-mingw32' get generated
@@ -8,6 +8,11 @@ Given /^a extension cross-compilable '(.*)'$/ do |extension_name|
8
8
  generate_source_code_for extension_name
9
9
  end
10
10
 
11
+ Given /^a extension '(.*)' multi cross\-compilable$/ do |extension_name|
12
+ generate_multi_cross_compile_extension_task_for extension_name
13
+ generate_source_code_for extension_name
14
+ end
15
+
11
16
  Given /^a extension '(.*)' with forced platform '(.*)'$/ do |extension_name, forced_platform|
12
17
  generate_extension_task_for extension_name, forced_platform
13
18
  generate_source_code_for extension_name
@@ -24,6 +29,12 @@ Given /^that my gem source is all in place$/ do
24
29
  Given "a extension cross-compilable 'extension_one'"
25
30
  end
26
31
 
32
+ Given /^that my gem source is all in place to target two platforms$/ do
33
+ Given "a safe project directory"
34
+ Given "a gem named 'gem_abc'"
35
+ Given "a extension 'extension_one' multi cross-compilable"
36
+ end
37
+
27
38
  Given /^not changed any file since$/ do
28
39
  # don't do anything, that's the purpose of this step!
29
40
  end
@@ -6,16 +6,26 @@ Given %r{^I'm running a POSIX operating system$} do
6
6
  end
7
7
 
8
8
  Given %r{^I've installed cross compile toolchain$} do
9
- compiler = 'i586-mingw32msvc-gcc'
10
- found = false
11
- ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
12
- next unless File.exist?(File.join(path, compiler))
13
- found = true
9
+ compilers = %w(i586-mingw32msvc-gcc i386-mingw32-gcc)
10
+ paths = ENV['PATH'].split(File::PATH_SEPARATOR)
11
+ compiler = compilers.find do |comp|
12
+ paths.find do |path|
13
+ File.exist? File.join(path, comp)
14
+ end
14
15
  end
15
- raise "Cannot locate '#{compiler}' in the PATH." unless found
16
+ raise "Cannot locate '#{compiler}' in the PATH." unless compiler
16
17
  end
17
18
 
18
19
  Then /^binaries for platform '(.*)' get generated$/ do |platform|
19
- ext_for_platform = Dir.glob("tmp/#{platform}/**/*.#{RbConfig::CONFIG['DLEXT']}")
20
+ ext = case platform
21
+ when /darwin/
22
+ 'bundle'
23
+ when /mingw|mswin|linux/
24
+ 'so'
25
+ else
26
+ RbConfig::CONFIG['DLEXT']
27
+ end
28
+
29
+ ext_for_platform = Dir.glob("tmp/#{platform}/**/*.#{ext}")
20
30
  ext_for_platform.should_not be_empty
21
31
  end
@@ -24,6 +24,7 @@ end
24
24
 
25
25
  def gem_file_platform(folder, name, version, platform = nil)
26
26
  file = "#{folder}/#{name}-#{version}"
27
- file << "-" << (platform || Gem::Platform.local.to_s)
27
+ file << "-" << (platform || Gem::Platform.new(RUBY_PLATFORM).to_s)
28
28
  file << ".gem"
29
+ file
29
30
  end
@@ -1,5 +1,6 @@
1
- def template_rakefile
2
- <<-EOF
1
+ module FileTemplateHelpers
2
+ def template_rakefile
3
+ <<-EOF
3
4
  # add rake-compiler lib dir to the LOAD_PATH
4
5
  $LOAD_PATH.unshift File.expand_path(File.join(File.dirname(__FILE__), '../..', 'lib'))
5
6
 
@@ -9,10 +10,10 @@ require 'rake'
9
10
  # load rakefile extensions (tasks)
10
11
  Dir['tasks/*.rake'].each { |f| import f }
11
12
  EOF
12
- end
13
+ end
13
14
 
14
- def template_rake_gemspec(gem_name)
15
- <<-EOF
15
+ def template_rake_gemspec(gem_name)
16
+ <<-EOF
16
17
  require 'rake/gempackagetask'
17
18
  SPEC = Gem::Specification.new do |s|
18
19
  s.name = "#{gem_name}"
@@ -37,52 +38,65 @@ gem_package = Rake::GemPackageTask.new(SPEC) do |pkg|
37
38
  pkg.need_tar = false
38
39
  end
39
40
  EOF
40
- end
41
+ end
41
42
 
42
- def template_rake_extension(extension_name, gem_spec = nil)
43
- <<-EOF
43
+ def template_rake_extension(extension_name, gem_spec = nil)
44
+ <<-EOF
44
45
  require 'rake/extensiontask'
45
46
  Rake::ExtensionTask.new("#{extension_name}"#{', SPEC' if gem_spec})
46
47
  EOF
47
- end
48
+ end
48
49
 
49
- def template_rake_extension_with_platform(extension_name, platform)
50
- <<-EOF
50
+ def template_rake_extension_with_platform(extension_name, platform)
51
+ <<-EOF
51
52
  require 'rake/extensiontask'
52
53
  Rake::ExtensionTask.new("#{extension_name}", SPEC) do |ext|
53
54
  ext.platform = "#{platform}"
54
55
  end
55
56
  EOF
56
- end
57
+ end
57
58
 
58
- def template_rake_extension_cross_compile(extension_name, gem_spec = nil)
59
- <<-EOF
59
+ def template_rake_extension_cross_compile(extension_name, gem_spec = nil)
60
+ <<-EOF
60
61
  require 'rake/extensiontask'
61
62
  Rake::ExtensionTask.new("#{extension_name}"#{', SPEC' if gem_spec}) do |ext|
62
63
  ext.cross_compile = true
63
64
  end
64
65
  EOF
66
+ end
67
+
68
+ def template_rake_extension_multi_cross_compile(extension_name)
69
+ <<-EOF
70
+ require 'rake/extensiontask'
71
+ Rake::ExtensionTask.new("#{extension_name}", SPEC) do |ext|
72
+ ext.cross_compile = true
73
+ ext.cross_platform = ['i386-mswin32', 'i386-mingw32']
65
74
  end
75
+ EOF
76
+ end
66
77
 
67
- def template_extconf(extension_name)
68
- <<-EOF
78
+ def template_extconf(extension_name)
79
+ <<-EOF
69
80
  require 'mkmf'
70
81
  create_makefile("#{extension_name}")
71
82
  EOF
72
- end
83
+ end
73
84
 
74
- def template_source_c(extension_name)
75
- <<-EOF
85
+ def template_source_c(extension_name)
86
+ <<-EOF
76
87
  #include "source.h"
77
88
  void Init_#{extension_name}()
78
89
  {
79
90
  printf("source.c of extension #{extension_name}\\n");
80
91
  }
81
92
  EOF
82
- end
93
+ end
83
94
 
84
- def template_source_h
85
- <<-EOF
95
+ def template_source_h
96
+ <<-EOF
86
97
  #include "ruby.h"
87
98
  EOF
99
+ end
88
100
  end
101
+
102
+ World(FileTemplateHelpers)
@@ -0,0 +1,96 @@
1
+ module GeneratorHelpers
2
+ def generate_scaffold_structure
3
+ # create folder structure
4
+ FileUtils.mkdir_p "lib"
5
+ FileUtils.mkdir_p "tasks"
6
+ FileUtils.mkdir_p "tmp"
7
+
8
+ # create Rakefile loader
9
+ File.open("Rakefile", 'w') do |rakefile|
10
+ rakefile.puts template_rakefile.strip
11
+ end
12
+ end
13
+
14
+ def generate_gem_task(gem_name)
15
+ # create generic gem task
16
+ File.open("tasks/gem.rake", 'w') do |gem_rake|
17
+ gem_rake.puts template_rake_gemspec(gem_name)
18
+ end
19
+ end
20
+
21
+ def generate_extension_task_for(extension_name, platform = nil)
22
+ # create folder structure
23
+ FileUtils.mkdir_p "ext/#{extension_name}"
24
+
25
+ return if File.exist?("tasks/#{extension_name}.rake")
26
+
27
+ # Building a gem?
28
+ if File.exist?("tasks/gem.rake") then
29
+ File.open("tasks/gem.rake", 'a+') do |ext_in_gem|
30
+ if platform
31
+ ext_in_gem.puts template_rake_extension_with_platform(extension_name, platform)
32
+ else
33
+ ext_in_gem.puts template_rake_extension(extension_name, true)
34
+ end
35
+ end
36
+ else
37
+ # create specific extension rakefile
38
+ File.open("tasks/#{extension_name}.rake", 'w') do |ext_rake|
39
+ ext_rake.puts template_rake_extension(extension_name)
40
+ end
41
+ end
42
+ end
43
+
44
+ def generate_cross_compile_extension_task_for(extension_name)
45
+ # create folder structure
46
+ FileUtils.mkdir_p "ext/#{extension_name}"
47
+
48
+ return if File.exist?("tasks/#{extension_name}.rake")
49
+
50
+ # create specific extension rakefile
51
+ # Building a gem?
52
+ if File.exist?("tasks/gem.rake") then
53
+ File.open("tasks/gem.rake", 'a+') do |ext_in_gem|
54
+ ext_in_gem.puts template_rake_extension_cross_compile(extension_name, true)
55
+ end
56
+ else
57
+ File.open("tasks/#{extension_name}.rake", 'w') do |ext_rake|
58
+ ext_rake.puts template_rake_extension_cross_compile(extension_name)
59
+ end
60
+ end
61
+ end
62
+
63
+ def generate_multi_cross_compile_extension_task_for(extension_name)
64
+ # create folder structure
65
+ FileUtils.mkdir_p "ext/#{extension_name}"
66
+
67
+ return if File.exist?("tasks/#{extension_name}.rake")
68
+
69
+ # create specific extension rakefile
70
+ # Building a gem?
71
+ if File.exist?("tasks/gem.rake") then
72
+ File.open("tasks/gem.rake", 'a+') do |ext_in_gem|
73
+ ext_in_gem.puts template_rake_extension_multi_cross_compile(extension_name)
74
+ end
75
+ end
76
+ end
77
+
78
+ def generate_source_code_for(extension_name)
79
+ # source C file
80
+ File.open("ext/#{extension_name}/source.c", 'w') do |c|
81
+ c.puts template_source_c(extension_name)
82
+ end
83
+
84
+ # header H file
85
+ File.open("ext/#{extension_name}/source.h", 'w') do |h|
86
+ h.puts template_source_h
87
+ end
88
+
89
+ # extconf.rb file
90
+ File.open("ext/#{extension_name}/extconf.rb", 'w') do |ext|
91
+ ext.puts template_extconf(extension_name)
92
+ end
93
+ end
94
+ end
95
+
96
+ World(GeneratorHelpers)
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ module Rake
4
+
5
+ #
6
+ # HACK: Lousy API design, sue me. At least works ;-)
7
+ #
8
+ # Define a series of helpers to aid in search and usage of MinGW (GCC) Compiler
9
+ # by gem developer/creators.
10
+ #
11
+ module ExtensionCompiler
12
+ # return the host portion from the installed MinGW
13
+ def self.mingw_host
14
+ return @mingw_host if @mingw_host
15
+
16
+ # the mingw_gcc_executable is helpful here
17
+ if target = mingw_gcc_executable then
18
+ # we only care for the filename
19
+ target = File.basename(target)
20
+
21
+ # now strip the extension (if present)
22
+ target.sub!(File.extname(target), '')
23
+
24
+ # get rid of '-gcc' portion too ;-)
25
+ target.sub!('-gcc', '')
26
+ end
27
+
28
+ raise "No MinGW tools or unknown setup platform?" unless target
29
+
30
+ @mingw_host = target
31
+ end
32
+
33
+ # return the first compiler found that includes both mingw and gcc conditions
34
+ # (this assumes you have one installed)
35
+ def self.mingw_gcc_executable
36
+ return @mingw_gcc_executable if @mingw_gcc_executable
37
+
38
+ # grab the paths defined in the environment
39
+ paths = ENV['PATH'].split(File::PATH_SEPARATOR)
40
+
41
+ # the pattern to look into (captures *nix and windows executables)
42
+ pattern = "*mingw*gcc{,.*}"
43
+
44
+ @mingw_gcc_executable = paths.find do |path|
45
+ # cleanup paths before globbing
46
+ gcc = Dir.glob("#{File.expand_path(path)}/#{pattern}").first
47
+ break gcc if gcc
48
+ end
49
+
50
+ @mingw_gcc_executable
51
+ end
52
+ end
53
+ end