Class: Gem::Ext::CargoBuilder

Inherits:
Builder
  • Object
show all
Defined in:
lib/rubygems/ext/cargo_builder.rb,
lib/rubygems/ext/cargo_builder/link_flag_converter.rb

Overview

This class is used by rubygems to build Rust extensions. It is a thin-wrapper over the ‘cargo rustc` command which takes care of building Rust code in a way that Ruby can use.

Defined Under Namespace

Classes: DylibNotFoundError, LinkFlagConverter

Instance Attribute Summary collapse

Attributes inherited from Builder

#build_args

Instance Method Summary collapse

Methods inherited from Builder

#build_error, #build_extension, #build_extensions, #builder_for, class_name, make, ruby, run, #write_gem_make_out

Methods included from UserInteraction

#alert, #alert_error, #alert_warning, #ask, #ask_for_password, #ask_yes_no, #choose_from_list, #say, #terminate_interaction, #verbose

Methods included from DefaultUserInteraction

ui, #ui, ui=, #ui=, use_ui, #use_ui

Methods included from Text

#clean_text, #format_text, #levenshtein_distance, #min3, #truncate_text

Constructor Details

#initializeCargoBuilder

Returns a new instance of CargoBuilder.



11
12
13
14
15
16
17
# File 'lib/rubygems/ext/cargo_builder.rb', line 11

def initialize
  require_relative "../command"
  require_relative "cargo_builder/link_flag_converter"

  @runner = self.class.method(:run)
  @profile = :release
end

Instance Attribute Details

#profileObject

Returns the value of attribute profile.



9
10
11
# File 'lib/rubygems/ext/cargo_builder.rb', line 9

def profile
  @profile
end

#runnerObject

Returns the value of attribute runner.



9
10
11
# File 'lib/rubygems/ext/cargo_builder.rb', line 9

def runner
  @runner
end

#specObject

Returns the value of attribute spec.



9
10
11
# File 'lib/rubygems/ext/cargo_builder.rb', line 9

def spec
  @spec
end

Instance Method Details

#build(extension, dest_path, results, args = [], lib_dir = nil, cargo_dir = Dir.pwd) ⇒ Object



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/rubygems/ext/cargo_builder.rb', line 19

def build(extension, dest_path, results, args = [], lib_dir = nil, cargo_dir = Dir.pwd)
  require "tempfile"
  require "fileutils"

  # Where's the Cargo.toml of the crate we're building
  cargo_toml = File.join(cargo_dir, "Cargo.toml")
  # What's the crate's name
  crate_name = cargo_crate_name(cargo_dir, cargo_toml, results)

  begin
    # Create a tmp dir to do the build in
    tmp_dest = Dir.mktmpdir(".gem.", cargo_dir)

    # Run the build
    cmd = cargo_command(cargo_toml, tmp_dest, args, crate_name)
    runner.call(cmd, results, "cargo", cargo_dir, build_env)

    # Where do we expect Cargo to write the compiled library
    dylib_path = cargo_dylib_path(tmp_dest, crate_name)

    # Helpful error if we didn't find the compiled library
    raise DylibNotFoundError, tmp_dest unless File.exist?(dylib_path)

    # Cargo and Ruby differ on how the library should be named, rename from
    # what Cargo outputs to what Ruby expects
    dlext_name = "#{crate_name}.#{makefile_config("DLEXT")}"
    dlext_path = File.join(File.dirname(dylib_path), dlext_name)
    FileUtils.cp(dylib_path, dlext_path)

    nesting = extension_nesting(extension)

    # TODO: remove in RubyGems 4
    if Gem.install_extension_in_lib && lib_dir
      nested_lib_dir = File.join(lib_dir, nesting)
      FileUtils.mkdir_p nested_lib_dir
      FileUtils.cp_r dlext_path, nested_lib_dir, remove_destination: true
    end

    # move to final destination
    nested_dest_path = File.join(dest_path, nesting)
    FileUtils.mkdir_p nested_dest_path
    FileUtils.cp_r dlext_path, nested_dest_path, remove_destination: true
  ensure
    # clean up intermediary build artifacts
    FileUtils.rm_rf tmp_dest if tmp_dest
  end

  results
end

#build_envObject



69
70
71
72
73
74
75
# File 'lib/rubygems/ext/cargo_builder.rb', line 69

def build_env
  build_env = rb_config_env
  build_env["RUBY_STATIC"] = "true" if ruby_static? && ENV.key?("RUBY_STATIC")
  cfg = "--cfg=rb_sys_gem --cfg=rubygems --cfg=rubygems_#{Gem::VERSION.tr(".", "_")}"
  build_env["RUSTFLAGS"] = [ENV["RUSTFLAGS"], cfg].compact.join(" ")
  build_env
end

#cargo_command(cargo_toml, dest_path, args = [], crate_name = nil) ⇒ Object



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/rubygems/ext/cargo_builder.rb', line 77

def cargo_command(cargo_toml, dest_path, args = [], crate_name = nil)
  cmd = []
  cmd += [cargo, "rustc"]
  cmd += ["--crate-type", "cdylib"]
  cmd += ["--target", ENV["CARGO_BUILD_TARGET"]] if ENV["CARGO_BUILD_TARGET"]
  cmd += ["--target-dir", dest_path]
  cmd += ["--manifest-path", cargo_toml]
  cmd += ["--lib"]
  cmd += ["--profile", profile.to_s]
  cmd += ["--locked"]
  cmd += Gem::Command.build_args
  cmd += args
  cmd += ["--"]
  cmd += [*cargo_rustc_args(dest_path, crate_name)]
  cmd
end