mirror of
https://github.com/ggerganov/whisper.cpp.git
synced 2025-06-13 04:28:07 +00:00
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]
This commit is contained in:
@ -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 $@
|
61
bindings/ruby/ext/dependencies.rb
Normal file
61
bindings/ruby/ext/dependencies.rb
Normal file
@ -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*(?<shape>\w+)\s*\]/
|
||||
static_lib_shape = $~[:shape]
|
||||
when /\A\s*"(?<node>\w+)"\s*\[\s*label\s*=\s*"(?<label>\S+)"\s*,\s*shape\s*=\s*(?<shape>\w+)\s*\]\s*;\s*\z/
|
||||
node = $~[:node]
|
||||
label = $~[:label]
|
||||
shape = $~[:shape]
|
||||
nodes[node] = [label, shape]
|
||||
when /\A\s*"(?<depender>\w+)"\s*->\s*"(?<dependee>\w+)"/
|
||||
depender = $~[:depender]
|
||||
dependee = $~[:dependee]
|
||||
depends[depender] ||= []
|
||||
depends[depender] << dependee
|
||||
end
|
||||
end
|
||||
depends.tsort.filter_map {|node|
|
||||
label, shape = nodes[node]
|
||||
shape == static_lib_shape ? label : nil
|
||||
}.collect {|lib| "lib#{lib}.a"}
|
||||
.reverse
|
||||
end
|
||||
end
|
@ -1,50 +1,12 @@
|
||||
require "mkmf"
|
||||
require "tsort"
|
||||
|
||||
# TODO: options such as CoreML
|
||||
require_relative "options"
|
||||
require_relative "dependencies"
|
||||
|
||||
cmake = find_executable("cmake") || abort
|
||||
|
||||
options = Options.new
|
||||
have_library("gomp") rescue nil
|
||||
libs = Dependencies.new(cmake, options)
|
||||
|
||||
prefix = File.join("build", "whisper.cpp.dot")
|
||||
system cmake, "-S", "sources", "-B", "build", "--graphviz", prefix, "-D", "BUILD_SHARED_LIBS=OFF", exception: true
|
||||
|
||||
static_lib_shape = nil
|
||||
nodes = {}
|
||||
depends = {}
|
||||
class << depends
|
||||
include TSort
|
||||
alias tsort_each_node each_key
|
||||
def tsort_each_child(node, &block)
|
||||
fetch(node, []).each(&block)
|
||||
end
|
||||
end
|
||||
File.open(File.join("build", "whisper.cpp.dot")).each_line do |line|
|
||||
case line
|
||||
when /\[\s*label\s*=\s*"Static Library"\s*,\s*shape\s*=\s*(?<shape>\w+)\s*\]/
|
||||
static_lib_shape = $~[:shape]
|
||||
when /\A\s*"(?<node>\w+)"\s*\[\s*label\s*=\s*"(?<label>\S+)"\s*,\s*shape\s*=\s*(?<shape>\w+)\s*\]\s*;\s*\z/
|
||||
node = $~[:node]
|
||||
label = $~[:label]
|
||||
shape = $~[:shape]
|
||||
nodes[node] = [label, shape]
|
||||
when /\A\s*"(?<depender>\w+)"\s*->\s*"(?<dependee>\w+)"/
|
||||
depender = $~[:depender]
|
||||
dependee = $~[:dependee]
|
||||
depends[depender] ||= []
|
||||
depends[depender] << dependee
|
||||
end
|
||||
end
|
||||
libs = depends.tsort.filter_map {|node|
|
||||
label, shape = nodes[node]
|
||||
shape == static_lib_shape ? label : nil
|
||||
}.collect {|lib| "lib#{lib}.a"}
|
||||
.reverse
|
||||
.join(" ")
|
||||
|
||||
$CFLAGS << " -std=c11 -fPIC"
|
||||
$CXXFLAGS << " -std=c++17 -O3 -DNDEBUG"
|
||||
$INCFLAGS << " -Isources/include -Isources/ggml/include -Isources/examples"
|
||||
$LOCAL_LIBS << " #{libs}"
|
||||
$cleanfiles << " build #{libs}"
|
||||
@ -54,8 +16,7 @@ create_makefile "whisper" do |conf|
|
||||
$(TARGET_SO): #{libs}
|
||||
#{libs}: cmake-targets
|
||||
cmake-targets:
|
||||
#{"\t"}#{cmake} -S sources -B build -D BUILD_SHARED_LIBS=OFF -D CMAKE_ARCHIVE_OUTPUT_DIRECTORY=#{__dir__} -D CMAKE_POSITION_INDEPENDENT_CODE=ON
|
||||
#{"\t"}#{cmake} -S sources -B build -D BUILD_SHARED_LIBS=OFF -D CMAKE_ARCHIVE_OUTPUT_DIRECTORY=#{__dir__} -D CMAKE_POSITION_INDEPENDENT_CODE=ON #{options}
|
||||
#{"\t"}#{cmake} --build build --config Release --target common whisper
|
||||
#{"\t"}
|
||||
EOF
|
||||
end
|
||||
|
@ -1,17 +0,0 @@
|
||||
ggml/src/ggml-metal/ggml-metal-embed.o: \
|
||||
ggml/src/ggml-metal/ggml-metal.metal \
|
||||
ggml/src/ggml-metal/ggml-metal-impl.h \
|
||||
ggml/src/ggml-common.h
|
||||
@echo "Embedding Metal library"
|
||||
@sed -e '/__embed_ggml-common.h__/r ggml/src/ggml-common.h' -e '/__embed_ggml-common.h__/d' < ggml/src/ggml-metal/ggml-metal.metal > ggml/src/ggml-metal/ggml-metal-embed.metal.tmp
|
||||
@sed -e '/#include "ggml-metal-impl.h"/r ggml/src/ggml-metal/ggml-metal-impl.h' -e '/#include "ggml-metal-impl.h"/d' < ggml/src/ggml-metal/ggml-metal-embed.metal.tmp > ggml/src/ggml-metal/ggml-metal-embed.metal
|
||||
$(eval TEMP_ASSEMBLY=$(shell mktemp -d))
|
||||
@echo ".section __DATA, __ggml_metallib" > $(TEMP_ASSEMBLY)/ggml-metal-embed.s
|
||||
@echo ".globl _ggml_metallib_start" >> $(TEMP_ASSEMBLY)/ggml-metal-embed.s
|
||||
@echo "_ggml_metallib_start:" >> $(TEMP_ASSEMBLY)/ggml-metal-embed.s
|
||||
@echo ".incbin \"ggml/src/ggml-metal/ggml-metal-embed.metal\"" >> $(TEMP_ASSEMBLY)/ggml-metal-embed.s
|
||||
@echo ".globl _ggml_metallib_end" >> $(TEMP_ASSEMBLY)/ggml-metal-embed.s
|
||||
@echo "_ggml_metallib_end:" >> $(TEMP_ASSEMBLY)/ggml-metal-embed.s
|
||||
$(CC) $(CFLAGS) -c $(TEMP_ASSEMBLY)/ggml-metal-embed.s -o $@
|
||||
@rm -f ${TEMP_ASSEMBLY}/ggml-metal-embed.s
|
||||
@rmdir ${TEMP_ASSEMBLY}
|
@ -1,6 +0,0 @@
|
||||
ggml/src/ggml-metal/ggml-metal.o: \
|
||||
ggml/src/ggml-metal/ggml-metal.m \
|
||||
ggml/src/ggml-metal/ggml-metal-impl.h \
|
||||
ggml/include/ggml-metal.h \
|
||||
ggml/include/ggml.h
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
219
bindings/ruby/ext/options.rb
Normal file
219
bindings/ruby/ext/options.rb
Normal file
@ -0,0 +1,219 @@
|
||||
class Options
|
||||
def initialize
|
||||
@options = {}
|
||||
@pending_options = []
|
||||
@ignored_options = []
|
||||
|
||||
configure
|
||||
end
|
||||
|
||||
def help
|
||||
@options
|
||||
.collect_concat {|name, (type, value)|
|
||||
option = option_name(name)
|
||||
if type == :bool
|
||||
["--enable-#{option}", "--disable-#{option}"]
|
||||
else
|
||||
"--#{option}=#{type.upcase}"
|
||||
end
|
||||
}
|
||||
.join($/)
|
||||
end
|
||||
|
||||
def to_s
|
||||
@options
|
||||
.reject {|name, (type, value)| value.nil?}
|
||||
.collect {|name, (type, value)| "-D #{name}=#{value == true ? "ON" : value == false ? "OFF" : value.shellescape}"}
|
||||
.join(" ")
|
||||
end
|
||||
|
||||
def cmake_options
|
||||
return @cmake_options if @cmake_options
|
||||
|
||||
output = nil
|
||||
Dir.chdir __dir__ do
|
||||
output = `cmake -S sources -B build -L`
|
||||
end
|
||||
started = false
|
||||
@cmake_options = output.lines.filter_map {|line|
|
||||
if line.chomp == "-- Cache values"
|
||||
started = true
|
||||
next
|
||||
end
|
||||
next unless started
|
||||
option, value = line.chomp.split("=", 2)
|
||||
name, type = option.split(":", 2)
|
||||
[name, type, value]
|
||||
}
|
||||
end
|
||||
|
||||
def missing_options
|
||||
cmake_options.collect {|name, type, value| name} -
|
||||
@options.keys - @pending_options - @ignored_options
|
||||
end
|
||||
|
||||
def extra_options
|
||||
@options.keys + @pending_options - @ignored_options -
|
||||
cmake_options.collect {|name, type, value| name}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def configure
|
||||
filepath "ACCELERATE_FRAMEWORK"
|
||||
ignored "BUILD_SHARED_LIBS"
|
||||
ignored "BUILD_TESTING"
|
||||
ignored "CMAKE_BUILD_TYPE"
|
||||
ignored "CMAKE_INSTALL_PREFIX"
|
||||
string "CMAKE_OSX_ARCHITECTURES"
|
||||
ignored "CMAKE_OSX_DEPLOYMENT_TARGET"
|
||||
string "CMAKE_OSX_SYSROOT"
|
||||
filepath "FOUNDATION_LIBRARY"
|
||||
bool "GGML_ACCELERATE"
|
||||
bool "GGML_ALL_WARNINGS_3RD_PARTY"
|
||||
bool "GGML_AMX_BF16"
|
||||
bool "GGML_AMX_INT8"
|
||||
bool "GGML_AMX_TILE"
|
||||
bool "GGML_AVX"
|
||||
bool "GGML_AVX2"
|
||||
bool "GGML_AVX512"
|
||||
bool "GGML_AVX512_BF16"
|
||||
bool "GGML_AVX512_VBMI"
|
||||
bool "GGML_AVX512_VNNI"
|
||||
bool "GGML_AVX_VNNI"
|
||||
ignored "GGML_BACKEND_DL"
|
||||
ignored "GGML_BIN_INSTALL_DIR"
|
||||
bool "GGML_BLAS"
|
||||
string "GGML_BLAS_VENDOR"
|
||||
bool "GGML_BMI2"
|
||||
ignored "GGML_BUILD_EXAMPLES"
|
||||
ignored "GGML_BUILD_TESTS"
|
||||
filepath "GGML_CCACHE_FOUND"
|
||||
bool "GGML_CPU"
|
||||
bool "GGML_CPU_AARCH64"
|
||||
ignored "GGML_CPU_ALL_VARIANTS"
|
||||
string "GGML_CPU_ARM_ARCH"
|
||||
bool "GGML_CPU_HBM"
|
||||
bool "GGML_CPU_KLEIDIAI"
|
||||
string "GGML_CPU_POWERPC_CPUTYPE"
|
||||
bool "GGML_CUDA"
|
||||
string "GGML_CUDA_COMPRESSION_MODE"
|
||||
bool "GGML_CUDA_F16"
|
||||
bool "GGML_CUDA_FA"
|
||||
bool "GGML_CUDA_FA_ALL_QUANTS"
|
||||
bool "GGML_CUDA_FORCE_CUBLAS"
|
||||
bool "GGML_CUDA_FORCE_MMQ"
|
||||
ignored "GGML_CUDA_GRAPHS"
|
||||
bool "GGML_CUDA_NO_PEER_COPY"
|
||||
bool "GGML_CUDA_NO_VMM"
|
||||
string "GGML_CUDA_PEER_MAX_BATCH_SIZE"
|
||||
bool "GGML_F16C"
|
||||
bool "GGML_FMA"
|
||||
bool "GGML_GPROF"
|
||||
bool "GGML_HIP"
|
||||
bool "GGML_HIP_GRAPHS"
|
||||
bool "GGML_HIP_NO_VMM"
|
||||
bool "GGML_HIP_ROCWMMA_FATTN"
|
||||
bool "GGML_HIP_UMA"
|
||||
ignored "GGML_INCLUDE_INSTALL_DIR"
|
||||
bool "GGML_KOMPUTE"
|
||||
bool "GGML_LASX"
|
||||
ignored "GGML_LIB_INSTALL_DIR"
|
||||
ignored "GGML_LLAMAFILE"
|
||||
bool "GGML_LSX"
|
||||
bool "GGML_LTO"
|
||||
bool "GGML_METAL"
|
||||
bool "GGML_METAL_EMBED_LIBRARY"
|
||||
string "GGML_METAL_MACOSX_VERSION_MIN"
|
||||
bool "GGML_METAL_NDEBUG"
|
||||
bool "GGML_METAL_SHADER_DEBUG"
|
||||
string "GGML_METAL_STD"
|
||||
bool "GGML_METAL_USE_BF16"
|
||||
bool "GGML_MUSA"
|
||||
bool "GGML_NATIVE"
|
||||
bool "GGML_OPENCL"
|
||||
bool "GGML_OPENCL_EMBED_KERNELS"
|
||||
bool "GGML_OPENCL_PROFILING"
|
||||
string "GGML_OPENCL_TARGET_VERSION"
|
||||
bool "GGML_OPENCL_USE_ADRENO_KERNELS"
|
||||
bool "GGML_OPENMP"
|
||||
bool "GGML_RPC"
|
||||
bool "GGML_RVV"
|
||||
bool "GGML_RV_ZFH"
|
||||
pending "GGML_SCCACHE_FOUND"
|
||||
string "GGML_SCHED_MAX_COPIES"
|
||||
ignored "GGML_STATIC"
|
||||
bool "GGML_SYCL"
|
||||
string "GGML_SYCL_DEVICE_ARCH"
|
||||
bool "GGML_SYCL_F16"
|
||||
bool "GGML_SYCL_GRAPH"
|
||||
string "GGML_SYCL_TARGET"
|
||||
bool "GGML_VULKAN"
|
||||
bool "GGML_VULKAN_CHECK_RESULTS"
|
||||
bool "GGML_VULKAN_DEBUG"
|
||||
bool "GGML_VULKAN_MEMORY_DEBUG"
|
||||
bool "GGML_VULKAN_PERF"
|
||||
ignored "GGML_VULKAN_RUN_TESTS"
|
||||
filepath "GGML_VULKAN_SHADERS_GEN_TOOLCHAIN"
|
||||
bool "GGML_VULKAN_SHADER_DEBUG_INFO"
|
||||
pending "GGML_VULKAN_VALIDATE"
|
||||
bool "GGML_VXE"
|
||||
filepath "GIT_EXE"
|
||||
filepath "MATH_LIBRARY"
|
||||
filepath "METALKIT_FRAMEWORK"
|
||||
filepath "METAL_FRAMEWORK"
|
||||
bool "WHISPER_ALL_WARNINGS"
|
||||
bool "WHISPER_ALL_WARNINGS_3RD_PARTY"
|
||||
ignored "WHISPER_BIN_INSTALL_DIR"
|
||||
ignored "WHISPER_BUILD_EXAMPLES"
|
||||
ignored "WHISPER_BUILD_SERVER"
|
||||
ignored"WHISPER_BUILD_TESTS"
|
||||
bool "WHISPER_CCACHE"
|
||||
bool "WHISPER_COREML"
|
||||
bool "WHISPER_COREML_ALLOW_FALLBACK"
|
||||
ignored "WHISPER_CURL"
|
||||
bool "WHISPER_FATAL_WARNINGS"
|
||||
ignored "WHISPER_FFMPEG"
|
||||
ignored "WHISPER_INCLUDE_INSTALL_DIR"
|
||||
ignored "WHISPER_LIB_INSTALL_DIR"
|
||||
bool "WHISPER_OPENVINO"
|
||||
bool "WHISPER_SANITIZE_ADDRESS"
|
||||
bool "WHISPER_SANITIZE_THREAD"
|
||||
bool "WHISPER_SANITIZE_UNDEFINED"
|
||||
ignored "WHISPER_SDL2"
|
||||
pending "WHISPER_USE_SYSTEM_GGML"
|
||||
end
|
||||
|
||||
def option_name(name)
|
||||
name.downcase.gsub("_", "-")
|
||||
end
|
||||
|
||||
def bool(name)
|
||||
option = option_name(name)
|
||||
value = enable_config(option)
|
||||
@options[name] = [:bool, value]
|
||||
end
|
||||
|
||||
def string(name, type=:string)
|
||||
option = "--#{option_name(name)}"
|
||||
value = arg_config(option)
|
||||
raise "String expected for #{option}" if value == true || value&.empty?
|
||||
@options[name] = [type, value]
|
||||
end
|
||||
|
||||
def path(name)
|
||||
string(name, :path)
|
||||
end
|
||||
|
||||
def filepath(name)
|
||||
string(name, :filepath)
|
||||
end
|
||||
|
||||
def pending(name)
|
||||
@pending_options << name
|
||||
end
|
||||
|
||||
def ignored(name)
|
||||
@ignored_options << name
|
||||
end
|
||||
end
|
Reference in New Issue
Block a user