Class: Bundler::Spinel::ExtDetector

Inherits:
Object
  • Object
show all
Defined in:
lib/bundler/spinel/ext_detector.rb

Overview

Auto-detect a gem’s Spinel C-extensions from the ‘ffi_cflags “@PLACEHOLDER@”` declarations already in its Ruby source — and emit a draft `spinel-ext.json`. This keeps the convention strictly consumer-side: a gem author doesn’t have to know about (or ship) ‘spinel-ext.json`; spinelgems infers what it needs from the existing `ffi_cflags` markers and any sibling `.c` files. The supplier can adopt the manifest natively later if they want — it’s a faster, more explicit path, not a precondition.

Matching heuristic: ‘@<PREFIX>_<NAME>_O@` → `.o` placeholder; look for a `*<name>*.c` near the declaring `.rb`. `@<PREFIX>_<NAME>_CFLAGS@` → a system-libs placeholder (no source); the maintainer or proxy still has to supply `pkg_config` and `disabled_cflags`, but the placeholder + name are detected. Whatever the detector can’t infer it leaves blank and warns —the output is a draft meant to be reviewed.

Constant Summary collapse

FFI_CFLAGS =

Legacy form: ffi_cflags “@PLACEHOLDER@” → substitution at vendor time.

/ffi_cflags\s+["'](@[A-Z0-9_]+@)["']/.freeze
FFI_CFLAGS_EXPAND =

Post-matz/spinel#1011 form: ffi_cflags File.expand_path(“name.o”, __dir__). Spinel const-folds the path from source position, so no substitution is needed — vendor just has to compile the .c and place the .o where the const-fold will look (next to the placed .rb).

/ffi_cflags\s+File\.expand_path\(\s*["']([^"']+\.o)["']\s*,\s*__dir__\s*\)/.freeze

Instance Method Summary collapse

Constructor Details

#initialize(dir, warn_io: $stderr) ⇒ ExtDetector

Returns a new instance of ExtDetector.



28
29
30
31
# File 'lib/bundler/spinel/ext_detector.rb', line 28

def initialize(dir, warn_io: $stderr)
  @dir = File.expand_path(dir)
  @warn = warn_io
end

Instance Method Details

#detectObject

array of entries shaped like spinel-ext.json. Legacy form (placeholder): dedup’d by placeholder; vendor substitutes. Const-fold form (post-#1011): dedup’d by source path; vendor compiles + places the .o, no substitution.



37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/bundler/spinel/ext_detector.rb', line 37

def detect
  decls = scan_declarations
  return [] if decls.empty?

  seen = {}
  decls.each_with_object([]) do |d, acc|
    key = d[:kind] == :placeholder ? d[:value] : :"src:#{c_for(d)}"
    next if seen[key]

    seen[key] = true
    entry = d[:kind] == :placeholder ? build_placeholder_entry(d) : build_expand_entry(d)
    acc << entry if entry
  end
end

#to_jsonObject



52
# File 'lib/bundler/spinel/ext_detector.rb', line 52

def to_json = JSON.pretty_generate(detect)