gem-compiler 0.8.0 → 0.9.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.
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.