diff --git a/bindings/ruby/Rakefile b/bindings/ruby/Rakefile index e138960b..9b2787e9 100644 --- a/bindings/ruby/Rakefile +++ b/bindings/ruby/Rakefile @@ -17,7 +17,12 @@ extsources.each_pair do |src_dir, dests| end SOURCES = extsources.values.flatten CLEAN.include SOURCES -CLEAN.include FileList["ext/*.o", "ext/whisper.so", "ext/whisper.bundle", "ext/whisper.dll"] +CLEAN.include FileList[ + "ext/*.o", + "ext/*.metal", + "ext/whisper.{so,bundle,dll}", + "ext/depend" + ] task build: SOURCES + FileList[ "ext/extconf.rb", diff --git a/bindings/ruby/ext/extconf.rb b/bindings/ruby/ext/extconf.rb index 656d9e03..3b54a4a1 100644 --- a/bindings/ruby/ext/extconf.rb +++ b/bindings/ruby/ext/extconf.rb @@ -12,4 +12,219 @@ if enable_config('march-tune-native', false) $CXXFLAGS << ' -march=native -mtune=native' end -create_makefile('whisper') +def with_disabling_unsupported_files + disabled_files = [] + + unless $GGML_METAL + disabled_files << 'ggml-metal.h' << 'ggml-metal.m' + end + + unless $GGML_METAL_EMBED_LIBRARY + disabled_files << 'ggml-metal.metal' + end + + unless $OBJ_ALL&.include? 'ggml-blas.o' + disabled_files << 'ggml-blas.h' << 'ggml-blas.cpp' + end + + disabled_files.filter! {|file| File.exist? file} + + disabled_files.each do |file| + File.rename file, "#{file}.disabled" + end + + yield + + disabled_files.each do |file| + File.rename "#{file}.disabled", file + end +end + +if ENV['WHISPER_METAL'] + $GGML_METAL ||= true + $DEPRECATE_WARNING ||= true +end + +$UNAME_S = `uname -s`.chomp +$UNAME_P = `uname -p`.chomp +$UNAME_M = `uname -m`.chomp + +if $UNAME_S == 'Darwin' + unless ENV['GGML_NO_METAL'] + $GGML_METAL ||= true + end + $GGML_NO_OPENMP ||= true +end + +if $GGML_METAL + $GGML_METAL_EMBED_LIBRARY = true +end + +$MK_CPPFLAGS = '' +$MK_CFLAGS = '-std=c11 -fPIC' +$MK_CXXFLAGS = '-std=c++11 -fPIC' +$MK_NVCCFLAGS = '-std=c++11' +$MK_LDFLAGS = '' + +$OBJ_GGML = '' +$OBJ_WHISPER = '' +$OBJ_COMMON = '' +$OBJ_SDL = '' + +$MK_CPPFLAGS << ' -D_XOPEN_SOURCE=600' + +if $UNAME_S == 'Linux' + $MK_CPPFLAGS << ' -D_GNU_SOURCE' +end + +if $UNAME_S == 'Darwin' + $MK_CPPFLAGS << ' -D_DARWIN_C_SOURCE' +end + +if ENV['WHISPER_DEBUG'] + $MK_CFLAGS << ' -O0 -g' + $MK_CXXFLAGS << ' -O0 -g' + $MK_LDFLAGS << ' -g' + $MK_NVCCFLAGS << ' -O0 -g' +else + $MK_CPPFLAGS << ' -DNDEBUG' + $MK_CFLAGS << ' -O3' + $MK_CXXFLAGS << ' -O3' + $MK_NVCCFLAGS << ' -O3' +end + +$WARN_FLAGS = + ' -Wall' << + ' -Wextra' << + ' -Wpedantic' << + ' -Wcast-qual' << + ' -Wno-unused-function' + +$MK_CFLAGS << + $WARN_FLAGS << + ' -Wshadow' << + ' -Wstrict-prototypes' << + ' -Wpointer-arith' << + ' -Wmissing-prototypes' << + ' -Werror=implicit-int' << + ' -Werror=implicit-function-declaration' + +$MK_CXXFLAGS << + $WARN_FLAGS << + ' -Wmissing-declarations' << + ' -Wmissing-noreturn' + +unless `#{cc_command} #{$LDFLAGS} -Wl,-v 2>&1`.chomp.include? 'dyld-1015.7' + $MK_CPPFLAGS << ' -DHAVE_BUGGY_APPLE_LINKER' +end + +if %w[Linux Darwin FreeBSD NetBSD OpenBSD Haiku].include? $UNAME_S + $MK_CFLAGS << ' -pthread' + $MK_CXXFLAGS << ' -pthread' +end + +unless $_WIN32 + $DSO_EXT = '.so' +else + $DSO_EXT = '.dll' +end + +unless ENV['RISCV'] + if %w[x86_64 i686 amd64].include? $UNAME_M + $HOST_CXXFLAGS ||= '' + + $MK_CFLAGS << ' -march=native -mtune=native' + $HOST_CXXFLAGS << ' -march=native -mtune=native' + end + + if $UNAME_M.match? /aarch64.*/ + $MK_CFLAGS << ' -mcpu=native' + $MK_CXXFLAGS << ' -mcpu=native' + end +else + $MK_CFLAGS << ' -march=rv64gcv -mabi=lp64d' + $MK_CXXFLAGS << ' -march=rv64gcv -mabi=lp64d' +end + +unless ENV['GGML_NO_ACCELERATE'] + if $UNAME_S == 'Darwin' + $MK_CPPFLAGS << ' -DGGML_USE_ACCELERATE -DGGML_USE_BLAS' + $MK_CPPFLAGS << ' -DACCELERATE_NEW_LAPACK' + $MK_CPPFLAGS << ' -DACCELERATE_LAPACK_ILP64' + $MK_LDFLAGS << ' -framework Accelerate' + $OBJ_GGML << ' ggml-blas.o' + end +end + +if ENV['GGML_OPENBLAS'] + $MK_CPPFLAGS << " -DGGML_USE_BLAS #{`pkg-config --cflags-only-I openblas`.chomp}" + $MK_CFLAGS << " #{`pkg-config --cflags-only-other openblas)`.chomp}" + $MK_LDFLAGS << " #{`pkg-config --libs openblas`}" + $OBJ_GGML << ' ggml-blas.o' +end + +if ENV['GGML_OPENBLAS64'] + $MK_CPPFLAGS << " -DGGML_USE_BLAS #{`pkg-config --cflags-only-I openblas64`.chomp}" + $MK_CFLAGS << " #{`pkg-config --cflags-only-other openblas64)`.chomp}" + $MK_LDFLAGS << " #{`pkg-config --libs openblas64`}" + $OBJ_GGML << ' ggml-blas.o' +end + +if $GGML_METAL + $MK_CPPFLAGS << ' -DGGML_USE_METAL' + $MK_LDFLAGS << ' -framework Foundation -framework Metal -framework MetalKit' + $OBJ_GGML << ' ggml-metal.o' + + if ENV['GGML_METAL_NDEBUG'] + $MK_CPPFLAGS << ' -DGGML_METAL_NDEBUG' + end + + if $GGML_METAL_EMBED_LIBRARY + $MK_CPPFLAGS << ' -DGGML_METAL_EMBED_LIBRARY' + $OBJ_GGML << ' ggml-metal-embed.o' + end +end + +$OBJ_GGML << + ' ggml.o' << + ' ggml-alloc.o' << + ' ggml-backend.o' << + ' ggml-quants.o' << + ' ggml-aarch64.o' + +$OBJ_WHISPER << + ' whisper.o' + +$OBJ_ALL = "#{$OBJ_GGML} #{$OBJ_WHISPER} #{$OBJ_COMMON} #{$OBJ_SDL}" + +$CPPFLAGS = "#{$MK_CPPFLAGS} #{$CPPFLAGS}" +$CFLAGS = "#{$CPPFLAGS} #{$MK_CFLAGS} #{$GF_CFLAGS} #{$CFLAGS}" +$BASE_CXXFLAGS = "#{$MK_CXXFLAGS} #{$CXXFLAGS}" +$CXXFLAGS = "#{$BASE_CXXFLAGS} #{$HOST_CXXFLAGS} #{$GF_CXXFLAGS} #{$CPPFLAGS}" +$NVCCFLAGS = "#{$MK_NVCCFLAGS} #{$NVCCFLAGS}" +$LDFLAGS = "#{$MK_LDFLAGS} #{$LDFLAGS}" + +if $GGML_METAL_EMBED_LIBRARY + File.write 'depend', "$(OBJS): $(OBJS) ggml-metal-embed.o\n" +end + +with_disabling_unsupported_files do + + create_makefile('whisper') + +end + +File.open 'Makefile', 'a' do |file| + file.puts 'include get-flags.mk' + + if $GGML_METAL + if $GGML_METAL_EMBED_LIBRARY + # mkmf determines object files to compile dependent on existing *.{c,cpp,m} files + # but ggml-metal-embed.c doesn't exist on creating Makefile. + file.puts "objs := $(OBJS)" + file.puts "OBJS = $(objs) 'ggml-metal-embed.o'" + + file.puts 'include metal-embed.mk' + end + end +end diff --git a/bindings/ruby/ext/metal-embed.mk b/bindings/ruby/ext/metal-embed.mk new file mode 100644 index 00000000..478b8fd8 --- /dev/null +++ b/bindings/ruby/ext/metal-embed.mk @@ -0,0 +1,14 @@ +ggml-metal-embed.o: \ + ggml-metal.metal \ + ggml-common.h + @echo "Embedding Metal library" + @sed -e '/#include "ggml-common.h"/r ggml-common.h' -e '/#include "ggml-common.h"/d' < ggml-metal.metal > ggml-metal-embed.metal + $(eval TEMP_ASSEMBLY=$(shell mktemp)) + @echo ".section __DATA, __ggml_metallib" > $(TEMP_ASSEMBLY) + @echo ".globl _ggml_metallib_start" >> $(TEMP_ASSEMBLY) + @echo "_ggml_metallib_start:" >> $(TEMP_ASSEMBLY) + @echo ".incbin \"ggml-metal-embed.metal\"" >> $(TEMP_ASSEMBLY) + @echo ".globl _ggml_metallib_end" >> $(TEMP_ASSEMBLY) + @echo "_ggml_metallib_end:" >> $(TEMP_ASSEMBLY) + @$(AS) $(TEMP_ASSEMBLY) -o $@ + @rm -f ${TEMP_ASSEMBLY} diff --git a/bindings/ruby/extsources.yaml b/bindings/ruby/extsources.yaml index 1a4b4d25..e59f6ecf 100644 --- a/bindings/ruby/extsources.yaml +++ b/bindings/ruby/extsources.yaml @@ -15,6 +15,9 @@ - ext/ggml-quants.h - ext/ggml-quants.c - ext/ggml-cpu-impl.h +- ext/ggml-metal.m +- ext/ggml-metal.metal +- ext/ggml-blas.cpp ../../ggml/include: - ext/ggml.h - ext/ggml-alloc.h @@ -24,9 +27,11 @@ - ext/ggml-metal.h - ext/ggml-sycl.h - ext/ggml-vulkan.h +- ext/ggml-blas.h +../../scripts: +- ext/get-flags.mk ../../examples: - ext/dr_wav.h ../..: - README.md - LICENSE -