Skip to content

Commit a9d704b

Browse files
KitaitiMakotoadutilleul
authored andcommitted
ruby : add Metal support (ggml-org#2516)
1 parent 42f9132 commit a9d704b

File tree

4 files changed

+242
-3
lines changed

4 files changed

+242
-3
lines changed

bindings/ruby/Rakefile

+6-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,12 @@ extsources.each_pair do |src_dir, dests|
1717
end
1818
SOURCES = extsources.values.flatten
1919
CLEAN.include SOURCES
20-
CLEAN.include FileList["ext/*.o", "ext/whisper.so", "ext/whisper.bundle", "ext/whisper.dll"]
20+
CLEAN.include FileList[
21+
"ext/*.o",
22+
"ext/*.metal",
23+
"ext/whisper.{so,bundle,dll}",
24+
"ext/depend"
25+
]
2126

2227
task build: SOURCES + FileList[
2328
"ext/extconf.rb",

bindings/ruby/ext/extconf.rb

+216-1
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,219 @@
1212
$CXXFLAGS << ' -march=native -mtune=native'
1313
end
1414

15-
create_makefile('whisper')
15+
def with_disabling_unsupported_files
16+
disabled_files = []
17+
18+
unless $GGML_METAL
19+
disabled_files << 'ggml-metal.h' << 'ggml-metal.m'
20+
end
21+
22+
unless $GGML_METAL_EMBED_LIBRARY
23+
disabled_files << 'ggml-metal.metal'
24+
end
25+
26+
unless $OBJ_ALL&.include? 'ggml-blas.o'
27+
disabled_files << 'ggml-blas.h' << 'ggml-blas.cpp'
28+
end
29+
30+
disabled_files.filter! {|file| File.exist? file}
31+
32+
disabled_files.each do |file|
33+
File.rename file, "#{file}.disabled"
34+
end
35+
36+
yield
37+
38+
disabled_files.each do |file|
39+
File.rename "#{file}.disabled", file
40+
end
41+
end
42+
43+
if ENV['WHISPER_METAL']
44+
$GGML_METAL ||= true
45+
$DEPRECATE_WARNING ||= true
46+
end
47+
48+
$UNAME_S = `uname -s`.chomp
49+
$UNAME_P = `uname -p`.chomp
50+
$UNAME_M = `uname -m`.chomp
51+
52+
if $UNAME_S == 'Darwin'
53+
unless ENV['GGML_NO_METAL']
54+
$GGML_METAL ||= true
55+
end
56+
$GGML_NO_OPENMP ||= true
57+
end
58+
59+
if $GGML_METAL
60+
$GGML_METAL_EMBED_LIBRARY = true
61+
end
62+
63+
$MK_CPPFLAGS = ''
64+
$MK_CFLAGS = '-std=c11 -fPIC'
65+
$MK_CXXFLAGS = '-std=c++11 -fPIC'
66+
$MK_NVCCFLAGS = '-std=c++11'
67+
$MK_LDFLAGS = ''
68+
69+
$OBJ_GGML = ''
70+
$OBJ_WHISPER = ''
71+
$OBJ_COMMON = ''
72+
$OBJ_SDL = ''
73+
74+
$MK_CPPFLAGS << ' -D_XOPEN_SOURCE=600'
75+
76+
if $UNAME_S == 'Linux'
77+
$MK_CPPFLAGS << ' -D_GNU_SOURCE'
78+
end
79+
80+
if $UNAME_S == 'Darwin'
81+
$MK_CPPFLAGS << ' -D_DARWIN_C_SOURCE'
82+
end
83+
84+
if ENV['WHISPER_DEBUG']
85+
$MK_CFLAGS << ' -O0 -g'
86+
$MK_CXXFLAGS << ' -O0 -g'
87+
$MK_LDFLAGS << ' -g'
88+
$MK_NVCCFLAGS << ' -O0 -g'
89+
else
90+
$MK_CPPFLAGS << ' -DNDEBUG'
91+
$MK_CFLAGS << ' -O3'
92+
$MK_CXXFLAGS << ' -O3'
93+
$MK_NVCCFLAGS << ' -O3'
94+
end
95+
96+
$WARN_FLAGS =
97+
' -Wall' <<
98+
' -Wextra' <<
99+
' -Wpedantic' <<
100+
' -Wcast-qual' <<
101+
' -Wno-unused-function'
102+
103+
$MK_CFLAGS <<
104+
$WARN_FLAGS <<
105+
' -Wshadow' <<
106+
' -Wstrict-prototypes' <<
107+
' -Wpointer-arith' <<
108+
' -Wmissing-prototypes' <<
109+
' -Werror=implicit-int' <<
110+
' -Werror=implicit-function-declaration'
111+
112+
$MK_CXXFLAGS <<
113+
$WARN_FLAGS <<
114+
' -Wmissing-declarations' <<
115+
' -Wmissing-noreturn'
116+
117+
unless `#{cc_command} #{$LDFLAGS} -Wl,-v 2>&1`.chomp.include? 'dyld-1015.7'
118+
$MK_CPPFLAGS << ' -DHAVE_BUGGY_APPLE_LINKER'
119+
end
120+
121+
if %w[Linux Darwin FreeBSD NetBSD OpenBSD Haiku].include? $UNAME_S
122+
$MK_CFLAGS << ' -pthread'
123+
$MK_CXXFLAGS << ' -pthread'
124+
end
125+
126+
unless $_WIN32
127+
$DSO_EXT = '.so'
128+
else
129+
$DSO_EXT = '.dll'
130+
end
131+
132+
unless ENV['RISCV']
133+
if %w[x86_64 i686 amd64].include? $UNAME_M
134+
$HOST_CXXFLAGS ||= ''
135+
136+
$MK_CFLAGS << ' -march=native -mtune=native'
137+
$HOST_CXXFLAGS << ' -march=native -mtune=native'
138+
end
139+
140+
if $UNAME_M.match? /aarch64.*/
141+
$MK_CFLAGS << ' -mcpu=native'
142+
$MK_CXXFLAGS << ' -mcpu=native'
143+
end
144+
else
145+
$MK_CFLAGS << ' -march=rv64gcv -mabi=lp64d'
146+
$MK_CXXFLAGS << ' -march=rv64gcv -mabi=lp64d'
147+
end
148+
149+
unless ENV['GGML_NO_ACCELERATE']
150+
if $UNAME_S == 'Darwin'
151+
$MK_CPPFLAGS << ' -DGGML_USE_ACCELERATE -DGGML_USE_BLAS'
152+
$MK_CPPFLAGS << ' -DACCELERATE_NEW_LAPACK'
153+
$MK_CPPFLAGS << ' -DACCELERATE_LAPACK_ILP64'
154+
$MK_LDFLAGS << ' -framework Accelerate'
155+
$OBJ_GGML << ' ggml-blas.o'
156+
end
157+
end
158+
159+
if ENV['GGML_OPENBLAS']
160+
$MK_CPPFLAGS << " -DGGML_USE_BLAS #{`pkg-config --cflags-only-I openblas`.chomp}"
161+
$MK_CFLAGS << " #{`pkg-config --cflags-only-other openblas)`.chomp}"
162+
$MK_LDFLAGS << " #{`pkg-config --libs openblas`}"
163+
$OBJ_GGML << ' ggml-blas.o'
164+
end
165+
166+
if ENV['GGML_OPENBLAS64']
167+
$MK_CPPFLAGS << " -DGGML_USE_BLAS #{`pkg-config --cflags-only-I openblas64`.chomp}"
168+
$MK_CFLAGS << " #{`pkg-config --cflags-only-other openblas64)`.chomp}"
169+
$MK_LDFLAGS << " #{`pkg-config --libs openblas64`}"
170+
$OBJ_GGML << ' ggml-blas.o'
171+
end
172+
173+
if $GGML_METAL
174+
$MK_CPPFLAGS << ' -DGGML_USE_METAL'
175+
$MK_LDFLAGS << ' -framework Foundation -framework Metal -framework MetalKit'
176+
$OBJ_GGML << ' ggml-metal.o'
177+
178+
if ENV['GGML_METAL_NDEBUG']
179+
$MK_CPPFLAGS << ' -DGGML_METAL_NDEBUG'
180+
end
181+
182+
if $GGML_METAL_EMBED_LIBRARY
183+
$MK_CPPFLAGS << ' -DGGML_METAL_EMBED_LIBRARY'
184+
$OBJ_GGML << ' ggml-metal-embed.o'
185+
end
186+
end
187+
188+
$OBJ_GGML <<
189+
' ggml.o' <<
190+
' ggml-alloc.o' <<
191+
' ggml-backend.o' <<
192+
' ggml-quants.o' <<
193+
' ggml-aarch64.o'
194+
195+
$OBJ_WHISPER <<
196+
' whisper.o'
197+
198+
$OBJ_ALL = "#{$OBJ_GGML} #{$OBJ_WHISPER} #{$OBJ_COMMON} #{$OBJ_SDL}"
199+
200+
$CPPFLAGS = "#{$MK_CPPFLAGS} #{$CPPFLAGS}"
201+
$CFLAGS = "#{$CPPFLAGS} #{$MK_CFLAGS} #{$GF_CFLAGS} #{$CFLAGS}"
202+
$BASE_CXXFLAGS = "#{$MK_CXXFLAGS} #{$CXXFLAGS}"
203+
$CXXFLAGS = "#{$BASE_CXXFLAGS} #{$HOST_CXXFLAGS} #{$GF_CXXFLAGS} #{$CPPFLAGS}"
204+
$NVCCFLAGS = "#{$MK_NVCCFLAGS} #{$NVCCFLAGS}"
205+
$LDFLAGS = "#{$MK_LDFLAGS} #{$LDFLAGS}"
206+
207+
if $GGML_METAL_EMBED_LIBRARY
208+
File.write 'depend', "$(OBJS): $(OBJS) ggml-metal-embed.o\n"
209+
end
210+
211+
with_disabling_unsupported_files do
212+
213+
create_makefile('whisper')
214+
215+
end
216+
217+
File.open 'Makefile', 'a' do |file|
218+
file.puts 'include get-flags.mk'
219+
220+
if $GGML_METAL
221+
if $GGML_METAL_EMBED_LIBRARY
222+
# mkmf determines object files to compile dependent on existing *.{c,cpp,m} files
223+
# but ggml-metal-embed.c doesn't exist on creating Makefile.
224+
file.puts "objs := $(OBJS)"
225+
file.puts "OBJS = $(objs) 'ggml-metal-embed.o'"
226+
227+
file.puts 'include metal-embed.mk'
228+
end
229+
end
230+
end

bindings/ruby/ext/metal-embed.mk

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
ggml-metal-embed.o: \
2+
ggml-metal.metal \
3+
ggml-common.h
4+
@echo "Embedding Metal library"
5+
@sed -e '/#include "ggml-common.h"/r ggml-common.h' -e '/#include "ggml-common.h"/d' < ggml-metal.metal > ggml-metal-embed.metal
6+
$(eval TEMP_ASSEMBLY=$(shell mktemp))
7+
@echo ".section __DATA, __ggml_metallib" > $(TEMP_ASSEMBLY)
8+
@echo ".globl _ggml_metallib_start" >> $(TEMP_ASSEMBLY)
9+
@echo "_ggml_metallib_start:" >> $(TEMP_ASSEMBLY)
10+
@echo ".incbin \"ggml-metal-embed.metal\"" >> $(TEMP_ASSEMBLY)
11+
@echo ".globl _ggml_metallib_end" >> $(TEMP_ASSEMBLY)
12+
@echo "_ggml_metallib_end:" >> $(TEMP_ASSEMBLY)
13+
@$(AS) $(TEMP_ASSEMBLY) -o $@
14+
@rm -f ${TEMP_ASSEMBLY}

bindings/ruby/extsources.yaml

+6-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
- ext/ggml-quants.h
1616
- ext/ggml-quants.c
1717
- ext/ggml-cpu-impl.h
18+
- ext/ggml-metal.m
19+
- ext/ggml-metal.metal
20+
- ext/ggml-blas.cpp
1821
../../ggml/include:
1922
- ext/ggml.h
2023
- ext/ggml-alloc.h
@@ -24,9 +27,11 @@
2427
- ext/ggml-metal.h
2528
- ext/ggml-sycl.h
2629
- ext/ggml-vulkan.h
30+
- ext/ggml-blas.h
31+
../../scripts:
32+
- ext/get-flags.mk
2733
../../examples:
2834
- ext/dr_wav.h
2935
../..:
3036
- README.md
3137
- LICENSE
32-

0 commit comments

Comments
 (0)