luislavena-rake-compiler 0.1.1 → 0.2.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/README.rdoc +67 -1
- data/features/compile.feature +1 -1
- data/features/cross-compile.feature +13 -0
- data/features/cross-package.feature +14 -0
- data/features/package.feature +2 -2
- data/features/step_definitions/compilation.rb +16 -0
- data/features/step_definitions/cross_compilation.rb +20 -0
- data/features/step_definitions/gem.rb +4 -0
- data/features/support/file_templates.rb +13 -0
- data/features/support/generators.rb +19 -0
- data/lib/rake/extensiontask.rb +175 -87
- data/spec/lib/rake/extensiontask_spec.rb +109 -16
- data/tasks/rubygems.rake +1 -1
- metadata +5 -2
data/README.rdoc
CHANGED
|
@@ -157,12 +157,78 @@ personalize several settings for <tt>Rake::ExtensionTask</tt>:
|
|
|
157
157
|
ext.config_script = 'custom_extconf.rb' # use instead of 'extconf.rb' default
|
|
158
158
|
ext.tmp_dir = 'tmp' # temporary folder used during compilation.
|
|
159
159
|
ext.source_pattern = "*.{c,cpp}" # monitor file changes to allow simple rebuild.
|
|
160
|
-
ext.
|
|
160
|
+
ext.config_options << '--with-foo' # supply additional configure options to config script.
|
|
161
161
|
ext.gem_spec = spec # optional indicate which gem specification
|
|
162
162
|
# will be used to based on.
|
|
163
163
|
end
|
|
164
164
|
|
|
165
165
|
|
|
166
|
+
== Future is now: Cross compilation
|
|
167
|
+
|
|
168
|
+
rake-compiler provides now an standarized way to generate, from Linux or OSX
|
|
169
|
+
both extensions and gem binaries for Windows!
|
|
170
|
+
|
|
171
|
+
It takes advantages from GCC host/target to build binaries (for target) on
|
|
172
|
+
different OS (hosts).
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
=== How I enjoy this?
|
|
176
|
+
|
|
177
|
+
Besides having the development tool chain installed (GCC), you should install
|
|
178
|
+
also <tt>mingw32</tt> cross compilation package.
|
|
179
|
+
|
|
180
|
+
Dependending on your operating system distribution, a simple <tt>apt-get install mingw32</tt>
|
|
181
|
+
will be enough.
|
|
182
|
+
|
|
183
|
+
Please check OSX documentation about installing mingw32 from macports.
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
=== I have my toolchain, now what?
|
|
187
|
+
|
|
188
|
+
You need to build Ruby for Windows.
|
|
189
|
+
|
|
190
|
+
Relax, no need to freak out. rake-compiler do it for you:
|
|
191
|
+
|
|
192
|
+
rake-compiler cross-ruby
|
|
193
|
+
|
|
194
|
+
And you're done. It will automatically download, configure and compile latest
|
|
195
|
+
stable version of Ruby for Windows, and place it into <tt>~/.rake-compiler</tt>
|
|
196
|
+
|
|
197
|
+
If, instead, you want to build another version than the default one, please
|
|
198
|
+
supply a <tt>VERSION</tt>:
|
|
199
|
+
|
|
200
|
+
rake-compiler cross-ruby VERSION=1.8.6-p114
|
|
201
|
+
|
|
202
|
+
=== Let's build some gems!
|
|
203
|
+
|
|
204
|
+
Now, you only need to use additional options in your extension defintion:
|
|
205
|
+
|
|
206
|
+
Rake::ExtensionTask.new('my_extension', gem_spec) do |ext|
|
|
207
|
+
ext.cross_compile = true # enable cross compilation (requires cross compile toolchain)
|
|
208
|
+
ext.cross_platform = 'i386-mswin32' # forces the Windows platform instead of the default one
|
|
209
|
+
# configure options only for cross compile
|
|
210
|
+
ext.cross_config_options << '--with-something'
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
By default, cross compilation targets 'i386-mingw32' which is default GCC platform
|
|
214
|
+
for Ruby.
|
|
215
|
+
|
|
216
|
+
To target gems for current Ruby official distribution, please force the platform
|
|
217
|
+
to the one shown before.
|
|
218
|
+
|
|
219
|
+
=== Magician doing some tricks, don't blink!
|
|
220
|
+
|
|
221
|
+
Compiles keeps being simple:
|
|
222
|
+
|
|
223
|
+
rake cross compile
|
|
224
|
+
|
|
225
|
+
And now, build your gems for Windows is just 4 more letters:
|
|
226
|
+
|
|
227
|
+
rake cross native gem
|
|
228
|
+
|
|
229
|
+
And you're done, yeah.
|
|
230
|
+
|
|
231
|
+
|
|
166
232
|
== Future
|
|
167
233
|
|
|
168
234
|
rake-compiler is a work in progress and we will appreciate feedback during the
|
data/features/compile.feature
CHANGED
|
@@ -20,7 +20,7 @@ Feature: Compile C code into Ruby extensions.
|
|
|
20
20
|
And not changed any file since
|
|
21
21
|
When rake task 'compile' is invoked
|
|
22
22
|
Then rake task 'compile' succeeded
|
|
23
|
-
And output of rake task 'compile' do not contain /
|
|
23
|
+
And output of rake task 'compile' do not contain /gcc|cl/
|
|
24
24
|
|
|
25
25
|
Scenario: recompile extension when source is modified
|
|
26
26
|
Given a safe project directory
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Feature: Cross-compile C extensions
|
|
2
|
+
|
|
3
|
+
In order to avoid bitching from Windows users
|
|
4
|
+
As a Ruby developer on Linux
|
|
5
|
+
I want some rake tasks that take away the pain of compilation
|
|
6
|
+
|
|
7
|
+
Scenario: compile single extension
|
|
8
|
+
Given that all my source files are in place
|
|
9
|
+
And I'm running a POSIX operating system
|
|
10
|
+
And I've installed cross compile toolchain
|
|
11
|
+
When rake task 'cross compile' is invoked
|
|
12
|
+
Then rake task 'cross compile' succeeded
|
|
13
|
+
And binaries for platform 'i386-mingw32' get generated
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
Feature: Generate Windows gems from Linux
|
|
2
|
+
|
|
3
|
+
In order to keep sanity in the Ruby world
|
|
4
|
+
As a Gem developer on Linux
|
|
5
|
+
I want more rake magic that turns monotony into joy.
|
|
6
|
+
|
|
7
|
+
Scenario: package a gem for Windows
|
|
8
|
+
Given that my gem source is all in place
|
|
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-mingw32' get generated
|
data/features/package.feature
CHANGED
|
@@ -33,8 +33,8 @@ Feature: Distribute native extension with gems
|
|
|
33
33
|
And a extension 'extension_one' with forced platform 'universal-unknown'
|
|
34
34
|
And I've already successfully executed rake task 'compile'
|
|
35
35
|
And 'pkg' folder is deleted
|
|
36
|
-
When rake task 'native gem' is invoked
|
|
37
|
-
Then rake task 'native gem' succeeded
|
|
36
|
+
When rake task 'native:universal-unknown gem' is invoked
|
|
37
|
+
Then rake task 'native:universal-unknown gem' succeeded
|
|
38
38
|
And 'pkg' folder is created
|
|
39
39
|
And ruby gem for 'my_project' version '0.1.0' do exist in 'pkg'
|
|
40
40
|
And a gem for 'my_project' version '0.1.0' platform 'universal-unknown' do exist in 'pkg'
|
|
@@ -3,11 +3,27 @@ Given /^a extension named '(.*)'$/ do |extension_name|
|
|
|
3
3
|
generate_source_code_for extension_name
|
|
4
4
|
end
|
|
5
5
|
|
|
6
|
+
Given /^a extension cross-compilable '(.*)'$/ do |extension_name|
|
|
7
|
+
generate_cross_compile_extension_task_for extension_name
|
|
8
|
+
generate_source_code_for extension_name
|
|
9
|
+
end
|
|
10
|
+
|
|
6
11
|
Given /^a extension '(.*)' with forced platform '(.*)'$/ do |extension_name, forced_platform|
|
|
7
12
|
generate_extension_task_for extension_name, forced_platform
|
|
8
13
|
generate_source_code_for extension_name
|
|
9
14
|
end
|
|
10
15
|
|
|
16
|
+
Given /^that all my source files are in place$/ do
|
|
17
|
+
Given "a safe project directory"
|
|
18
|
+
Given "a extension cross-compilable 'extension_one'"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
Given /^that my gem source is all in place$/ do
|
|
22
|
+
Given "a safe project directory"
|
|
23
|
+
Given "a gem named 'gem_abc'"
|
|
24
|
+
Given "a extension cross-compilable 'extension_one'"
|
|
25
|
+
end
|
|
26
|
+
|
|
11
27
|
Given /^not changed any file since$/ do
|
|
12
28
|
# don't do anything, that's the purpose of this step!
|
|
13
29
|
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Naive way of looking into platforms, please include others like FreeBSD?
|
|
2
|
+
if RUBY_PLATFORM =~ /linux|darwin/
|
|
3
|
+
Given %r{^I'm running a POSIX operating system$} do
|
|
4
|
+
end
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
Given %r{^I've installed cross compile toolchain$} do
|
|
8
|
+
compiler = 'i586-mingw32msvc-gcc'
|
|
9
|
+
found = false
|
|
10
|
+
ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
|
|
11
|
+
next unless File.exist?(File.join(path, compiler))
|
|
12
|
+
found = true
|
|
13
|
+
end
|
|
14
|
+
raise "Cannot locate '#{compiler}' in the PATH." unless found
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
Then /^binaries for platform '(.*)' get generated$/ do |platform|
|
|
18
|
+
ext_for_platform = Dir.glob("tmp/#{platform}/**/*.#{RbConfig::CONFIG['DLEXT']}")
|
|
19
|
+
ext_for_platform.should_not be_empty
|
|
20
|
+
end
|
|
@@ -14,6 +14,10 @@ Then /^a gem for '(.*)' version '(.*)' platform '(.*)' do exist in '(.*)'$/ do |
|
|
|
14
14
|
File.exist?(gem_file_platform(folder, name, version, platform)).should be_true
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
+
Then /^gem for platform '(.*)' get generated$/ do |platform|
|
|
18
|
+
Then "a gem for 'gem_abc' version '0.1.0' platform '#{platform}' do exist in 'pkg'"
|
|
19
|
+
end
|
|
20
|
+
|
|
17
21
|
def gem_file(folder, name, version)
|
|
18
22
|
"#{folder}/#{name}-#{version}.gem"
|
|
19
23
|
end
|
|
@@ -19,6 +19,10 @@ SPEC = Gem::Specification.new do |s|
|
|
|
19
19
|
s.version = "0.1.0"
|
|
20
20
|
s.summary = "#{gem_name} test gem for rake-compiler"
|
|
21
21
|
|
|
22
|
+
s.files = FileList["ext/**/*.{rb,c,h}", "Rakefile", "tasks/*.rake", "lib/**/*.rb"]
|
|
23
|
+
|
|
24
|
+
s.extensions = FileList["ext/**/extconf.rb"]
|
|
25
|
+
|
|
22
26
|
s.has_rdoc = true
|
|
23
27
|
|
|
24
28
|
s.homepage = 'http://github.com/luislavena/rake-compiler'
|
|
@@ -51,6 +55,15 @@ end
|
|
|
51
55
|
EOF
|
|
52
56
|
end
|
|
53
57
|
|
|
58
|
+
def template_rake_extension_cross_compile(extension_name, gem_spec = nil)
|
|
59
|
+
<<-EOF
|
|
60
|
+
require 'rake/extensiontask'
|
|
61
|
+
Rake::ExtensionTask.new("#{extension_name}"#{', SPEC' if gem_spec}) do |ext|
|
|
62
|
+
ext.cross_compile = true
|
|
63
|
+
end
|
|
64
|
+
EOF
|
|
65
|
+
end
|
|
66
|
+
|
|
54
67
|
def template_extconf(extension_name)
|
|
55
68
|
<<-EOF
|
|
56
69
|
require 'mkmf'
|
|
@@ -40,6 +40,25 @@ def generate_extension_task_for(extension_name, platform = nil)
|
|
|
40
40
|
end
|
|
41
41
|
end
|
|
42
42
|
|
|
43
|
+
def generate_cross_compile_extension_task_for(extension_name)
|
|
44
|
+
# create folder structure
|
|
45
|
+
FileUtils.mkdir_p "ext/#{extension_name}"
|
|
46
|
+
|
|
47
|
+
return if File.exist?("tasks/#{extension_name}.rake")
|
|
48
|
+
|
|
49
|
+
# create specific extension rakefile
|
|
50
|
+
# Building a gem?
|
|
51
|
+
if File.exist?("tasks/gem.rake") then
|
|
52
|
+
File.open("tasks/gem.rake", 'a+') do |ext_in_gem|
|
|
53
|
+
ext_in_gem.puts template_rake_extension_cross_compile(extension_name, true)
|
|
54
|
+
end
|
|
55
|
+
else
|
|
56
|
+
File.open("tasks/#{extension_name}.rake", 'w') do |ext_rake|
|
|
57
|
+
ext_rake.puts template_rake_extension_cross_compile(extension_name)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
43
62
|
def generate_source_code_for(extension_name)
|
|
44
63
|
# source C file
|
|
45
64
|
File.open("ext/#{extension_name}/source.c", 'w') do |c|
|
data/lib/rake/extensiontask.rb
CHANGED
|
@@ -9,6 +9,9 @@ require 'rake/tasklib'
|
|
|
9
9
|
require 'rbconfig'
|
|
10
10
|
|
|
11
11
|
module Rake
|
|
12
|
+
autoload :GemPackageTask, 'rake/gempackagetask'
|
|
13
|
+
autoload :YAML, 'yaml'
|
|
14
|
+
|
|
12
15
|
class ExtensionTask < TaskLib
|
|
13
16
|
attr_accessor :name
|
|
14
17
|
attr_accessor :gem_spec
|
|
@@ -17,8 +20,11 @@ module Rake
|
|
|
17
20
|
attr_accessor :ext_dir
|
|
18
21
|
attr_accessor :lib_dir
|
|
19
22
|
attr_accessor :platform
|
|
20
|
-
attr_accessor :
|
|
23
|
+
attr_accessor :config_options
|
|
21
24
|
attr_accessor :source_pattern
|
|
25
|
+
attr_accessor :cross_compile
|
|
26
|
+
attr_accessor :cross_platform
|
|
27
|
+
attr_accessor :cross_config_options
|
|
22
28
|
|
|
23
29
|
def initialize(name = nil, gem_spec = nil)
|
|
24
30
|
init(name, gem_spec)
|
|
@@ -34,149 +40,231 @@ module Rake
|
|
|
34
40
|
@ext_dir = 'ext'
|
|
35
41
|
@lib_dir = 'lib'
|
|
36
42
|
@source_pattern = "*.c"
|
|
37
|
-
@
|
|
43
|
+
@config_options = []
|
|
44
|
+
@cross_compile = false
|
|
45
|
+
@cross_config_options = []
|
|
38
46
|
end
|
|
39
47
|
|
|
40
48
|
def platform
|
|
41
49
|
@platform ||= RUBY_PLATFORM
|
|
42
50
|
end
|
|
43
51
|
|
|
52
|
+
def cross_platform
|
|
53
|
+
@cross_platform ||= 'i386-mingw32'
|
|
54
|
+
end
|
|
55
|
+
|
|
44
56
|
def define
|
|
45
57
|
fail "Extension name must be provided." if @name.nil?
|
|
46
58
|
|
|
47
59
|
define_compile_tasks
|
|
48
|
-
|
|
60
|
+
|
|
61
|
+
# only gems with 'ruby' platforms are allowed to define native tasks
|
|
62
|
+
define_native_tasks if @gem_spec && @gem_spec.platform == 'ruby'
|
|
63
|
+
|
|
64
|
+
# only define cross platform functionality when enabled
|
|
65
|
+
# FIXME: there is no value for having this on Windows or JRuby
|
|
66
|
+
define_cross_platform_tasks if @cross_compile
|
|
49
67
|
end
|
|
50
68
|
|
|
51
69
|
private
|
|
52
|
-
def define_compile_tasks
|
|
70
|
+
def define_compile_tasks(for_platform = nil)
|
|
71
|
+
# platform usage
|
|
72
|
+
platf = for_platform || platform
|
|
73
|
+
|
|
74
|
+
# tmp_path
|
|
75
|
+
tmp_path = "#{@tmp_dir}/#{platf}/#{@name}"
|
|
76
|
+
|
|
77
|
+
# cleanup and clobbering
|
|
78
|
+
CLEAN.include(tmp_path)
|
|
79
|
+
CLOBBER.include("#{@lib_dir}/#{binary}")
|
|
80
|
+
CLOBBER.include("#{@tmp_dir}")
|
|
81
|
+
|
|
53
82
|
# directories we need
|
|
54
83
|
directory tmp_path
|
|
55
|
-
directory
|
|
84
|
+
directory lib_dir
|
|
56
85
|
|
|
57
|
-
#
|
|
58
|
-
|
|
86
|
+
# copy binary from temporary location to final lib
|
|
87
|
+
# tmp/extension_name/extension_name.{so,bundle} => lib/
|
|
88
|
+
task "copy:#{@name}:#{platf}" => [lib_dir, "#{tmp_path}/#{binary}"] do
|
|
89
|
+
cp "#{tmp_path}/#{binary}", "#{@lib_dir}/#{binary}"
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# binary in temporary folder depends on makefile and source files
|
|
93
|
+
# tmp/extension_name/extension_name.{so,bundle}
|
|
94
|
+
file "#{tmp_path}/#{binary}" => ["#{tmp_path}/Makefile"] + source_files do
|
|
95
|
+
chdir tmp_path do
|
|
96
|
+
sh make
|
|
97
|
+
end
|
|
98
|
+
end
|
|
59
99
|
|
|
60
100
|
# makefile depends of tmp_dir and config_script
|
|
61
101
|
# tmp/extension_name/Makefile
|
|
62
|
-
file
|
|
102
|
+
file "#{tmp_path}/Makefile" => [tmp_path, extconf] do |t|
|
|
103
|
+
options = @config_options.dup
|
|
104
|
+
|
|
105
|
+
# rbconfig.rb will be present if we are cross compiling
|
|
106
|
+
if t.prerequisites.include?("#{tmp_path}/rbconfig.rb") then
|
|
107
|
+
options.push(*@cross_config_options)
|
|
108
|
+
end
|
|
109
|
+
|
|
63
110
|
parent = Dir.pwd
|
|
64
|
-
|
|
111
|
+
chdir tmp_path do
|
|
65
112
|
# FIXME: Rake is broken for multiple arguments system() calls.
|
|
66
113
|
# Add current directory to the search path of Ruby
|
|
67
114
|
# Also, include additional parameters supplied.
|
|
68
|
-
ruby ['-I.', File.join(parent, extconf),
|
|
115
|
+
ruby ['-I.', File.join(parent, extconf), *options].join(' ')
|
|
69
116
|
end
|
|
70
117
|
end
|
|
71
118
|
|
|
72
|
-
#
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
sh make
|
|
77
|
-
end
|
|
119
|
+
# compile tasks
|
|
120
|
+
unless Rake::Task.task_defined?('compile') then
|
|
121
|
+
desc "Compile all the extensions"
|
|
122
|
+
task "compile"
|
|
78
123
|
end
|
|
79
124
|
|
|
80
|
-
#
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
125
|
+
# compile:name
|
|
126
|
+
unless Rake::Task.task_defined?("compile:#{@name}") then
|
|
127
|
+
desc "Compile #{@name}"
|
|
128
|
+
task "compile:#{@name}"
|
|
84
129
|
end
|
|
85
130
|
|
|
86
|
-
#
|
|
87
|
-
|
|
131
|
+
# Allow segmented compilation by platfrom (open door for 'cross compile')
|
|
132
|
+
task "compile:#{@name}:#{platf}" => ["copy:#{@name}:#{platf}"]
|
|
133
|
+
task "compile:#{platf}" => ["compile:#{@name}:#{platf}"]
|
|
88
134
|
|
|
89
|
-
#
|
|
90
|
-
|
|
135
|
+
# Only add this extension to the compile chain if current
|
|
136
|
+
# platform matches the indicated one.
|
|
137
|
+
if platf == RUBY_PLATFORM then
|
|
138
|
+
# ensure file is always copied
|
|
139
|
+
file "#{@lib_dir}/#{binary}" => ["copy:#{name}:#{platf}"]
|
|
91
140
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
desc "Compile the extension(s)" unless Rake::Task.task_defined?('compile')
|
|
96
|
-
task "compile" => ["compile:#{@name}"]
|
|
141
|
+
task "compile:#{@name}" => ["compile:#{@name}:#{platf}"]
|
|
142
|
+
task "compile" => ["compile:#{platf}"]
|
|
143
|
+
end
|
|
97
144
|
end
|
|
98
145
|
|
|
99
|
-
def define_native_tasks
|
|
100
|
-
|
|
101
|
-
return unless @gem_spec.platform == 'ruby'
|
|
146
|
+
def define_native_tasks(for_platform = nil)
|
|
147
|
+
platf = for_platform || platform
|
|
102
148
|
|
|
103
|
-
|
|
149
|
+
# tmp_path
|
|
150
|
+
tmp_path = "#{@tmp_dir}/#{platf}/#{@name}"
|
|
104
151
|
|
|
105
152
|
# create 'native:gem_name' and chain it to 'native' task
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
153
|
+
spec = @gem_spec.dup
|
|
154
|
+
|
|
155
|
+
unless Rake::Task.task_defined?("native:#{@gem_spec.name}:#{platf}")
|
|
156
|
+
task "native:#{@gem_spec.name}:#{platf}" do |t|
|
|
157
|
+
# adjust to specified platform
|
|
158
|
+
spec.platform = platf
|
|
159
|
+
|
|
160
|
+
# clear the extensions defined in the specs
|
|
161
|
+
spec.extensions.clear
|
|
162
|
+
|
|
163
|
+
# add the binaries that this task depends on
|
|
164
|
+
# ensure the files get properly copied to lib_dir
|
|
165
|
+
ext_files = t.prerequisites.map { |ext| "#{@lib_dir}/#{File.basename(ext)}" }
|
|
166
|
+
ext_files.each do |ext|
|
|
167
|
+
unless Rake::Task.task_defined?("#{@lib_dir}/#{File.basename(ext)}") then
|
|
168
|
+
# strip out path and .so/.bundle
|
|
169
|
+
file "#{@lib_dir}/#{File.basename(ext)}" => ["copy:#{File.basename(ext).ext('')}:#{platf}"]
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
# include the files in the gem specification
|
|
174
|
+
spec.files += ext_files
|
|
175
|
+
|
|
176
|
+
# Generate a package for this gem
|
|
177
|
+
gem_package = Rake::GemPackageTask.new(spec) do |pkg|
|
|
178
|
+
pkg.need_zip = false
|
|
179
|
+
pkg.need_tar = false
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# ensure the binaries are copied
|
|
183
|
+
task "#{gem_package.package_dir}/#{gem_package.gem_file}" => ["copy:#{@name}:#{platf}"]
|
|
184
|
+
end
|
|
185
|
+
end
|
|
115
186
|
|
|
116
|
-
|
|
117
|
-
"#{
|
|
118
|
-
end
|
|
187
|
+
# add binaries to the dependency chain
|
|
188
|
+
task "native:#{@gem_spec.name}:#{platf}" => ["#{tmp_path}/#{binary}"]
|
|
119
189
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
end
|
|
190
|
+
# Allow segmented packaging by platfrom (open door for 'cross compile')
|
|
191
|
+
task "native:#{platf}" => ["native:#{@gem_spec.name}:#{platf}"]
|
|
123
192
|
|
|
124
|
-
|
|
125
|
-
|
|
193
|
+
# Only add this extension to the compile chain if current
|
|
194
|
+
# platform matches the indicated one.
|
|
195
|
+
if platf == RUBY_PLATFORM then
|
|
196
|
+
task "native:#{@gem_spec.name}" => ["native:#{@gem_spec.name}:#{platf}"]
|
|
197
|
+
task "native" => ["native:#{platf}"]
|
|
198
|
+
end
|
|
126
199
|
end
|
|
127
200
|
|
|
128
|
-
def
|
|
129
|
-
|
|
130
|
-
|
|
201
|
+
def define_cross_platform_tasks
|
|
202
|
+
config_path = File.expand_path("~/.rake-compiler/config.yml")
|
|
203
|
+
major_ver = RUBY_VERSION.match(/(\d+.\d+)/)[1]
|
|
131
204
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
205
|
+
# warn the user about the need of configuration to use cross compilation.
|
|
206
|
+
unless File.exist?(config_path)
|
|
207
|
+
warn "rake-compiler must be configured first to enable cross-compilation"
|
|
208
|
+
return
|
|
209
|
+
end
|
|
135
210
|
|
|
136
|
-
|
|
137
|
-
"#{@name}.#{RbConfig::CONFIG['DLEXT']}"
|
|
138
|
-
end
|
|
211
|
+
config_file = YAML.load_file(config_path)
|
|
139
212
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
end
|
|
213
|
+
# tmp_path
|
|
214
|
+
tmp_path = "#{@tmp_dir}/#{cross_platform}/#{@name}"
|
|
143
215
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
216
|
+
unless rbconfig_file = config_file["rbconfig-#{major_ver}"] then
|
|
217
|
+
fail "no configuration section for this version of Ruby (rbconfig-#{major_ver})"
|
|
218
|
+
end
|
|
147
219
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
end
|
|
220
|
+
# define compilation tasks for cross platfrom!
|
|
221
|
+
define_compile_tasks(cross_platform)
|
|
151
222
|
|
|
152
|
-
|
|
153
|
-
"
|
|
154
|
-
end
|
|
223
|
+
# chain rbconfig.rb to Makefile generation
|
|
224
|
+
file "#{tmp_path}/Makefile" => ["#{tmp_path}/rbconfig.rb"]
|
|
155
225
|
|
|
156
|
-
|
|
157
|
-
|
|
226
|
+
# copy the file from the cross-ruby location
|
|
227
|
+
file "#{tmp_path}/rbconfig.rb" => [rbconfig_file] do |t|
|
|
228
|
+
cp t.prerequisites.first, t.name
|
|
229
|
+
end
|
|
158
230
|
|
|
159
|
-
|
|
231
|
+
# now define native tasks for cross compiled files
|
|
232
|
+
define_native_tasks(cross_platform) if @gem_spec && @gem_spec.platform == 'ruby'
|
|
160
233
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
234
|
+
# create cross task
|
|
235
|
+
task 'cross' do
|
|
236
|
+
# clear compile dependencies
|
|
237
|
+
Rake::Task['compile'].prerequisites.clear
|
|
164
238
|
|
|
165
|
-
#
|
|
166
|
-
|
|
239
|
+
# chain the cross platform ones
|
|
240
|
+
task 'compile' => ["compile:#{cross_platform}"]
|
|
167
241
|
|
|
168
|
-
#
|
|
169
|
-
|
|
242
|
+
# clear lib/binary dependencies and trigger cross platform ones
|
|
243
|
+
Rake::Task["#{@lib_dir}/#{binary}"].prerequisites.clear
|
|
244
|
+
file "#{@lib_dir}/#{binary}" => ["copy:#{@name}:#{cross_platform}"]
|
|
170
245
|
|
|
171
|
-
#
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
246
|
+
# if everything for native task is in place
|
|
247
|
+
if @gem_spec && @gem_spec.platform == 'ruby' then
|
|
248
|
+
Rake::Task['native'].prerequisites.clear
|
|
249
|
+
task 'native' => ["native:#{cross_platform}"]
|
|
175
250
|
end
|
|
176
251
|
end
|
|
252
|
+
end
|
|
177
253
|
|
|
178
|
-
|
|
179
|
-
|
|
254
|
+
def extconf
|
|
255
|
+
"#{@ext_dir}/#{@name}/#{@config_script}"
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
def make
|
|
259
|
+
RUBY_PLATFORM =~ /mswin/ ? 'nmake' : 'make'
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
def binary
|
|
263
|
+
"#{@name}.#{RbConfig::CONFIG['DLEXT']}"
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
def source_files
|
|
267
|
+
@source_files ||= FileList["#{@ext_dir}/#{@name}/#{@source_pattern}"]
|
|
180
268
|
end
|
|
181
269
|
end
|
|
182
270
|
end
|
|
@@ -80,13 +80,25 @@ describe Rake::ExtensionTask do
|
|
|
80
80
|
@ext.source_pattern.should == "*.c"
|
|
81
81
|
end
|
|
82
82
|
|
|
83
|
-
it 'should have no
|
|
84
|
-
@ext.
|
|
83
|
+
it 'should have no configuration options preset to delegate' do
|
|
84
|
+
@ext.config_options.should be_empty
|
|
85
85
|
end
|
|
86
86
|
|
|
87
87
|
it 'should default to current platform' do
|
|
88
88
|
@ext.platform.should == RUBY_PLATFORM
|
|
89
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
|
|
90
102
|
end
|
|
91
103
|
|
|
92
104
|
describe '(tasks)' do
|
|
@@ -109,8 +121,8 @@ describe Rake::ExtensionTask do
|
|
|
109
121
|
Rake::Task.task_defined?('compile').should be_true
|
|
110
122
|
end
|
|
111
123
|
|
|
112
|
-
it "should depend on 'compile:
|
|
113
|
-
Rake::Task['compile'].prerequisites.should include(
|
|
124
|
+
it "should depend on 'compile:{platform}'" do
|
|
125
|
+
Rake::Task['compile'].prerequisites.should include("compile:#{@platform}")
|
|
114
126
|
end
|
|
115
127
|
end
|
|
116
128
|
|
|
@@ -119,8 +131,8 @@ describe Rake::ExtensionTask do
|
|
|
119
131
|
Rake::Task.task_defined?('compile:extension_one').should be_true
|
|
120
132
|
end
|
|
121
133
|
|
|
122
|
-
it "should depend on '
|
|
123
|
-
Rake::Task['compile:extension_one'].prerequisites.should include("
|
|
134
|
+
it "should depend on 'compile:extension_one:{platform}'" do
|
|
135
|
+
Rake::Task['compile:extension_one'].prerequisites.should include("compile:extension_one:#{@platform}")
|
|
124
136
|
end
|
|
125
137
|
end
|
|
126
138
|
|
|
@@ -129,12 +141,8 @@ describe Rake::ExtensionTask do
|
|
|
129
141
|
Rake::Task.task_defined?("lib/#{@ext_bin}").should be_true
|
|
130
142
|
end
|
|
131
143
|
|
|
132
|
-
it "should depend on '
|
|
133
|
-
Rake::Task["lib/#{@ext_bin}"].prerequisites.should include("
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
it "should depend on 'tmp/extension_one.{so,bundle}'" do
|
|
137
|
-
Rake::Task["lib/#{@ext_bin}"].prerequisites.should include("tmp/#{@platform}/extension_one/#{@ext_bin}")
|
|
144
|
+
it "should depend on 'copy:extension_one:{platform}'" do
|
|
145
|
+
Rake::Task["lib/#{@ext_bin}"].prerequisites.should include("copy:extension_one:#{@platform}")
|
|
138
146
|
end
|
|
139
147
|
end
|
|
140
148
|
|
|
@@ -192,6 +200,7 @@ describe Rake::ExtensionTask do
|
|
|
192
200
|
Rake::FileList.stub!(:[]).and_return(["ext/extension_one/source.c"])
|
|
193
201
|
@spec = mock_gem_spec
|
|
194
202
|
@ext_bin = ext_bin('extension_one')
|
|
203
|
+
@platform = RUBY_PLATFORM
|
|
195
204
|
end
|
|
196
205
|
|
|
197
206
|
describe 'native' do
|
|
@@ -216,15 +225,93 @@ describe Rake::ExtensionTask do
|
|
|
216
225
|
Rake::Task.task_defined?('native').should be_false
|
|
217
226
|
end
|
|
218
227
|
|
|
219
|
-
it 'should depend on
|
|
228
|
+
it 'should depend on platform specific native tasks' do
|
|
220
229
|
Rake::ExtensionTask.new('extension_one', @spec)
|
|
221
|
-
Rake::Task["native"].prerequisites.should include("native
|
|
230
|
+
Rake::Task["native"].prerequisites.should include("native:#{@platform}")
|
|
222
231
|
end
|
|
223
232
|
|
|
224
|
-
describe 'native:my_gem' do
|
|
233
|
+
describe 'native:my_gem:{platform}' do
|
|
225
234
|
it 'should depend on binary extension' do
|
|
226
235
|
Rake::ExtensionTask.new('extension_one', @spec)
|
|
227
|
-
Rake::Task["native:my_gem"].prerequisites.should include("
|
|
236
|
+
Rake::Task["native:my_gem:#{@platform}"].prerequisites.should include("tmp/#{@platform}/extension_one/#{@ext_bin}")
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
describe '(cross platform tasks)' do
|
|
243
|
+
before :each do
|
|
244
|
+
File.stub!(:exist?).and_return(true)
|
|
245
|
+
YAML.stub!(:load_file).and_return(mock_config_yml)
|
|
246
|
+
Rake::FileList.stub!(:[]).and_return(["ext/extension_one/source.c"])
|
|
247
|
+
@spec = mock_gem_spec
|
|
248
|
+
@config_file = File.expand_path("~/.rake-compiler/config.yml")
|
|
249
|
+
@major_ver = RUBY_VERSION.match(/(\d+.\d+)/)[1]
|
|
250
|
+
@config_path = mock_config_yml["rbconfig-#{@major_ver}"]
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
it 'should not generate an error if no rake-compiler configuration exist' do
|
|
254
|
+
File.should_receive(:exist?).with(@config_file).and_return(false)
|
|
255
|
+
lambda {
|
|
256
|
+
Rake::ExtensionTask.new('extension_one') do |ext|
|
|
257
|
+
ext.cross_compile = true
|
|
258
|
+
end
|
|
259
|
+
}.should_not raise_error(RuntimeError)
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
it 'should parse the config file using YAML' do
|
|
263
|
+
YAML.should_receive(:load_file).with(@config_file).and_return(mock_config_yml)
|
|
264
|
+
Rake::ExtensionTask.new('extension_one') do |ext|
|
|
265
|
+
ext.cross_compile = true
|
|
266
|
+
end
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
it 'should fail if no section of config file defines running version of ruby' do
|
|
270
|
+
config = mock(Hash)
|
|
271
|
+
config.should_receive(:[]).with("rbconfig-#{@major_ver}").and_return(nil)
|
|
272
|
+
YAML.stub!(:load_file).and_return(config)
|
|
273
|
+
lambda {
|
|
274
|
+
Rake::ExtensionTask.new('extension_one') do |ext|
|
|
275
|
+
ext.cross_compile = true
|
|
276
|
+
end
|
|
277
|
+
}.should raise_error(RuntimeError, /no configuration section for this version of Ruby/)
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
describe "(cross for 'universal-unknown' platform)" do
|
|
281
|
+
before :each do
|
|
282
|
+
@ext = Rake::ExtensionTask.new('extension_one', @spec) do |ext|
|
|
283
|
+
ext.cross_compile = true
|
|
284
|
+
ext.cross_platform = 'universal-unknown'
|
|
285
|
+
end
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
describe 'rbconfig' do
|
|
289
|
+
it 'should chain rbconfig tasks to Makefile generation' do
|
|
290
|
+
Rake::Task['tmp/universal-unknown/extension_one/Makefile'].prerequisites.should include('tmp/universal-unknown/extension_one/rbconfig.rb')
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
it 'should take rbconfig from rake-compiler configuration' do
|
|
294
|
+
Rake::Task['tmp/universal-unknown/extension_one/rbconfig.rb'].prerequisites.should include(@config_path)
|
|
295
|
+
end
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
describe 'compile:universal-unknown' do
|
|
299
|
+
it "should be defined" do
|
|
300
|
+
Rake::Task.task_defined?('compile:universal-unknown').should be_true
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
it "should depend on 'compile:extension_one:universal-unknown'" do
|
|
304
|
+
Rake::Task['compile:universal-unknown'].prerequisites.should include('compile:extension_one:universal-unknown')
|
|
305
|
+
end
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
describe 'native:universal-unknown' do
|
|
309
|
+
it "should be defined" do
|
|
310
|
+
Rake::Task.task_defined?('native:universal-unknown').should be_true
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
it "should depend on 'native:my_gem:universal-unknown'" do
|
|
314
|
+
Rake::Task['native:universal-unknown'].prerequisites.should include('native:my_gem:universal-unknown')
|
|
228
315
|
end
|
|
229
316
|
end
|
|
230
317
|
end
|
|
@@ -242,4 +329,10 @@ describe Rake::ExtensionTask do
|
|
|
242
329
|
)
|
|
243
330
|
end
|
|
244
331
|
|
|
332
|
+
def mock_config_yml
|
|
333
|
+
{
|
|
334
|
+
'rbconfig-1.8' => '/some/path/version/1.8/to/rbconfig.rb',
|
|
335
|
+
'rbconfig-1.9' => '/some/path/version/1.9/to/rbconfig.rb'
|
|
336
|
+
}
|
|
337
|
+
end
|
|
245
338
|
end
|
data/tasks/rubygems.rake
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: luislavena-rake-compiler
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Luis Lavena
|
|
@@ -9,7 +9,7 @@ autorequire:
|
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
11
|
|
|
12
|
-
date: 2008-11-
|
|
12
|
+
date: 2008-11-28 18:00:00 -08:00
|
|
13
13
|
default_executable:
|
|
14
14
|
dependencies:
|
|
15
15
|
- !ruby/object:Gem::Dependency
|
|
@@ -36,8 +36,11 @@ extra_rdoc_files:
|
|
|
36
36
|
- LICENSE.txt
|
|
37
37
|
files:
|
|
38
38
|
- features/compile.feature
|
|
39
|
+
- features/cross-compile.feature
|
|
40
|
+
- features/cross-package.feature
|
|
39
41
|
- features/package.feature
|
|
40
42
|
- features/step_definitions/compilation.rb
|
|
43
|
+
- features/step_definitions/cross_compilation.rb
|
|
41
44
|
- features/step_definitions/execution.rb
|
|
42
45
|
- features/step_definitions/folders.rb
|
|
43
46
|
- features/step_definitions/gem.rb
|