Module: Lda::RustExtensionBuild

Defined in:
ext/lda-ruby-rust/extconf.rb

Class Method Summary collapse

Class Method Details

.build_and_stage!Object



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'ext/lda-ruby-rust/extconf.rb', line 51

def build_and_stage!
  cargo = ENV.fetch("CARGO", "cargo")
  Dir.chdir(__dir__) do
    env = rust_build_env
    success =
      if env.empty?
        system(cargo, "build", "--release")
      else
        system(env, cargo, "build", "--release")
      end
    success or raise "cargo build --release failed"
  end

  source = File.join(__dir__, "target", "release", rust_cdylib_filename)
  raise "Rust extension artifact not found at #{source}" unless File.exist?(source)

  destination = File.expand_path("../../lib/lda_ruby_rust.#{RbConfig::CONFIG.fetch('DLEXT')}", __dir__)
  FileUtils.cp(source, destination)
  puts("Staged Rust extension to #{destination}")
end

.cargo_available?Boolean

Returns:

  • (Boolean)


46
47
48
49
# File 'ext/lda-ruby-rust/extconf.rb', line 46

def cargo_available?
  cargo = ENV.fetch("CARGO", "cargo")
  system(cargo, "--version", out: File::NULL, err: File::NULL)
end

.ensure_cargo_available!Object



40
41
42
43
44
# File 'ext/lda-ruby-rust/extconf.rb', line 40

def ensure_cargo_available!
  return if cargo_available?

  abort("cargo not found in PATH but #{RustBuildPolicy::ENV_KEY}=#{RustBuildPolicy::ALWAYS} was requested.")
end

.runObject



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'ext/lda-ruby-rust/extconf.rb', line 12

def run
  policy = RustBuildPolicy.resolve
  puts("Rust extension build policy: #{policy} (#{RustBuildPolicy::ENV_KEY})")

  case policy
  when RustBuildPolicy::NEVER
    puts("Skipping Rust extension build (policy=#{RustBuildPolicy::NEVER}).")
  when RustBuildPolicy::ALWAYS
    ensure_cargo_available!
    build_and_stage!
  else
    if cargo_available?
      build_and_stage!
    else
      puts("cargo not found; skipping Rust extension build (policy=#{RustBuildPolicy::AUTO}).")
    end
  end

  write_noop_makefile
rescue StandardError => e
  if policy == RustBuildPolicy::ALWAYS
    abort("Rust extension build failed with #{RustBuildPolicy::ENV_KEY}=#{RustBuildPolicy::ALWAYS}: #{e.message}")
  end

  warn("Rust extension build skipped after error in auto mode: #{e.message}")
  write_noop_makefile
end

.rust_build_envObject



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'ext/lda-ruby-rust/extconf.rb', line 87

def rust_build_env
  host_os = RbConfig::CONFIG.fetch("host_os")
  return {} unless host_os.match?(/darwin/)

  dynamic_lookup_flag = "-C link-arg=-Wl,-undefined,dynamic_lookup"
  existing = ENV.fetch("RUSTFLAGS", "")
  merged =
    if existing.include?(dynamic_lookup_flag)
      existing
    else
      [existing, dynamic_lookup_flag].reject(&:empty?).join(" ")
    end

  { "RUSTFLAGS" => merged }
end

.rust_cdylib_filenameObject



72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'ext/lda-ruby-rust/extconf.rb', line 72

def rust_cdylib_filename
  host_os = RbConfig::CONFIG.fetch("host_os")
  extension =
    case host_os
    when /darwin/
      "dylib"
    when /mswin|mingw|cygwin/
      "dll"
    else
      "so"
    end

  "liblda_ruby_rust.#{extension}"
end

.write_noop_makefileObject



103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'ext/lda-ruby-rust/extconf.rb', line 103

def write_noop_makefile
  File.write(
    File.join(__dir__, "Makefile"),
    <<~MAKEFILE
      all:
      \t@echo "Rust extension handled by extconf.rb"

      install:
      \t@echo "Rust extension handled by extconf.rb"

      clean:
      \t@true

      distclean: clean
    MAKEFILE
  )
end