From f0d2bfbfb77e01df6160f64d249bd43e75e11660 Mon Sep 17 00:00:00 2001 From: KITAITI Makoto Date: Thu, 17 Apr 2025 18:49:58 +0900 Subject: [PATCH] ruby : make Ruby bindings installed with build options (#3056) * Fix signature of URI.new7s return value * Use path instead of string | _ToPath * Add document comment to RBS * Remove unnecessary build flags * Remove unnecessary line * Remove files have become unnecessary * Make gem install accept build options for whisper.cpp * Add instraction for build options in README * Add methods for check to Options * Test build options * Rename: configs -> options * Add assert_installed assertion * Use assert_installed * Remove unused attribute * Extract dependency check logic as Dependencies class * Update README * Add WHISPER_FFMPEG option * Test extra build options only on local test * Bump version to 1.3.2 [skip ci] --- bindings/ruby/README.md | 12 ++ bindings/ruby/ext/cpu.mk | 13 -- bindings/ruby/ext/dependencies.rb | 61 ++++++++ bindings/ruby/ext/extconf.rb | 49 +------ bindings/ruby/ext/metal-embed.mk | 17 --- bindings/ruby/ext/metal.mk | 6 - bindings/ruby/ext/options.rb | 219 ++++++++++++++++++++++++++++ bindings/ruby/sig/whisper.rbs | 210 +++++++++++++++++++++++++- bindings/ruby/tests/helper.rb | 11 ++ bindings/ruby/tests/test_package.rb | 21 ++- bindings/ruby/whispercpp.gemspec | 4 +- 11 files changed, 535 insertions(+), 88 deletions(-) delete mode 100644 bindings/ruby/ext/cpu.mk create mode 100644 bindings/ruby/ext/dependencies.rb delete mode 100644 bindings/ruby/ext/metal-embed.mk delete mode 100644 bindings/ruby/ext/metal.mk create mode 100644 bindings/ruby/ext/options.rb diff --git a/bindings/ruby/README.md b/bindings/ruby/README.md index 119940ad..7b1a7f29 100644 --- a/bindings/ruby/README.md +++ b/bindings/ruby/README.md @@ -16,6 +16,18 @@ If bundler is not being used to manage dependencies, install the gem by executin $ gem install whispercpp +You can pass build options for whisper.cpp, for instance: + + $ bundle config build.whispercpp --enable-ggml-cuda + +or, + + $ gem install whispercpp -- --enable-ggml-cuda + +See whisper.cpp's [README](https://github.com/ggml-org/whisper.cpp/blob/master/README.md) for available options. You need convert options present the README to Ruby-style options. +For boolean options like `GGML_CUDA`, the README says `-DGGML_CUDA=1`. You need strip `-D`, prepend `--enable-` for `1` or `ON` (`--disable-` for `0` or `OFF`) and make it kebab-case: `--enable-ggml-cuda`. +For options which require arguments like `CMAKE_CUDA_ARCHITECTURES`, the README says `-DCMAKE_CUDA_ARCHITECTURES="86"`. You need strip `-D`, prepend `--`, make it kebab-case, append `=` and append argument: `--cmake-cuda-architectures="86"`. + Usage ----- diff --git a/bindings/ruby/ext/cpu.mk b/bindings/ruby/ext/cpu.mk deleted file mode 100644 index 135d270b..00000000 --- a/bindings/ruby/ext/cpu.mk +++ /dev/null @@ -1,13 +0,0 @@ -ggml/src/ggml-cpu/ggml-cpu-cpp.o: \ - ggml/src/ggml-cpu/ggml-cpu.cpp \ - ggml/src/ggml-cpu/unary-ops.cpp \ - ggml/src/ggml-cpu/binary-ops.cpp \ - ggml/src/ggml-cpu/vec.cpp \ - ggml/src/ggml-cpu/ops.cpp \ - ggml/include/ggml-backend.h \ - ggml/include/ggml.h \ - ggml/include/ggml-alloc.h \ - ggml/src/ggml-backend-impl.h \ - ggml/include/ggml-cpu.h \ - ggml/src/ggml-impl.h - $(CXX) $(CXXFLAGS) -c $< -o $@ diff --git a/bindings/ruby/ext/dependencies.rb b/bindings/ruby/ext/dependencies.rb new file mode 100644 index 00000000..9beb128c --- /dev/null +++ b/bindings/ruby/ext/dependencies.rb @@ -0,0 +1,61 @@ +require "tsort" + +class Dependencies + def initialize(cmake, options) + @cmake = cmake + @options = options + + generate_dot + @libs = parse_dot + end + + def to_s + @libs.join(" ") + end + + private + + def dot_path + File.join(__dir__, "build", "whisper.cpp.dot") + end + + def generate_dot + system @cmake, "-S", "sources", "-B", "build", "--graphviz", dot_path, "-D", "BUILD_SHARED_LIBS=OFF", @options.to_s, exception: true + end + + def parse_dot + static_lib_shape = nil + nodes = {} + depends = Hash.new {|h, k| h[k] = []} + + class << depends + include TSort + alias tsort_each_node each_key + def tsort_each_child(node, &block) + fetch(node, []).each(&block) + end + end + + File.open(dot_path).each_line do |line| + case line + when /\[\s*label\s*=\s*"Static Library"\s*,\s*shape\s*=\s*(?\w+)\s*\]/ + static_lib_shape = $~[:shape] + when /\A\s*"(?\w+)"\s*\[\s*label\s*=\s*"(?