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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA256:
3
- metadata.gz: 2f88322755fee2322a31c6516b5f52dc9470bc132e2fde88628f6a0f449987ac
4
- data.tar.gz: 53a1dc54a53791f6a106d012e6306228f548a906549dd601c7c273c252048013
2
+ SHA1:
3
+ metadata.gz: f715fe84339746f8ec890e713c7e162bb73d53d5
4
+ data.tar.gz: 5898f0dfb960d964755662674c469c84d95e5db4
5
5
  SHA512:
6
- metadata.gz: dc22e52f9e0328c93b90a0ed5e8dce3d63aece8377af375aba94e3c0d2d6e30dbd3bf37a91d6043fb859cb561e3e94622998b237509040f32b45e12cc694c381
7
- data.tar.gz: 149623d4a832894032c1a249fabe912a8a6af1028faf9ad62a5735ebdb7aebe2b7e283f416c63f78ed69c4d3d03df89fe1b965ab1f71e96a30445cb66a91985c
6
+ metadata.gz: b879e33e40fa3ed600305f8c759caae5d3387af03577eb5fdf7bd5e8b3e61029edd7a5f5d3bdb33c6ca5a3fe5f6fa2beec001b48f70492f24042a74e51f9380d
7
+ data.tar.gz: 1212ed35d0ae616c54e1df0a857b40cfb83e03d6bcf52030e34e2d5ac160ca74097bee9ba360f0a4db4d19d22236b62524481700cfda2fbbbc553e6be247fc9c
@@ -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.8.0...HEAD
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
- The result of the compilation is a binary gem built for your current platform,
23
- skipping the need of a compiler toolchain when installing it.
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
- #### Restrictions of binaries
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
- Gems compiled with `gem-compiler` will be lock to the version of Ruby used
97
- to compile them.
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
- This means that a gem compiled under Ruby 2.2 could only be installed under
100
- Ruby 2.2.
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
- You can disable this by using `--no-abi-lock` option during compilation:
155
+ #### Reducing extension's size (stripping)
103
156
 
104
- $ gem compile yajl-ruby-1.1.0.gem --no-abi-lock
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
- **Warning**: this is not recommended since different versions of Ruby might
107
- expose different options on the API. The binary might be expecting specific
108
- features not present in the version of Ruby you're installing the binary gem
109
- into.
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 1.8.x to properly work.
208
+ RubyGems 2.6.x to work.
133
209
 
134
- If you don't have RubyGems 1.8.x, you can upgrade by running:
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 [installation instructions](https://github.com/oneclick/rubyinstaller/wiki/Development-Kit).
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
- tcs-ruby 1.9.3p196 (2012-04-21, TCS patched 2012-04-21) [i386-mingw32]
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,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "rubygems/package_task"
2
4
 
3
5
  gemspec = Gem::Specification.load("gem-compiler.gemspec")
@@ -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
- super "compile", "Create binary pre-compiled gem",
6
- output: Dir.pwd
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 "-N", "--no-abi-lock", "Do not lock compiled Gem to Ruby's ABI" do |value, options|
21
- options[:no_abi_lock] = true
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
 
@@ -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
- # RubyGems 2.5 specifics
119
- unpack_options = options.dup.merge(unpack: true)
120
- if Gem::Installer.respond_to?(:at)
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
- raise CompilerError,
145
- "The gem file seems to be compiled already."
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
- raise CompilerError,
151
- "There are no extensions to build on this gem file."
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
- unless @options[:no_abi_lock]
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
- installer.unpack(@target_dir)
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
@@ -1,7 +1,8 @@
1
1
  # encoding: UTF-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module Gem
4
5
  class Compiler
5
- VERSION = "0.8.0"
6
+ VERSION = "0.9.0"
6
7
  end
7
8
  end
@@ -1,2 +1,4 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "rubygems/command_manager"
2
4
  Gem::CommandManager.instance.register_command :compile
@@ -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
- e = assert_raises Gem::Compiler::CompilerError do
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
- assert_equal "There are no extensions to build on this gem file.",
35
- e.message
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
- e = assert_raises Gem::Compiler::CompilerError do
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
- assert_equal "The gem file seems to be compiled already.", e.message
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 test_compile_lock_ruby_abi
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 spec.required_ruby_version, Gem::Requirement.new("~> #{ruby_abi}")
357
+ assert_equal Gem::Requirement.new("~> #{ruby_abi}"), spec.required_ruby_version
330
358
  end
331
359
 
332
- def test_compile_no_lock_ruby_abi
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, :no_abi_lock => true)
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
- assert_equal spec.required_ruby_version, Gem::Requirement.new(">= 0")
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 = new_spec name, "1", nil, files, &block
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.8.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: 2017-12-28 00:00:00.000000000 Z
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.3.0
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.5.0
82
+ version: 2.6.0
83
83
  requirements: []
84
84
  rubyforge_project:
85
- rubygems_version: 2.7.4
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.