# madcat-say — VoxCPM2 voice-cloning CLI (on-device, MLX/Metal) # # MLX needs a compiled Metal shader library (mlx.metallib) sitting next to the # binary, or inference crashes with "Failed to load the default metallib". # We reuse the one speech-swift already builds. SPEECH_SWIFT ?= ../speech-swift CONFIG ?= release .PHONY: build run clean metallib install build: swift build -c $(CONFIG) @$(MAKE) --no-print-directory metallib # Copy the prebuilt metallib next to our binary. SwiftPM's real bin dir is # triple-prefixed (e.g. .build/arm64-apple-macosx/release) and the # .build/ symlink is not always present in speech-swift, so resolve # both ends with `swift build --show-bin-path` instead of hardcoding the path. # If speech-swift hasn't built the metallib yet, fall back to its build script. metallib: @ss_bin="$$(cd "$(SPEECH_SWIFT)" && swift build -c $(CONFIG) --show-bin-path)"; \ if [ ! -f "$$ss_bin/mlx.metallib" ]; then \ echo "metallib missing in speech-swift — building it there..."; \ ( cd "$(SPEECH_SWIFT)" && swift build -c $(CONFIG) && ./scripts/build_mlx_metallib.sh $(CONFIG) ); \ ss_bin="$$(cd "$(SPEECH_SWIFT)" && swift build -c $(CONFIG) --show-bin-path)"; \ fi; \ our_bin="$$(swift build -c $(CONFIG) --show-bin-path)"; \ cp "$$ss_bin/mlx.metallib" "$$our_bin/mlx.metallib"; \ echo "metallib in place: $$our_bin/mlx.metallib" # Quick smoke test (default voice). run: build .build/$(CONFIG)/madcat-say "Hello. This is madcat say, running on device." # Install to ~/.local/bin (binary + metallib alongside it). install: build @mkdir -p $(HOME)/.local/bin cp ".build/$(CONFIG)/madcat-say" "$(HOME)/.local/bin/madcat-say" cp ".build/$(CONFIG)/mlx.metallib" "$(HOME)/.local/bin/mlx.metallib" @echo "installed to ~/.local/bin/madcat-say (with mlx.metallib)" clean: swift package clean rm -rf .build