class Gem::Ext::CargoBuilder

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.

Attributes

profile [RW]
runner [RW]
spec [RW]

Public Class Methods

new ()
# 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

Public Instance Methods

build (extension, dest_path, results, args = [], lib_dir = nil, cargo_dir = Dir.pwd, target_rbconfig=Gem.target_rbconfig)
# File lib/rubygems/ext/cargo_builder.rb, line 19
def build(extension, dest_path, results, args = [], lib_dir = nil, cargo_dir = Dir.pwd,
  target_rbconfig=Gem.target_rbconfig)
  require "tempfile"
  require "fileutils"

  if target_rbconfig.path
    warn "--target-rbconfig is not yet supported for Rust extensions. Ignoring"
  end

  # 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)

    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_env ()
# File lib/rubygems/ext/cargo_builder.rb, line 73
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)
# File lib/rubygems/ext/cargo_builder.rb, line 81
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