Class: Lilac::CLI::BytecodeBuilder

Inherits:
Object
  • Object
show all
Defined in:
lib/lilac/cli/build/bytecode_builder.rb

Overview

Compiles aggregated Ruby source to mruby bytecode, then writes it under the build output with a content-hash filename so browsers cache-invalidate automatically when the bytes change.

Used by Builder when target == :compiled. Owns the compile subprocess (or wasm driver) lifecycle and error translation; Builder keeps the HTML / vendor concerns.

Backend dispatch — first hit wins:

1. explicit `mrbc_path:` (from `Lilac::CLI.configure { c.mrbc_path = ... }`
 or `--mrbc-path` CLI flag)                                  → :binary
2. ENV["MRBC"]                                                  → :binary
3. ENV["MRUBY_WASM_RUNTIME_PATH"]/mruby/build/host/bin/mrbc     → :binary
4. `lilac-wasm-bin` gem ships `mrbc-host.wasm` AND wasmtime-rb
 loadable AND module instantiates with required exports       → :wasm
5. `mrbc` on $PATH                                              → :binary

The wasm-driven backend is the "default for end users" path — a scaffolded lilac new Gemfile pulls in lilac-wasm-bin and wasmtime, so gem install lilac-cli && bundle install is enough to make lilac build --target compiled work without any external binary. Explicit mrbc_path / ENV vars override (priority 1-3) so devs who built mruby themselves get the native path.

If nothing resolves, raises BuildError pointing at the most likely fix paths.

Defined Under Namespace

Classes: Error

Constant Summary collapse

HASH_LENGTH =

8 hex chars (32 bits) — enough collision resistance for cache busting, short enough to keep filenames readable.

8

Instance Method Summary collapse

Constructor Details

#initialize(output_dir: nil, mrbc_path: nil, basename: 'app', disable_gem_discovery: false) ⇒ BytecodeBuilder

Returns a new instance of BytecodeBuilder.



47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/lilac/cli/build/bytecode_builder.rb', line 47

def initialize(output_dir: nil, mrbc_path: nil, basename: 'app',
               disable_gem_discovery: false)
  @configured_mrbc_path = mrbc_path
  @output_dir = output_dir
  @basename = basename
  # Mirrors `CompiledRuntimeResolver`'s kwarg — lets the bytecode
  # builder's tests sandbox out the gem's `mrbc-host.wasm` when
  # they want to assert specific discovery fallbacks. Production
  # callers leave it false and the gem's wasm is picked up by
  # default (priority #4).
  @disable_gem_discovery = disable_gem_discovery
end

Instance Method Details

#build(ruby_source, source_label: '(aggregated)') ⇒ Object

Compile a Ruby source string into a .mrb file under output_dir. Returns the basename of the produced file (e.g. "app.a3f29b21.mrb") so the caller can wire it into a fetch URL.

Raises:



63
64
65
66
67
68
69
70
71
# File 'lib/lilac/cli/build/bytecode_builder.rb', line 63

def build(ruby_source, source_label: '(aggregated)')
  raise Error, '`build` requires `output_dir:` at construction time' unless @output_dir
  FileUtils.mkdir_p(@output_dir)
  bytecode = compile_to_bytes(ruby_source, source_label: source_label)
  filename = "#{@basename}.#{content_hash(bytecode)}.mrb"
  dest = File.join(@output_dir, filename)
  File.binwrite(dest, bytecode)
  filename
end

#compile_to_bytes(ruby_source, source_label: '(aggregated)') ⇒ Object

Compile a Ruby source string into raw mruby bytecode (no write, no hashing). Used by lilac package-build which wants explicit control over output path / filename — it has no need for the content-hash cache-busting that build does for .lil apps.



77
78
79
80
81
82
83
# File 'lib/lilac/cli/build/bytecode_builder.rb', line 77

def compile_to_bytes(ruby_source, source_label: '(aggregated)')
  backend = resolve_backend!
  case backend.first
  when :binary then compile_via_binary(backend.last, ruby_source, source_label)
  when :wasm   then compile_via_wasm(backend.last, ruby_source, source_label)
  end
end

#resolve_backendObject

Diagnostic accessor: returns [:binary, "/path"] or [:wasm, "/path/to/wasm"] describing which backend build would select, or nil when nothing resolves. Doesn't raise — lilac doctor uses it to render the OK / WARN line; build calls resolve_backend! instead.



90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/lilac/cli/build/bytecode_builder.rb', line 90

def resolve_backend
  if (binary = resolve_mrbc_binary)
    return [:binary, binary]
  end
  if (wasm = discoverable_mrbc_host_wasm) && WasmMrbcDriver.available?(wasm_path: wasm)
    return [:wasm, wasm]
  end
  if (path_binary = path_lookup('mrbc'))
    return [:binary, path_binary]
  end

  nil
end

#resolve_mrbcObject

Resolved mrbc binary path for lilac doctor and back-compat. Nil when no binary is discoverable (gem-provided wasm doesn't count). Renamed-but-kept-as-alias for callers that pre-date the backend dispatch (e.g. existing tests).



108
109
110
# File 'lib/lilac/cli/build/bytecode_builder.rb', line 108

def resolve_mrbc
  resolve_mrbc_binary || path_lookup('mrbc')
end