rubygems-update 3.3.10 → 3.3.11

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.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +14 -0
  3. data/Manifest.txt +14 -0
  4. data/bundler/CHANGELOG.md +11 -0
  5. data/bundler/exe/bundler +1 -1
  6. data/bundler/lib/bundler/build_metadata.rb +3 -3
  7. data/bundler/lib/bundler/cli/info.rb +1 -1
  8. data/bundler/lib/bundler/cli/init.rb +1 -1
  9. data/bundler/lib/bundler/cli/show.rb +1 -1
  10. data/bundler/lib/bundler/cli.rb +1 -1
  11. data/bundler/lib/bundler/installer.rb +2 -2
  12. data/bundler/lib/bundler/man/bundle-config.1 +3 -3
  13. data/bundler/lib/bundler/man/bundle-config.1.ronn +8 -6
  14. data/bundler/lib/bundler/shared_helpers.rb +4 -4
  15. data/bundler/lib/bundler/source/metadata.rb +1 -1
  16. data/bundler/lib/bundler/templates/Executable +2 -4
  17. data/bundler/lib/bundler/templates/Executable.bundler +1 -1
  18. data/bundler/lib/bundler/templates/Executable.standalone +2 -4
  19. data/bundler/lib/bundler/templates/newgem/github/workflows/main.yml.tt +1 -1
  20. data/bundler/lib/bundler/templates/newgem/newgem.gemspec.tt +1 -1
  21. data/bundler/lib/bundler/version.rb +1 -1
  22. data/bundler/lib/bundler.rb +1 -1
  23. data/lib/rubygems/commands/setup_command.rb +1 -1
  24. data/lib/rubygems/ext/builder.rb +3 -0
  25. data/lib/rubygems/ext/cargo_builder.rb +305 -0
  26. data/lib/rubygems/ext/ext_conf_builder.rb +1 -1
  27. data/lib/rubygems/ext.rb +1 -0
  28. data/lib/rubygems/gemcutter_utilities.rb +34 -5
  29. data/lib/rubygems/request.rb +1 -1
  30. data/lib/rubygems/source/git.rb +1 -0
  31. data/lib/rubygems.rb +2 -2
  32. data/rubygems-update.gemspec +1 -1
  33. data/setup.rb +1 -1
  34. data/test/rubygems/helper.rb +5 -5
  35. data/test/rubygems/test_gem.rb +1 -1
  36. data/test/rubygems/test_gem_command_manager.rb +1 -1
  37. data/test/rubygems/test_gem_commands_help_command.rb +1 -1
  38. data/test/rubygems/test_gem_commands_push_command.rb +5 -0
  39. data/test/rubygems/test_gem_commands_setup_command.rb +1 -1
  40. data/test/rubygems/test_gem_commands_signin_command.rb +100 -11
  41. data/test/rubygems/test_gem_dependency_installer.rb +2 -2
  42. data/test/rubygems/test_gem_ext_builder.rb +1 -1
  43. data/test/rubygems/test_gem_ext_cargo_builder/custom_name/.gitignore +1 -0
  44. data/test/rubygems/test_gem_ext_cargo_builder/custom_name/Cargo.lock +374 -0
  45. data/test/rubygems/test_gem_ext_cargo_builder/custom_name/Cargo.toml +10 -0
  46. data/test/rubygems/test_gem_ext_cargo_builder/custom_name/build.rb +21 -0
  47. data/test/rubygems/test_gem_ext_cargo_builder/custom_name/custom_name.gemspec +10 -0
  48. data/test/rubygems/test_gem_ext_cargo_builder/custom_name/src/lib.rs +30 -0
  49. data/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/.gitignore +1 -0
  50. data/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.lock +374 -0
  51. data/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.toml +10 -0
  52. data/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/build.rb +21 -0
  53. data/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/rust_ruby_example.gemspec +8 -0
  54. data/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/src/lib.rs +42 -0
  55. data/test/rubygems/test_gem_ext_cargo_builder.rb +148 -0
  56. data/test/rubygems/test_gem_ext_cmake_builder.rb +2 -0
  57. data/test/rubygems/test_gem_gemcutter_utilities.rb +4 -2
  58. data/test/rubygems/test_gem_source_git.rb +1 -0
  59. data/test/rubygems/test_gem_specification.rb +1 -1
  60. data/test/rubygems/test_project_sanity.rb +1 -1
  61. data/test/rubygems/test_require.rb +1 -1
  62. data/test/test_changelog_generator.rb +1 -0
  63. metadata +17 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 88b51a16140837e81c1775155ede2bfd054f6ac05e34072ebfa871814decd8e6
4
- data.tar.gz: 12de868024f63a63873184ddf8cf856f14808484fb41dd091c862390870cbd4f
3
+ metadata.gz: 3f9f133a10adb0dca16feb1c6dd3d12c2da126c621dcf6ac086a5434f62cdecb
4
+ data.tar.gz: 0b48275de222559f54a44e6cdf9c1105e40ff156d57d26d2a5a246d1fcc50521
5
5
  SHA512:
6
- metadata.gz: 0aab9e5b5388126454361b8a1b591cb376da5edc5449246690cf0c666cfed5714ad95dfa6844739362cbae488fd1fb868eccaa5a990bb5e3a50eaef9a7df28ca
7
- data.tar.gz: e438ac4bf829acc1244d51dd00f098c1073d904391b8c5feee24fad1949b870b23cd60d180ac458db707bbcdae2c13bc6ede5a6491e6c0ee9afa23884f7305b6
6
+ metadata.gz: ab1dc93b4c3748bc3580c8d4047ec956a52271b389fcb1c306ebecbf665670231648126aed8b84c711d7444025323a27cf665fefe801180bfeb3cc5d5a26ad25
7
+ data.tar.gz: 24d7c27ed7fdfff099d291b7524c377296ea4f3622c9c1880c3f2bd55b9fafcca79ee138df9d00138cc22dd5be5d5db376d6b145ec96566ccbc63dd7fd4cd507
data/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ # 3.3.11 / 2022-04-07
2
+
3
+ ## Enhancements:
4
+
5
+ * Enable mfa on specific keys during gem signin. Pull request #5305 by
6
+ aellispierce
7
+ * Prefer `__dir__` to `__FILE__`. Pull request #5444 by deivid-rodriguez
8
+ * Add cargo builder for rust extensions. Pull request #5175 by ianks
9
+ * Installs bundler 2.3.11 as a default gem.
10
+
11
+ ## Documentation:
12
+
13
+ * Improve RDoc setup. Pull request #5398 by deivid-rodriguez
14
+
1
15
  # 3.3.10 / 2022-03-23
2
16
 
3
17
  ## Enhancements:
data/Manifest.txt CHANGED
@@ -382,6 +382,7 @@ lib/rubygems/exceptions.rb
382
382
  lib/rubygems/ext.rb
383
383
  lib/rubygems/ext/build_error.rb
384
384
  lib/rubygems/ext/builder.rb
385
+ lib/rubygems/ext/cargo_builder.rb
385
386
  lib/rubygems/ext/cmake_builder.rb
386
387
  lib/rubygems/ext/configure_builder.rb
387
388
  lib/rubygems/ext/ext_conf_builder.rb
@@ -635,6 +636,19 @@ test/rubygems/test_gem_dependency_list.rb
635
636
  test/rubygems/test_gem_dependency_resolution_error.rb
636
637
  test/rubygems/test_gem_doctor.rb
637
638
  test/rubygems/test_gem_ext_builder.rb
639
+ test/rubygems/test_gem_ext_cargo_builder.rb
640
+ test/rubygems/test_gem_ext_cargo_builder/custom_name/.gitignore
641
+ test/rubygems/test_gem_ext_cargo_builder/custom_name/Cargo.lock
642
+ test/rubygems/test_gem_ext_cargo_builder/custom_name/Cargo.toml
643
+ test/rubygems/test_gem_ext_cargo_builder/custom_name/build.rb
644
+ test/rubygems/test_gem_ext_cargo_builder/custom_name/custom_name.gemspec
645
+ test/rubygems/test_gem_ext_cargo_builder/custom_name/src/lib.rs
646
+ test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/.gitignore
647
+ test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.lock
648
+ test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.toml
649
+ test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/build.rb
650
+ test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/rust_ruby_example.gemspec
651
+ test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/src/lib.rs
638
652
  test/rubygems/test_gem_ext_cmake_builder.rb
639
653
  test/rubygems/test_gem_ext_configure_builder.rb
640
654
  test/rubygems/test_gem_ext_ext_conf_builder.rb
data/bundler/CHANGELOG.md CHANGED
@@ -1,3 +1,14 @@
1
+ # 2.3.11 (April 7, 2022)
2
+
3
+ ## Enhancements:
4
+
5
+ - Bump actions/checkout to 3 in bundler gem template [#5445](https://github.com/rubygems/rubygems/pull/5445)
6
+ - Prefer `__dir__` to `__FILE__` [#5444](https://github.com/rubygems/rubygems/pull/5444)
7
+
8
+ ## Documentation:
9
+
10
+ - Update bundler documentation to reflect bundle config scope changes [#5441](https://github.com/rubygems/rubygems/pull/5441)
11
+
1
12
  # 2.3.10 (March 23, 2022)
2
13
 
3
14
  ## Enhancements:
data/bundler/exe/bundler CHANGED
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- load File.expand_path("../bundle", __FILE__)
4
+ load File.expand_path("bundle", __dir__)
@@ -4,8 +4,8 @@ module Bundler
4
4
  # Represents metadata from when the Bundler gem was built.
5
5
  module BuildMetadata
6
6
  # begin ivars
7
- @built_at = "2022-03-23".freeze
8
- @git_commit_sha = "4bbb70e7de".freeze
7
+ @built_at = "2022-04-07".freeze
8
+ @git_commit_sha = "9b6c5a801a".freeze
9
9
  @release = true
10
10
  # end ivars
11
11
 
@@ -29,7 +29,7 @@ module Bundler
29
29
 
30
30
  # If Bundler has been installed without its .git directory and without a
31
31
  # commit instance variable then we can't determine its commits SHA.
32
- git_dir = File.join(File.expand_path("../../../..", __FILE__), ".git")
32
+ git_dir = File.expand_path("../../../.git", __dir__)
33
33
  if File.directory?(git_dir)
34
34
  return @git_commit_sha = Dir.chdir(git_dir) { `git rev-parse --short HEAD`.strip.freeze }
35
35
  end
@@ -47,7 +47,7 @@ module Bundler
47
47
  def print_gem_path(spec)
48
48
  name = spec.name
49
49
  if name == "bundler"
50
- path = File.expand_path("../../../..", __FILE__)
50
+ path = File.expand_path("../../..", __dir__)
51
51
  else
52
52
  path = spec.full_gem_path
53
53
  if spec.deleted_gem?
@@ -32,7 +32,7 @@ module Bundler
32
32
  file << spec.to_gemfile
33
33
  end
34
34
  else
35
- FileUtils.cp(File.expand_path("../../templates/#{gemfile}", __FILE__), gemfile)
35
+ FileUtils.cp(File.expand_path("../templates/#{gemfile}", __dir__), gemfile)
36
36
  end
37
37
 
38
38
  puts "Writing new #{gemfile} to #{SharedHelpers.pwd}/#{gemfile}"
@@ -18,7 +18,7 @@ module Bundler
18
18
 
19
19
  if gem_name
20
20
  if gem_name == "bundler"
21
- path = File.expand_path("../../../..", __FILE__)
21
+ path = File.expand_path("../../..", __dir__)
22
22
  else
23
23
  spec = Bundler::CLI::Common.select_spec(gem_name, :regex_match)
24
24
  return unless spec
@@ -610,7 +610,7 @@ module Bundler
610
610
  private :gem
611
611
 
612
612
  def self.source_root
613
- File.expand_path(File.join(File.dirname(__FILE__), "templates"))
613
+ File.expand_path("templates", __dir__)
614
614
  end
615
615
 
616
616
  desc "clean [OPTIONS]", "Cleans up unused gems in your bundler directory", :hide => true
@@ -119,7 +119,7 @@ module Bundler
119
119
  relative_gemfile_path = relative_gemfile_path
120
120
  ruby_command = Thor::Util.ruby_command
121
121
  ruby_command = ruby_command
122
- template_path = File.expand_path("../templates/Executable", __FILE__)
122
+ template_path = File.expand_path("templates/Executable", __dir__)
123
123
  if spec.name == "bundler"
124
124
  template_path += ".bundler"
125
125
  spec.executables = %(bundle)
@@ -172,7 +172,7 @@ module Bundler
172
172
  end
173
173
  standalone_path = Bundler.root.join(path).relative_path_from(bin_path)
174
174
  standalone_path = standalone_path
175
- template = File.read(File.expand_path("../templates/Executable.standalone", __FILE__))
175
+ template = File.read(File.expand_path("templates/Executable.standalone", __dir__))
176
176
  ruby_command = Thor::Util.ruby_command
177
177
  ruby_command = ruby_command
178
178
 
@@ -36,13 +36,13 @@ Executing \fBbundle config list\fR with will print a list of all bundler configu
36
36
  Executing \fBbundle config get <name>\fR will print the value of that configuration setting, and where it was set\.
37
37
  .
38
38
  .P
39
- Executing \fBbundle config set <name> <value>\fR will set that configuration to the value specified for all bundles executed as the current user\. The configuration will be stored in \fB~/\.bundle/config\fR\. If \fIname\fR already is set, \fIname\fR will be overridden and user will be warned\.
39
+ Executing \fBbundle config set <name> <value>\fR defaults to setting \fBlocal\fR configuration if executing from within a local application, otherwise it will set \fBglobal\fR configuration\. See \fB\-\-local\fR and \fB\-\-global\fR options below\.
40
40
  .
41
41
  .P
42
- Executing \fBbundle config set \-\-global <name> <value>\fR works the same as above\.
42
+ Executing \fBbundle config set \-\-local <name> <value>\fR will set that configuration in the directory for the local application\. The configuration will be stored in \fB<project_root>/\.bundle/config\fR\. If \fBBUNDLE_APP_CONFIG\fR is set, the configuration will be stored in \fB$BUNDLE_APP_CONFIG/config\fR\.
43
43
  .
44
44
  .P
45
- Executing \fBbundle config set \-\-local <name> <value>\fR will set that configuration in the directory for the local application\. The configuration will be stored in \fB<project_root>/\.bundle/config\fR\. If \fBBUNDLE_APP_CONFIG\fR is set, the configuration will be stored in \fB$BUNDLE_APP_CONFIG/config\fR\.
45
+ Executing \fBbundle config set \-\-global <name> <value>\fR will set that configuration to the value specified for all bundles executed as the current user\. The configuration will be stored in \fB~/\.bundle/config\fR\. If \fIname\fR already is set, \fIname\fR will be overridden and user will be warned\.
46
46
  .
47
47
  .P
48
48
  Executing \fBbundle config unset <name>\fR will delete the configuration in both local and global sources\.
@@ -23,18 +23,20 @@ was set.
23
23
  Executing `bundle config get <name>` will print the value of that configuration
24
24
  setting, and where it was set.
25
25
 
26
- Executing `bundle config set <name> <value>` will set that configuration to the
27
- value specified for all bundles executed as the current user. The configuration
28
- will be stored in `~/.bundle/config`. If <name> already is set, <name> will be
29
- overridden and user will be warned.
30
-
31
- Executing `bundle config set --global <name> <value>` works the same as above.
26
+ Executing `bundle config set <name> <value>` defaults to setting `local`
27
+ configuration if executing from within a local application, otherwise it will
28
+ set `global` configuration. See `--local` and `--global` options below.
32
29
 
33
30
  Executing `bundle config set --local <name> <value>` will set that configuration
34
31
  in the directory for the local application. The configuration will be stored in
35
32
  `<project_root>/.bundle/config`. If `BUNDLE_APP_CONFIG` is set, the configuration
36
33
  will be stored in `$BUNDLE_APP_CONFIG/config`.
37
34
 
35
+ Executing `bundle config set --global <name> <value>` will set that
36
+ configuration to the value specified for all bundles executed as the current
37
+ user. The configuration will be stored in `~/.bundle/config`. If <name> already
38
+ is set, <name> will be overridden and user will be warned.
39
+
38
40
  Executing `bundle config unset <name>` will delete the configuration in both
39
41
  local and global sources.
40
42
 
@@ -274,10 +274,10 @@ module Bundler
274
274
 
275
275
  def set_bundle_variables
276
276
  # bundler exe & lib folders have same root folder, typical gem installation
277
- exe_file = File.expand_path("../../../exe/bundle", __FILE__)
277
+ exe_file = File.expand_path("../../exe/bundle", __dir__)
278
278
 
279
279
  # for Ruby core repository testing
280
- exe_file = File.expand_path("../../../libexec/bundle", __FILE__) unless File.exist?(exe_file)
280
+ exe_file = File.expand_path("../../libexec/bundle", __dir__) unless File.exist?(exe_file)
281
281
 
282
282
  # bundler is a default gem, exe path is separate
283
283
  exe_file = Bundler.rubygems.bin_path("bundler", "bundle", VERSION) unless File.exist?(exe_file)
@@ -309,7 +309,7 @@ module Bundler
309
309
  end
310
310
 
311
311
  def bundler_ruby_lib
312
- resolve_path File.expand_path("../..", __FILE__)
312
+ File.expand_path("..", __dir__)
313
313
  end
314
314
 
315
315
  def clean_load_path
@@ -325,7 +325,7 @@ module Bundler
325
325
 
326
326
  def resolve_path(path)
327
327
  expanded = File.expand_path(path)
328
- return expanded unless File.respond_to?(:realpath) && File.exist?(expanded)
328
+ return expanded unless File.exist?(expanded)
329
329
 
330
330
  File.realpath(expanded)
331
331
  end
@@ -22,7 +22,7 @@ module Bundler
22
22
  s.summary = "The best way to manage your application's dependencies"
23
23
  s.executables = %w[bundle]
24
24
  # can't point to the actual gemspec or else the require paths will be wrong
25
- s.loaded_from = File.expand_path("..", __FILE__)
25
+ s.loaded_from = __dir__
26
26
  end
27
27
 
28
28
  if local_spec = Bundler.rubygems.find_bundler(VERSION)
@@ -8,11 +8,9 @@
8
8
  # this file is here to facilitate running it.
9
9
  #
10
10
 
11
- require "pathname"
12
- ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../<%= relative_gemfile_path %>",
13
- Pathname.new(__FILE__).realpath)
11
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("<%= relative_gemfile_path %>", __dir__)
14
12
 
15
- bundle_binstub = File.expand_path("../bundle", __FILE__)
13
+ bundle_binstub = File.expand_path("bundle", __dir__)
16
14
 
17
15
  if File.file?(bundle_binstub)
18
16
  if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
@@ -41,7 +41,7 @@ m = Module.new do
41
41
  gemfile = ENV["BUNDLE_GEMFILE"]
42
42
  return gemfile if gemfile && !gemfile.empty?
43
43
 
44
- File.expand_path("../<%= relative_gemfile_path %>", __FILE__)
44
+ File.expand_path("<%= relative_gemfile_path %>", __dir__)
45
45
  end
46
46
 
47
47
  def lockfile
@@ -6,9 +6,7 @@
6
6
  # this file is here to facilitate running it.
7
7
  #
8
8
 
9
- require "pathname"
10
- path = Pathname.new(__FILE__)
11
- $:.unshift File.expand_path "../<%= standalone_path %>", path.realpath
9
+ $:.unshift File.expand_path "<%= standalone_path %>", __dir__
12
10
 
13
11
  require "bundler/setup"
14
- load File.expand_path "../<%= executable_path %>", path.realpath
12
+ load File.expand_path "<%= executable_path %>", __dir__
@@ -17,7 +17,7 @@ jobs:
17
17
  - '<%= RUBY_VERSION %>'
18
18
 
19
19
  steps:
20
- - uses: actions/checkout@v2
20
+ - uses: actions/checkout@v3
21
21
  - name: Set up Ruby
22
22
  uses: ruby/setup-ruby@v1
23
23
  with:
@@ -24,7 +24,7 @@ Gem::Specification.new do |spec|
24
24
 
25
25
  # Specify which files should be added to the gem when it is released.
26
26
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
27
- spec.files = Dir.chdir(File.expand_path(__dir__)) do
27
+ spec.files = Dir.chdir(__dir__) do
28
28
  `git ls-files -z`.split("\x0").reject do |f|
29
29
  (f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
30
30
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: false
2
2
 
3
3
  module Bundler
4
- VERSION = "2.3.10".freeze
4
+ VERSION = "2.3.11".freeze
5
5
 
6
6
  def self.bundler_major_version
7
7
  @bundler_major_version ||= VERSION.split(".").first.to_i
@@ -370,7 +370,7 @@ EOF
370
370
 
371
371
  if env.key?("RUBYLIB")
372
372
  rubylib = env["RUBYLIB"].split(File::PATH_SEPARATOR)
373
- rubylib.delete(File.expand_path("..", __FILE__))
373
+ rubylib.delete(__dir__)
374
374
  env["RUBYLIB"] = rubylib.join(File::PATH_SEPARATOR)
375
375
  end
376
376
 
@@ -341,7 +341,7 @@ By default, this RubyGems will install gem as:
341
341
 
342
342
  fake_spec = Gem::Specification.new 'rubygems', Gem::VERSION
343
343
  def fake_spec.full_gem_path
344
- File.expand_path '../../../..', __FILE__
344
+ File.expand_path '../../..', __dir__
345
345
  end
346
346
 
347
347
  generate_ri = options[:document].include? 'ri'
@@ -123,6 +123,9 @@ class Gem::Ext::Builder
123
123
  Gem::Ext::RakeBuilder
124
124
  when /CMakeLists.txt/ then
125
125
  Gem::Ext::CmakeBuilder
126
+ when /Cargo.toml/ then
127
+ # We use the spec name here to ensure we invoke the correct init function later
128
+ Gem::Ext::CargoBuilder.new(@spec)
126
129
  else
127
130
  build_error("No builder for extension '#{extension}'")
128
131
  end
@@ -0,0 +1,305 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This class is used by rubygems to build Rust extensions. It is a thin-wrapper
4
+ # over the `cargo rustc` command which takes care of building Rust code in a way
5
+ # that Ruby can use.
6
+ class Gem::Ext::CargoBuilder < Gem::Ext::Builder
7
+ attr_reader :spec
8
+
9
+ def initialize(spec)
10
+ @spec = spec
11
+ end
12
+
13
+ def build(_extension, dest_path, results, args = [], lib_dir = nil, cargo_dir = Dir.pwd)
14
+ require "rubygems/command"
15
+ require "fileutils"
16
+ require "shellwords"
17
+
18
+ build_crate(dest_path, results, args, cargo_dir)
19
+ ext_path = rename_cdylib_for_ruby_compatibility(dest_path)
20
+ finalize_directory(ext_path, dest_path, lib_dir, cargo_dir)
21
+ results
22
+ end
23
+
24
+ private
25
+
26
+ def build_crate(dest_path, results, args, cargo_dir)
27
+ manifest = File.join(cargo_dir, "Cargo.toml")
28
+
29
+ given_ruby_static = ENV["RUBY_STATIC"]
30
+
31
+ ENV["RUBY_STATIC"] = "true" if ruby_static? && !given_ruby_static
32
+
33
+ cargo = ENV.fetch("CARGO", "cargo")
34
+
35
+ cmd = []
36
+ cmd += [cargo, "rustc"]
37
+ cmd += ["--target-dir", dest_path]
38
+ cmd += ["--manifest-path", manifest]
39
+ cmd += ["--lib", "--release", "--locked"]
40
+ cmd += ["--"]
41
+ cmd += [*cargo_rustc_args(dest_path)]
42
+ cmd += Gem::Command.build_args
43
+ cmd += args
44
+
45
+ self.class.run cmd, results, self.class.class_name, cargo_dir
46
+ results
47
+ ensure
48
+ ENV["RUBY_STATIC"] = given_ruby_static
49
+ end
50
+
51
+ def cargo_rustc_args(dest_dir)
52
+ [
53
+ *linker_args,
54
+ *mkmf_libpath,
55
+ *rustc_dynamic_linker_flags(dest_dir),
56
+ *rustc_lib_flags(dest_dir),
57
+ *platform_specific_rustc_args(dest_dir),
58
+ *debug_flags,
59
+ ]
60
+ end
61
+
62
+ def platform_specific_rustc_args(dest_dir, flags = [])
63
+ if mingw_target?
64
+ # On mingw platforms, mkmf adds libruby to the linker flags
65
+ flags += libruby_args(dest_dir)
66
+
67
+ # Make sure ALSR is used on mingw
68
+ # see https://github.com/rust-lang/rust/pull/75406/files
69
+ flags += ["-C", "link-arg=-Wl,--dynamicbase"]
70
+ flags += ["-C", "link-arg=-Wl,--disable-auto-image-base"]
71
+
72
+ # If the gem is installed on a host with build tools installed, but is
73
+ # run on one that isn't the missing libraries will cause the extension
74
+ # to fail on start.
75
+ flags += ["-C", "link-arg=-static-libgcc"]
76
+ end
77
+
78
+ flags
79
+ end
80
+
81
+ # We want to use the same linker that Ruby uses, so that the linker flags from
82
+ # mkmf work properly.
83
+ def linker_args
84
+ # Have to handle CC="cl /nologo" on mswin
85
+ cc_flag = Shellwords.split(makefile_config("CC"))
86
+ linker = cc_flag.shift
87
+ link_args = cc_flag.flat_map {|a| ["-C", "link-arg=#{a}"] }
88
+
89
+ ["-C", "linker=#{linker}", *link_args]
90
+ end
91
+
92
+ def libruby_args(dest_dir)
93
+ libs = makefile_config(ruby_static? ? "LIBRUBYARG_STATIC" : "LIBRUBYARG_SHARED")
94
+ raw_libs = Shellwords.split(libs)
95
+ raw_libs.flat_map {|l| ldflag_to_link_modifier(l, dest_dir) }
96
+ end
97
+
98
+ def ruby_static?
99
+ return true if %w[1 true].include?(ENV["RUBY_STATIC"])
100
+
101
+ makefile_config("ENABLE_SHARED") == "no"
102
+ end
103
+
104
+ # Ruby expects the dylib to follow a file name convention for loading
105
+ def rename_cdylib_for_ruby_compatibility(dest_path)
106
+ dylib_path = validate_cargo_build!(dest_path)
107
+ dlext_name = "#{spec.name}.#{makefile_config("DLEXT")}"
108
+ new_name = dylib_path.gsub(File.basename(dylib_path), dlext_name)
109
+ FileUtils.cp(dylib_path, new_name)
110
+ new_name
111
+ end
112
+
113
+ def validate_cargo_build!(dir)
114
+ prefix = so_ext == "dll" ? "" : "lib"
115
+ dylib_path = File.join(dir, "release", "#{prefix}#{cargo_crate_name}.#{so_ext}")
116
+
117
+ raise DylibNotFoundError, dir unless File.exist?(dylib_path)
118
+
119
+ dylib_path
120
+ end
121
+
122
+ def cargo_crate_name
123
+ spec.metadata.fetch('cargo_crate_name', spec.name).tr('-', '_')
124
+ end
125
+
126
+ def rustc_dynamic_linker_flags(dest_dir)
127
+ split_flags("DLDFLAGS")
128
+ .map {|arg| maybe_resolve_ldflag_variable(arg, dest_dir) }
129
+ .compact
130
+ .flat_map {|arg| ldflag_to_link_modifier(arg, dest_dir) }
131
+ end
132
+
133
+ def rustc_lib_flags(dest_dir)
134
+ split_flags("LIBS").flat_map {|arg| ldflag_to_link_modifier(arg, dest_dir) }
135
+ end
136
+
137
+ def split_flags(var)
138
+ Shellwords.split(RbConfig::CONFIG.fetch(var, ""))
139
+ end
140
+
141
+ def ldflag_to_link_modifier(arg, dest_dir)
142
+ flag = arg[0..1]
143
+ val = arg[2..-1]
144
+
145
+ case flag
146
+ when "-L" then ["-L", "native=#{val}"]
147
+ when "-l" then ["-l", val.to_s]
148
+ when "-F" then ["-l", "framework=#{val}"]
149
+ else ["-C", "link_arg=#{arg}"]
150
+ end
151
+ end
152
+
153
+ def link_flag(link_name)
154
+ # These are provided by the CRT with MSVC
155
+ # @see https://github.com/rust-lang/pkg-config-rs/blob/49a4ac189aafa365167c72e8e503565a7c2697c2/src/lib.rs#L622
156
+ return [] if msvc_target? && ["m", "c", "pthread"].include?(link_name)
157
+
158
+ if link_name.include?("ruby")
159
+ # Specify the lib kind and give it the name "ruby" for linking
160
+ kind = ruby_static? ? "static" : "dylib"
161
+
162
+ ["-l", "#{kind}=ruby:#{link_name}"]
163
+ else
164
+ ["-l", link_name]
165
+ end
166
+ end
167
+
168
+ def msvc_target?
169
+ makefile_config("target_os").include?("msvc")
170
+ end
171
+
172
+ def darwin_target?
173
+ makefile_config("target_os").include?("darwin")
174
+ end
175
+
176
+ def mingw_target?
177
+ makefile_config("target_os").include?("mingw")
178
+ end
179
+
180
+ def win_target?
181
+ target_platform = RbConfig::CONFIG["target_os"]
182
+ !!Gem::WIN_PATTERNS.find {|r| target_platform =~ r }
183
+ end
184
+
185
+ # Intepolate substition vars in the arg (i.e. $(DEFFILE))
186
+ def maybe_resolve_ldflag_variable(input_arg, dest_dir)
187
+ str = input_arg.gsub(/\$\((\w+)\)/) do |var_name|
188
+ case var_name
189
+ # On windows, it is assumed that mkmf has setup an exports file for the
190
+ # extension, so we have to to create one ourselves.
191
+ when "DEFFILE"
192
+ write_deffile(dest_dir)
193
+ else
194
+ RbConfig::CONFIG[var_name]
195
+ end
196
+ end.strip
197
+
198
+ str == "" ? nil : str
199
+ end
200
+
201
+ def write_deffile(dest_dir)
202
+ deffile_path = File.join(dest_dir, "#{spec.name}-#{RbConfig::CONFIG["arch"]}.def")
203
+ export_prefix = makefile_config("EXPORT_PREFIX") || ""
204
+
205
+ File.open(deffile_path, "w") do |f|
206
+ f.puts "EXPORTS"
207
+ f.puts "#{export_prefix.strip}Init_#{spec.name}"
208
+ end
209
+
210
+ deffile_path
211
+ end
212
+
213
+ # We have to basically reimplement RbConfig::CONFIG['SOEXT'] here to support
214
+ # Ruby < 2.5
215
+ #
216
+ # @see https://github.com/ruby/ruby/blob/c87c027f18c005460746a74c07cd80ee355b16e4/configure.ac#L3185
217
+ def so_ext
218
+ return RbConfig::CONFIG["SOEXT"] if RbConfig::CONFIG.key?("SOEXT")
219
+
220
+ if win_target?
221
+ "dll"
222
+ elsif darwin_target?
223
+ "dylib"
224
+ else
225
+ "so"
226
+ end
227
+ end
228
+
229
+ # Corresponds to $(LIBPATH) in mkmf
230
+ def mkmf_libpath
231
+ ["-L", "native=#{makefile_config("libdir")}"]
232
+ end
233
+
234
+ def makefile_config(var_name)
235
+ val = RbConfig::MAKEFILE_CONFIG[var_name]
236
+
237
+ return unless val
238
+
239
+ RbConfig.expand(val.dup)
240
+ end
241
+
242
+ # Good balance between binary size and debugability
243
+ def debug_flags
244
+ ["-C", "debuginfo=1"]
245
+ end
246
+
247
+ # Copied from ExtConfBuilder
248
+ def finalize_directory(ext_path, dest_path, lib_dir, extension_dir)
249
+ require "fileutils"
250
+ require "tempfile"
251
+
252
+ begin
253
+ tmp_dest = Dir.mktmpdir(".gem.", extension_dir)
254
+
255
+ # Some versions of `mktmpdir` return absolute paths, which will break make
256
+ # if the paths contain spaces. However, on Ruby 1.9.x on Windows, relative
257
+ # paths cause all C extension builds to fail.
258
+ #
259
+ # As such, we convert to a relative path unless we are using Ruby 1.9.x on
260
+ # Windows. This means that when using Ruby 1.9.x on Windows, paths with
261
+ # spaces do not work.
262
+ #
263
+ # Details: https://github.com/rubygems/rubygems/issues/977#issuecomment-171544940
264
+ tmp_dest_relative = get_relative_path(tmp_dest.clone, extension_dir)
265
+
266
+ if tmp_dest_relative
267
+ full_tmp_dest = File.join(extension_dir, tmp_dest_relative)
268
+
269
+ # TODO: remove in RubyGems 3
270
+ if Gem.install_extension_in_lib && lib_dir
271
+ FileUtils.mkdir_p lib_dir
272
+ FileUtils.cp_r ext_path, lib_dir, remove_destination: true
273
+ end
274
+
275
+ FileUtils::Entry_.new(full_tmp_dest).traverse do |ent|
276
+ destent = ent.class.new(dest_path, ent.rel)
277
+ destent.exist? || FileUtils.mv(ent.path, destent.path)
278
+ end
279
+ end
280
+ ensure
281
+ FileUtils.rm_rf tmp_dest if tmp_dest
282
+ end
283
+ end
284
+
285
+ def get_relative_path(path, base)
286
+ path[0..base.length - 1] = "." if path.start_with?(base)
287
+ path
288
+ end
289
+
290
+ # Error raised when no cdylib artifact was created
291
+ class DylibNotFoundError < StandardError
292
+ def initialize(dir)
293
+ files = Dir.glob(File.join(dir, "**", "*")).map {|f| "- #{f}" }.join "\n"
294
+
295
+ super <<~MSG
296
+ Dynamic library not found for Rust extension (in #{dir})
297
+
298
+ Make sure you set "crate-type" in Cargo.toml to "cdylib"
299
+
300
+ Found files:
301
+ #{files}
302
+ MSG
303
+ end
304
+ end
305
+ end