gem-compiler 0.8.0 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG.md +20 -1
- data/README.md +95 -19
- data/Rakefile +2 -0
- data/lib/rubygems/commands/compile_command.rb +37 -4
- data/lib/rubygems/compiler.rb +76 -22
- data/lib/rubygems/compiler/version.rb +2 -1
- data/lib/rubygems_plugin.rb +2 -0
- data/test/rubygems/test_gem_commands_compile_command.rb +53 -0
- data/test/rubygems/test_gem_compiler.rb +159 -12
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f715fe84339746f8ec890e713c7e162bb73d53d5
|
4
|
+
data.tar.gz: 5898f0dfb960d964755662674c469c84d95e5db4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b879e33e40fa3ed600305f8c759caae5d3387af03577eb5fdf7bd5e8b3e61029edd7a5f5d3bdb33c6ca5a3fe5f6fa2beec001b48f70492f24042a74e51f9380d
|
7
|
+
data.tar.gz: 1212ed35d0ae616c54e1df0a857b40cfb83e03d6bcf52030e34e2d5ac160ca74097bee9ba360f0a4db4d19d22236b62524481700cfda2fbbbc553e6be247fc9c
|
data/CHANGELOG.md
CHANGED
@@ -10,6 +10,24 @@ upgrading.
|
|
10
10
|
|
11
11
|
## [Unreleased]
|
12
12
|
|
13
|
+
## [0.9.0] - 2020-04-05
|
14
|
+
|
15
|
+
### Added
|
16
|
+
- Allow symbol stripping from extensions (using `--strip`). (#40, #48, #50)
|
17
|
+
- Introduce more strict Ruby version locking (using `--abi-lock`). (#51, #52)
|
18
|
+
|
19
|
+
### Fixed
|
20
|
+
- Solve upcoming RubyGems deprecation warnings
|
21
|
+
|
22
|
+
### Changed
|
23
|
+
- Deal with RubyGems 3.x `new_spec` deprecation in tests.
|
24
|
+
- CI: Replace Travis/AppVeyor with GitHub Actions for Ubuntu, macOS and Windows.
|
25
|
+
- No longer raise exceptions when executed against non-compilable gems. (#38, #47)
|
26
|
+
|
27
|
+
### Removed
|
28
|
+
- Drop support for Ruby 2.3.x, as it reached EOL (End Of Life)
|
29
|
+
- Drop support for RubyGems older than 2.6.0 (Ruby 2.4 includes RubyGems 2.6.8)
|
30
|
+
|
13
31
|
## [0.8.0] - 2017-12-28
|
14
32
|
|
15
33
|
### Added
|
@@ -94,7 +112,8 @@ upgrading.
|
|
94
112
|
|
95
113
|
- Initial public release, extracted from internal project.
|
96
114
|
|
97
|
-
[Unreleased]: https://github.com/luislavena/gem-compiler/compare/v0.
|
115
|
+
[Unreleased]: https://github.com/luislavena/gem-compiler/compare/v0.9.0...HEAD
|
116
|
+
[0.8.0]: https://github.com/luislavena/gem-compiler/compare/v0.8.0...v0.9.0
|
98
117
|
[0.8.0]: https://github.com/luislavena/gem-compiler/compare/v0.7.0...v0.8.0
|
99
118
|
[0.7.0]: https://github.com/luislavena/gem-compiler/compare/v0.6.0...v0.7.0
|
100
119
|
[0.6.0]: https://github.com/luislavena/gem-compiler/compare/v0.5.0...v0.6.0
|
data/README.md
CHANGED
@@ -3,8 +3,6 @@
|
|
3
3
|
A RubyGems plugin that generates binary (pre-compiled) gems.
|
4
4
|
|
5
5
|
[![Gem Version](https://img.shields.io/gem/v/gem-compiler.svg)](https://rubygems.org/gems/gem-compiler)
|
6
|
-
[![Travis status](https://img.shields.io/travis/luislavena/gem-compiler/master.svg)](https://travis-ci.org/luislavena/gem-compiler)
|
7
|
-
[![AppVeyor status](https://img.shields.io/appveyor/ci/luislavena/gem-compiler/master.svg)](https://ci.appveyor.com/project/luislavena/gem-compiler)
|
8
6
|
[![Code Climate](https://img.shields.io/codeclimate/github/luislavena/gem-compiler.svg)](https://codeclimate.com/github/luislavena/gem-compiler)
|
9
7
|
|
10
8
|
- [home](https://github.com/luislavena/gem-compiler)
|
@@ -19,8 +17,49 @@ Ruby C extensions and bundles the result into a new gem.
|
|
19
17
|
It uses an *outside-in* approach and leverages on existing RubyGems code to
|
20
18
|
do it.
|
21
19
|
|
22
|
-
|
23
|
-
|
20
|
+
## Benefits
|
21
|
+
|
22
|
+
Using `gem-compiler` removes the need to install a compiler toolchain on the
|
23
|
+
platform used to run the extension. This means less dependencies are required
|
24
|
+
in those systems and can reduce associated update/maintenance cycles.
|
25
|
+
|
26
|
+
Additionally, by having only binaries, it reduces the time it takes to install
|
27
|
+
several gems that normally take minutes to compile themselves and the needed
|
28
|
+
dependencies.
|
29
|
+
|
30
|
+
Without `gem-compiler`, takes more than a minute to install Nokogiri on
|
31
|
+
Ubuntu 18.04:
|
32
|
+
|
33
|
+
```console
|
34
|
+
$ time gem install --local nokogiri-1.10.7.gem
|
35
|
+
Building native extensions. This could take a while...
|
36
|
+
Successfully installed nokogiri-1.10.7
|
37
|
+
1 gem installed
|
38
|
+
|
39
|
+
real 1m22.670s
|
40
|
+
user 1m5.856s
|
41
|
+
sys 0m18.637s
|
42
|
+
```
|
43
|
+
|
44
|
+
Compared to the installation of the pre-compiled version:
|
45
|
+
|
46
|
+
```console
|
47
|
+
$ gem compile nokogiri-1.10.7.gem --prune
|
48
|
+
Unpacking gem: 'nokogiri-1.10.7' in temporary directory...
|
49
|
+
Building native extensions. This could take a while...
|
50
|
+
Successfully built RubyGem
|
51
|
+
Name: nokogiri
|
52
|
+
Version: 1.10.7
|
53
|
+
File: nokogiri-1.10.7-x86_64-linux.gem
|
54
|
+
|
55
|
+
$ time gem install --local nokogiri-1.10.7-x86_64-linux.gem
|
56
|
+
Successfully installed nokogiri-1.10.7-x86_64-linux
|
57
|
+
1 gem installed
|
58
|
+
|
59
|
+
real 0m1.697s
|
60
|
+
user 0m1.281s
|
61
|
+
sys 0m0.509s
|
62
|
+
```
|
24
63
|
|
25
64
|
## Installation
|
26
65
|
|
@@ -91,22 +130,59 @@ process:
|
|
91
130
|
Successfully installed nokogiri-1.6.6.2-x86_64-darwin-12
|
92
131
|
1 gem installed
|
93
132
|
|
94
|
-
####
|
133
|
+
#### Restricting generated binary gems
|
134
|
+
|
135
|
+
Gems compiled with `gem-compiler` be lock to the version of Ruby used
|
136
|
+
to compile them, following Ruby's ABI compatibility (`MAJOR.MINOR`)
|
137
|
+
|
138
|
+
This means that a gem compiled with Ruby 2.6.1 could be installed in any
|
139
|
+
version of Ruby 2.6.x (Eg. 2.6.4).
|
140
|
+
|
141
|
+
You can tweak this behavior by using `--abi-lock` option during compilation.
|
142
|
+
There are 3 available modes:
|
95
143
|
|
96
|
-
|
97
|
-
|
144
|
+
* `ruby`: Follows Ruby's ABI. Gems compiled with Ruby 2.6.1 can be installed
|
145
|
+
in any Ruby 2.6.x (default behavior).
|
146
|
+
* `strict`: Uses Ruby's full version. Gems compiled with Ruby 2.6.1 can only
|
147
|
+
be installed in Ruby 2.6.1.
|
148
|
+
* `none`: Disables Ruby compatibility. Gems compiled with this option can be
|
149
|
+
installed on any version of Ruby (alias for `--no-abi-lock`).
|
98
150
|
|
99
|
-
|
100
|
-
Ruby
|
151
|
+
**Warning**: usage of `none` is not recommended since different versions of
|
152
|
+
Ruby might expose different APIs. The binary might be expecting specific
|
153
|
+
features not present in the version of Ruby you're installing the gem into.
|
101
154
|
|
102
|
-
|
155
|
+
#### Reducing extension's size (stripping)
|
103
156
|
|
104
|
-
|
157
|
+
By default, RubyGems do not strip symbols from compiled extensions, including
|
158
|
+
debugging information and can result in increased size of final package.
|
105
159
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
160
|
+
With `--strip`, you can reduce extensions by using same stripping options used
|
161
|
+
by Ruby itself (see `RbConfig::CONFIG["STRIP"]`):
|
162
|
+
|
163
|
+
```console
|
164
|
+
$ gem compile oj-3.10.0.gem --strip
|
165
|
+
Unpacking gem: 'oj-3.10.0' in temporary directory...
|
166
|
+
Building native extensions. This could take a while...
|
167
|
+
Stripping symbols from extensions (using 'strip -S -x')...
|
168
|
+
Successfully built RubyGem
|
169
|
+
Name: oj
|
170
|
+
Version: 3.10.0
|
171
|
+
File: oj-3.10.0-x86_64-linux.gem
|
172
|
+
```
|
173
|
+
|
174
|
+
Or you can provide your own stripping command instead:
|
175
|
+
|
176
|
+
```console
|
177
|
+
$ gem compile oj-3.10.0.gem --strip "strip --strip-unneeded"
|
178
|
+
Unpacking gem: 'oj-3.10.0' in temporary directory...
|
179
|
+
Building native extensions. This could take a while...
|
180
|
+
Stripping symbols from extensions (using 'strip --strip-unneeded')...
|
181
|
+
Successfully built RubyGem
|
182
|
+
Name: oj
|
183
|
+
Version: 3.10.0
|
184
|
+
File: oj-3.10.0-x86_64-linux.gem
|
185
|
+
```
|
110
186
|
|
111
187
|
### Compiling from Rake
|
112
188
|
|
@@ -129,9 +205,9 @@ required.
|
|
129
205
|
### Ruby and RubyGems
|
130
206
|
|
131
207
|
It's assumed you have Ruby and RubyGems installed. gem-compiler requires
|
132
|
-
RubyGems
|
208
|
+
RubyGems 2.6.x to work.
|
133
209
|
|
134
|
-
If you don't have RubyGems
|
210
|
+
If you don't have RubyGems 2.6.x, you can upgrade by running:
|
135
211
|
|
136
212
|
$ gem update --system
|
137
213
|
|
@@ -146,7 +222,7 @@ right one.
|
|
146
222
|
|
147
223
|
For those using RubyInstaller-based builds, you will need to download the
|
148
224
|
DevKit from their [downloads page](http://rubyinstaller.org/downloads)
|
149
|
-
and follow the
|
225
|
+
and follow the installation instructions.
|
150
226
|
|
151
227
|
To be sure your installation of Ruby is based on RubyInstaller, execute at
|
152
228
|
the command prompt:
|
@@ -155,7 +231,7 @@ the command prompt:
|
|
155
231
|
|
156
232
|
And from the output:
|
157
233
|
|
158
|
-
|
234
|
+
ruby 2.4.9p362 (2019-10-02 revision 67824) [x64-mingw32]
|
159
235
|
|
160
236
|
If you see `mingw32`, that means you're using a RubyInstaller build
|
161
237
|
(MinGW based).
|
data/Rakefile
CHANGED
@@ -1,9 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rbconfig"
|
1
4
|
require "rubygems/command"
|
2
5
|
|
3
6
|
class Gem::Commands::CompileCommand < Gem::Command
|
7
|
+
ABIs = {
|
8
|
+
"ruby" => :ruby,
|
9
|
+
"strict" => :strict,
|
10
|
+
"none" => :none
|
11
|
+
}.freeze
|
12
|
+
|
4
13
|
def initialize
|
5
|
-
|
6
|
-
|
14
|
+
defaults = {
|
15
|
+
output: Dir.pwd,
|
16
|
+
abi_lock: :ruby
|
17
|
+
}
|
18
|
+
|
19
|
+
super "compile", "Create binary pre-compiled gem", defaults
|
7
20
|
|
8
21
|
add_option "-O", "--output DIR", "Directory where binary will be stored" do |value, options|
|
9
22
|
options[:output] = File.expand_path(value, Dir.pwd)
|
@@ -17,8 +30,28 @@ class Gem::Commands::CompileCommand < Gem::Command
|
|
17
30
|
options[:prune] = true
|
18
31
|
end
|
19
32
|
|
20
|
-
add_option "
|
21
|
-
|
33
|
+
add_option "--abi-lock MODE",
|
34
|
+
"Lock to version of Ruby (ruby, strict, none)" do |value, options|
|
35
|
+
|
36
|
+
mode = ABIs[value]
|
37
|
+
unless mode
|
38
|
+
valid = ABIs.keys.sort
|
39
|
+
raise OptionParser::InvalidArgument, "#{value} (#{valid.join ', '} are valid)"
|
40
|
+
end
|
41
|
+
|
42
|
+
options[:abi_lock] = mode
|
43
|
+
end
|
44
|
+
|
45
|
+
add_option "-N", "--no-abi-lock", "Do not lock compiled Gem to Ruby's ABI (same as --abi-lock=none)" do |value, options|
|
46
|
+
options[:abi_lock] = :none
|
47
|
+
end
|
48
|
+
|
49
|
+
add_option "-S", "--strip [CMD]", "Strip symbols from generated binaries" do |value, options|
|
50
|
+
if value.nil? || value.empty?
|
51
|
+
options[:strip] = RbConfig::CONFIG["STRIP"]
|
52
|
+
else
|
53
|
+
options[:strip] = value
|
54
|
+
end
|
22
55
|
end
|
23
56
|
end
|
24
57
|
|
data/lib/rubygems/compiler.rb
CHANGED
@@ -1,4 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "fileutils"
|
4
|
+
require "open3"
|
2
5
|
require "rbconfig"
|
3
6
|
require "tmpdir"
|
4
7
|
require "rubygems/installer"
|
@@ -25,6 +28,8 @@ class Gem::Compiler
|
|
25
28
|
|
26
29
|
artifacts = collect_artifacts
|
27
30
|
|
31
|
+
strip_artifacts artifacts
|
32
|
+
|
28
33
|
if shared_dir = options[:include_shared_dir]
|
29
34
|
shared_libs = collect_shared(shared_dir)
|
30
35
|
|
@@ -44,6 +49,19 @@ class Gem::Compiler
|
|
44
49
|
|
45
50
|
private
|
46
51
|
|
52
|
+
def adjust_abi_lock(gemspec)
|
53
|
+
abi_lock = @options[:abi_lock] || :ruby
|
54
|
+
case abi_lock
|
55
|
+
when :ruby
|
56
|
+
ruby_abi = RbConfig::CONFIG["ruby_version"]
|
57
|
+
gemspec.required_ruby_version = "~> #{ruby_abi}"
|
58
|
+
when :strict
|
59
|
+
cfg = RbConfig::CONFIG
|
60
|
+
ruby_abi = "#{cfg["MAJOR"]}.#{cfg["MINOR"]}.#{cfg["TEENY"]}.0"
|
61
|
+
gemspec.required_ruby_version = "~> #{ruby_abi}"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
47
65
|
def adjust_gemspec_files(gemspec, artifacts)
|
48
66
|
# remove any non-existing files
|
49
67
|
if @options[:prune]
|
@@ -115,19 +133,9 @@ class Gem::Compiler
|
|
115
133
|
end
|
116
134
|
|
117
135
|
def prepare_installer
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
installer = Gem::Installer.at(@gemfile, unpack_options)
|
122
|
-
else
|
123
|
-
installer = Gem::Installer.new(@gemfile, options.dup.merge(unpack: true))
|
124
|
-
end
|
125
|
-
|
126
|
-
# RubyGems 2.2 specifics
|
127
|
-
if installer.spec.respond_to?(:full_gem_path=)
|
128
|
-
installer.spec.full_gem_path = @target_dir
|
129
|
-
installer.spec.extension_dir = File.join(@target_dir, "lib")
|
130
|
-
end
|
136
|
+
installer = Gem::Installer.at(@gemfile, options.dup.merge(unpack: true))
|
137
|
+
installer.spec.full_gem_path = @target_dir
|
138
|
+
installer.spec.extension_dir = File.join(@target_dir, "lib")
|
131
139
|
|
132
140
|
# Ensure Ruby version is met
|
133
141
|
if installer.respond_to?(:ensure_required_ruby_version_met)
|
@@ -141,14 +149,16 @@ class Gem::Compiler
|
|
141
149
|
|
142
150
|
# Hmm, gem already compiled?
|
143
151
|
if installer.spec.platform != Gem::Platform::RUBY
|
144
|
-
|
145
|
-
|
152
|
+
info "The gem file seems to be compiled already. Skipping."
|
153
|
+
cleanup
|
154
|
+
terminate_interaction
|
146
155
|
end
|
147
156
|
|
148
157
|
# Hmm, no extensions?
|
149
158
|
if installer.spec.extensions.empty?
|
150
|
-
|
151
|
-
|
159
|
+
info "There are no extensions to build on this gem file. Skipping."
|
160
|
+
cleanup
|
161
|
+
terminate_interaction
|
152
162
|
end
|
153
163
|
|
154
164
|
installer
|
@@ -162,10 +172,7 @@ class Gem::Compiler
|
|
162
172
|
gemspec.platform = Gem::Platform::CURRENT
|
163
173
|
|
164
174
|
# adjust version of Ruby
|
165
|
-
|
166
|
-
ruby_abi = RbConfig::CONFIG["ruby_version"]
|
167
|
-
gemspec.required_ruby_version = "~> #{ruby_abi}"
|
168
|
-
end
|
175
|
+
adjust_abi_lock(gemspec)
|
169
176
|
|
170
177
|
# build new gem
|
171
178
|
output_gem = nil
|
@@ -186,6 +193,45 @@ class Gem::Compiler
|
|
186
193
|
output_gem
|
187
194
|
end
|
188
195
|
|
196
|
+
def simple_run(command, command_name)
|
197
|
+
begin
|
198
|
+
output, status = Open3.capture2e(*command)
|
199
|
+
rescue => error
|
200
|
+
raise Gem::CompilerError, "#{command_name} failed#{error.message}"
|
201
|
+
end
|
202
|
+
|
203
|
+
yield(status, output) if block_given?
|
204
|
+
|
205
|
+
unless status.success?
|
206
|
+
exit_reason =
|
207
|
+
if status.exited?
|
208
|
+
", exit code #{status.exitstatus}"
|
209
|
+
elsif status.signaled?
|
210
|
+
", uncaught signal #{status.termsig}"
|
211
|
+
end
|
212
|
+
|
213
|
+
raise Gem::CompilerError, "#{command_name} failed#{exit_reason}"
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
def strip_artifacts(artifacts)
|
218
|
+
return unless options[:strip]
|
219
|
+
|
220
|
+
strip_cmd = options[:strip]
|
221
|
+
|
222
|
+
info "Stripping symbols from extensions (using '#{strip_cmd}')..."
|
223
|
+
|
224
|
+
artifacts.each do |artifact|
|
225
|
+
cmd = [strip_cmd, artifact].join(' ').rstrip
|
226
|
+
|
227
|
+
simple_run(cmd, "strip #{File.basename(artifact)}") do |status, output|
|
228
|
+
if status.success?
|
229
|
+
debug "Stripped #{File.basename(artifact)}"
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
189
235
|
def tmp_dir
|
190
236
|
@tmp_dir ||= Dir.glob(Dir.mktmpdir).first
|
191
237
|
end
|
@@ -197,6 +243,14 @@ class Gem::Compiler
|
|
197
243
|
# unpack gem sources into target_dir
|
198
244
|
# We need the basename to keep the unpack happy
|
199
245
|
info "Unpacking gem: '#{basename}' in temporary directory..."
|
200
|
-
|
246
|
+
|
247
|
+
# RubyGems >= 3.1.x
|
248
|
+
if installer.respond_to?(:package)
|
249
|
+
package = installer.package
|
250
|
+
else
|
251
|
+
package = Gem::Package.new(@gemfile)
|
252
|
+
end
|
253
|
+
|
254
|
+
package.extract_files(@target_dir)
|
201
255
|
end
|
202
256
|
end
|
data/lib/rubygems_plugin.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "rubygems/test_case"
|
2
4
|
require "rubygems/commands/compile_command"
|
3
5
|
require "rubygems/package"
|
@@ -20,4 +22,55 @@ class TestGemCommandsCompileCommand < Gem::TestCase
|
|
20
22
|
|
21
23
|
assert_match %r{Please specify a gem file on the command line}, e.message
|
22
24
|
end
|
25
|
+
|
26
|
+
def test_handle_abi_lock_ruby
|
27
|
+
@cmd.handle_options []
|
28
|
+
|
29
|
+
assert_equal :ruby, @cmd.options[:abi_lock]
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_handle_abi_lock_explicit_ruby
|
33
|
+
@cmd.handle_options ["--abi-lock=ruby"]
|
34
|
+
|
35
|
+
assert_equal :ruby, @cmd.options[:abi_lock]
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_handle_abi_lock_strict
|
39
|
+
@cmd.handle_options ["--abi-lock=strict"]
|
40
|
+
|
41
|
+
assert_equal :strict, @cmd.options[:abi_lock]
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_handle_abi_lock_none
|
45
|
+
@cmd.handle_options ["--abi-lock=none"]
|
46
|
+
|
47
|
+
assert_equal :none, @cmd.options[:abi_lock]
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_handle_no_abi_lock_none
|
51
|
+
@cmd.handle_options ["--no-abi-lock"]
|
52
|
+
|
53
|
+
assert_equal :none, @cmd.options[:abi_lock]
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_handle_abi_lock_unknown
|
57
|
+
e = assert_raises OptionParser::InvalidArgument do
|
58
|
+
@cmd.handle_options %w[--abi-lock unknown]
|
59
|
+
end
|
60
|
+
|
61
|
+
assert_equal "invalid argument: --abi-lock unknown (none, ruby, strict are valid)",
|
62
|
+
e.message
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_handle_strip_default
|
66
|
+
@cmd.handle_options %w[--strip]
|
67
|
+
|
68
|
+
assert_equal RbConfig::CONFIG["STRIP"], @cmd.options[:strip]
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_handle_strip_custom
|
72
|
+
@cmd.handle_options ["--strip", "strip --custom"]
|
73
|
+
|
74
|
+
assert_equal "strip --custom", @cmd.options[:strip]
|
75
|
+
end
|
23
76
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "rubygems/test_case"
|
2
4
|
require "rubygems/compiler"
|
3
5
|
|
@@ -25,14 +27,16 @@ class TestGemCompiler < Gem::TestCase
|
|
25
27
|
|
26
28
|
compiler = Gem::Compiler.new(gem_file, :output => @output_dir)
|
27
29
|
|
28
|
-
|
30
|
+
assert_raises Gem::MockGemUi::SystemExitException do
|
29
31
|
use_ui @ui do
|
30
32
|
compiler.compile
|
31
33
|
end
|
32
34
|
end
|
33
35
|
|
34
|
-
|
35
|
-
|
36
|
+
out = @ui.output.split "\n"
|
37
|
+
|
38
|
+
assert_equal "There are no extensions to build on this gem file. Skipping.",
|
39
|
+
out.last
|
36
40
|
end
|
37
41
|
|
38
42
|
def test_compile_non_ruby
|
@@ -40,13 +44,15 @@ class TestGemCompiler < Gem::TestCase
|
|
40
44
|
|
41
45
|
compiler = Gem::Compiler.new(gem_file, :output => @output_dir)
|
42
46
|
|
43
|
-
|
47
|
+
assert_raises Gem::MockGemUi::SystemExitException do
|
44
48
|
use_ui @ui do
|
45
49
|
compiler.compile
|
46
50
|
end
|
47
51
|
end
|
48
52
|
|
49
|
-
|
53
|
+
out = @ui.output.split "\n"
|
54
|
+
|
55
|
+
assert_equal "The gem file seems to be compiled already. Skipping.", out.last
|
50
56
|
end
|
51
57
|
|
52
58
|
def test_compile_pre_install_hooks
|
@@ -307,7 +313,7 @@ class TestGemCompiler < Gem::TestCase
|
|
307
313
|
util_reset_arch
|
308
314
|
end
|
309
315
|
|
310
|
-
def
|
316
|
+
def test_compile_abi_lock_ruby
|
311
317
|
util_reset_arch
|
312
318
|
|
313
319
|
ruby_abi = RbConfig::CONFIG["ruby_version"]
|
@@ -317,7 +323,29 @@ class TestGemCompiler < Gem::TestCase
|
|
317
323
|
util_fake_extension s, "foo", util_custom_configure(artifact)
|
318
324
|
}
|
319
325
|
|
320
|
-
compiler = Gem::Compiler.new(gem_file, :output => @output_dir)
|
326
|
+
compiler = Gem::Compiler.new(gem_file, :output => @output_dir, :abi_lock => nil)
|
327
|
+
output_gem = nil
|
328
|
+
|
329
|
+
use_ui @ui do
|
330
|
+
output_gem = compiler.compile
|
331
|
+
end
|
332
|
+
|
333
|
+
spec = util_read_spec File.join(@output_dir, output_gem)
|
334
|
+
|
335
|
+
assert_equal Gem::Requirement.new("~> #{ruby_abi}"), spec.required_ruby_version
|
336
|
+
end
|
337
|
+
|
338
|
+
def test_compile_abi_lock_explicit_ruby
|
339
|
+
util_reset_arch
|
340
|
+
|
341
|
+
ruby_abi = RbConfig::CONFIG["ruby_version"]
|
342
|
+
artifact = "foo.#{RbConfig::CONFIG["DLEXT"]}"
|
343
|
+
|
344
|
+
gem_file = util_bake_gem("foo") { |s|
|
345
|
+
util_fake_extension s, "foo", util_custom_configure(artifact)
|
346
|
+
}
|
347
|
+
|
348
|
+
compiler = Gem::Compiler.new(gem_file, :output => @output_dir, :abi_lock => :ruby)
|
321
349
|
output_gem = nil
|
322
350
|
|
323
351
|
use_ui @ui do
|
@@ -326,19 +354,65 @@ class TestGemCompiler < Gem::TestCase
|
|
326
354
|
|
327
355
|
spec = util_read_spec File.join(@output_dir, output_gem)
|
328
356
|
|
329
|
-
assert_equal
|
357
|
+
assert_equal Gem::Requirement.new("~> #{ruby_abi}"), spec.required_ruby_version
|
330
358
|
end
|
331
359
|
|
332
|
-
def
|
360
|
+
def test_compile_abi_lock_strict
|
333
361
|
util_reset_arch
|
334
362
|
|
363
|
+
ruby_abi = "%d.%d.%d.0" % RbConfig::CONFIG.values_at("MAJOR", "MINOR", "TEENY")
|
335
364
|
artifact = "foo.#{RbConfig::CONFIG["DLEXT"]}"
|
336
365
|
|
337
366
|
gem_file = util_bake_gem("foo") { |s|
|
338
367
|
util_fake_extension s, "foo", util_custom_configure(artifact)
|
339
368
|
}
|
340
369
|
|
341
|
-
compiler = Gem::Compiler.new(gem_file, :output => @output_dir, :
|
370
|
+
compiler = Gem::Compiler.new(gem_file, :output => @output_dir, :abi_lock => :strict)
|
371
|
+
output_gem = nil
|
372
|
+
|
373
|
+
use_ui @ui do
|
374
|
+
output_gem = compiler.compile
|
375
|
+
end
|
376
|
+
|
377
|
+
spec = util_read_spec File.join(@output_dir, output_gem)
|
378
|
+
|
379
|
+
assert_equal Gem::Requirement.new("~> #{ruby_abi}"), spec.required_ruby_version
|
380
|
+
end
|
381
|
+
|
382
|
+
def test_compile_abi_lock_none
|
383
|
+
util_reset_arch
|
384
|
+
|
385
|
+
artifact = "foo.#{RbConfig::CONFIG["DLEXT"]}"
|
386
|
+
|
387
|
+
gem_file = util_bake_gem("foo") { |s|
|
388
|
+
util_fake_extension s, "foo", util_custom_configure(artifact)
|
389
|
+
}
|
390
|
+
|
391
|
+
compiler = Gem::Compiler.new(gem_file, :output => @output_dir, :abi_lock => :none)
|
392
|
+
output_gem = nil
|
393
|
+
|
394
|
+
use_ui @ui do
|
395
|
+
output_gem = compiler.compile
|
396
|
+
end
|
397
|
+
|
398
|
+
spec = util_read_spec File.join(@output_dir, output_gem)
|
399
|
+
|
400
|
+
assert_equal Gem::Requirement.new(">= 0"), spec.required_ruby_version
|
401
|
+
end
|
402
|
+
|
403
|
+
def test_compile_strip_cmd
|
404
|
+
util_reset_arch
|
405
|
+
hook_simple_run
|
406
|
+
|
407
|
+
old_rbconfig_strip = RbConfig::CONFIG["STRIP"]
|
408
|
+
RbConfig::CONFIG["STRIP"] = "rbconfig-strip-cmd"
|
409
|
+
|
410
|
+
gem_file = util_bake_gem("foo") do |spec|
|
411
|
+
util_dummy_extension spec, "bar"
|
412
|
+
end
|
413
|
+
|
414
|
+
compiler = Gem::Compiler.new(gem_file, :output => @output_dir,
|
415
|
+
:strip => "echo strip-custom")
|
342
416
|
output_gem = nil
|
343
417
|
|
344
418
|
use_ui @ui do
|
@@ -346,8 +420,38 @@ class TestGemCompiler < Gem::TestCase
|
|
346
420
|
end
|
347
421
|
|
348
422
|
spec = util_read_spec File.join(@output_dir, output_gem)
|
423
|
+
assert_includes spec.files, "lib/bar.#{RbConfig::CONFIG["DLEXT"]}"
|
424
|
+
|
425
|
+
assert_match %r|Stripping symbols from extensions|, @ui.output
|
426
|
+
refute_match %r|#{RbConfig::CONFIG["STRIP"]}|, @ui.output
|
427
|
+
assert_match %r|using 'echo strip-custom'|, @ui.output
|
428
|
+
ensure
|
429
|
+
RbConfig::CONFIG["STRIP"] = old_rbconfig_strip
|
430
|
+
restore_simple_run
|
431
|
+
end
|
432
|
+
|
433
|
+
##
|
434
|
+
# Replace `simple_run` to help testing command execution
|
435
|
+
|
436
|
+
def hook_simple_run
|
437
|
+
Gem::Compiler.class_eval do
|
438
|
+
alias_method :orig_simple_run, :simple_run
|
439
|
+
remove_method :simple_run
|
440
|
+
|
441
|
+
def simple_run(command, command_name)
|
442
|
+
say "#{command_name}: #{command}"
|
443
|
+
end
|
444
|
+
end
|
445
|
+
end
|
446
|
+
|
447
|
+
##
|
448
|
+
# Restore `simple_run` to its original version
|
349
449
|
|
350
|
-
|
450
|
+
def restore_simple_run
|
451
|
+
Gem::Compiler.class_eval do
|
452
|
+
remove_method :simple_run
|
453
|
+
alias_method :simple_run, :orig_simple_run
|
454
|
+
end
|
351
455
|
end
|
352
456
|
|
353
457
|
##
|
@@ -364,11 +468,54 @@ class TestGemCompiler < Gem::TestCase
|
|
364
468
|
def util_bake_gem(name = "a", *extra, &block)
|
365
469
|
files = ["lib/#{name}.rb"].concat(extra)
|
366
470
|
|
367
|
-
spec =
|
471
|
+
spec = if Gem::VERSION >= "3.0.0"
|
472
|
+
util_spec name, "1", nil, files, &block
|
473
|
+
else
|
474
|
+
new_spec name, "1", nil, files, &block
|
475
|
+
end
|
368
476
|
|
369
477
|
File.join @tempdir, "gems", "#{spec.full_name}.gem"
|
370
478
|
end
|
371
479
|
|
480
|
+
##
|
481
|
+
# Add a dummy, valid extension to provided spec
|
482
|
+
|
483
|
+
def util_dummy_extension(spec, name = "a")
|
484
|
+
extconf = File.join("ext", name, "extconf.rb")
|
485
|
+
dummy_c = File.join("ext", name, "dummy.c")
|
486
|
+
|
487
|
+
spec.extensions << extconf
|
488
|
+
spec.files << dummy_c
|
489
|
+
|
490
|
+
dir = spec.gem_dir
|
491
|
+
FileUtils.mkdir_p dir
|
492
|
+
|
493
|
+
Dir.chdir dir do
|
494
|
+
FileUtils.mkdir_p File.dirname(extconf)
|
495
|
+
|
496
|
+
# extconf.rb
|
497
|
+
File.open extconf, "w" do |f|
|
498
|
+
f.write <<~EOF
|
499
|
+
require "mkmf"
|
500
|
+
|
501
|
+
create_makefile("#{name}")
|
502
|
+
EOF
|
503
|
+
end
|
504
|
+
|
505
|
+
# dummy.c
|
506
|
+
File.open dummy_c, "w" do |f|
|
507
|
+
f.write <<~EOF
|
508
|
+
#include <ruby.h>
|
509
|
+
|
510
|
+
void Init_#{name}(void)
|
511
|
+
{
|
512
|
+
rb_p(ID2SYM(rb_intern("ok")));
|
513
|
+
}
|
514
|
+
EOF
|
515
|
+
end
|
516
|
+
end
|
517
|
+
end
|
518
|
+
|
372
519
|
##
|
373
520
|
# Add a fake extension to provided spec and accept an optional script.
|
374
521
|
# Default to no-op if none is provided.
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gem-compiler
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Luis Lavena
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-04-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -74,15 +74,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
74
74
|
requirements:
|
75
75
|
- - ">="
|
76
76
|
- !ruby/object:Gem::Version
|
77
|
-
version: 2.
|
77
|
+
version: 2.4.0
|
78
78
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
80
|
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: 2.
|
82
|
+
version: 2.6.0
|
83
83
|
requirements: []
|
84
84
|
rubyforge_project:
|
85
|
-
rubygems_version: 2.
|
85
|
+
rubygems_version: 2.6.14.4
|
86
86
|
signing_key:
|
87
87
|
specification_version: 4
|
88
88
|
summary: A RubyGems plugin that generates binary gems.
|