Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ jobs:
go-version: "1.24"
- name: Build with CGO (llamacpp tag)
run: CGO_ENABLED=1 go build -tags llamacpp ./ggml/llamacpp/...
- name: Build with CGO (whispercpp tag)
run: CGO_ENABLED=1 go build -tags whispercpp ./ggml/whispercpp/...

build-libs:
name: Build Libraries from Source (${{ matrix.os }})
Expand Down Expand Up @@ -68,9 +70,16 @@ jobs:
- name: Build static libraries from source
run: make build-libs
- name: Verify CGO build with fresh libraries
run: CGO_ENABLED=1 go build -tags llamacpp ./ggml/llamacpp/...
- name: Upload prebuilt artifacts
run: |
CGO_ENABLED=1 go build -tags llamacpp ./ggml/llamacpp/...
CGO_ENABLED=1 go build -tags whispercpp ./ggml/whispercpp/...
- name: Upload llama.cpp prebuilt artifacts
uses: actions/upload-artifact@v4
with:
name: prebuilt-llamacpp-${{ matrix.platform }}
path: ggml/llamacpp/third_party/prebuilt/${{ matrix.platform }}/*.a
- name: Upload whisper.cpp prebuilt artifacts
uses: actions/upload-artifact@v4
with:
name: prebuilt-${{ matrix.platform }}
path: third_party/llama.cpp/prebuilt/${{ matrix.platform }}/*.a
name: prebuilt-whispercpp-${{ matrix.platform }}
path: ggml/whispercpp/third_party/prebuilt/${{ matrix.platform }}/*.a
6 changes: 3 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Build artifacts (source downloads, cmake dirs)
third_party/llama.cpp/src/
third_party/whisper.cpp/src/
third_party/**/build/
ggml/llamacpp/third_party/src/
ggml/whispercpp/third_party/src/
**/build/
out/

# Prebuilt .a files and headers ARE committed — do not ignore them
Expand Down
25 changes: 22 additions & 3 deletions Dockerfile.libs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Dockerfile.libs — build linux-amd64 static libraries for llama.cpp
# Dockerfile.libs — build linux-amd64 static libraries for llama.cpp and whisper.cpp
#
# Usage:
# docker build -f Dockerfile.libs -o ./out .
Expand All @@ -18,27 +18,46 @@ COPY go.mod ./
COPY version.go ./
COPY cmd/versioncmd/ ./cmd/versioncmd/

# Read versions and download sources
# Download llama.cpp
RUN LLAMA_VERSION=$(go run ./cmd/versioncmd llama.cpp) && \
echo "Downloading llama.cpp ${LLAMA_VERSION}..." && \
wget -qO llama.cpp.tar.gz "https://github.com/ggerganov/llama.cpp/archive/refs/tags/${LLAMA_VERSION}.tar.gz" && \
mkdir -p llama-src && \
tar xzf llama.cpp.tar.gz --strip-components=1 -C llama-src && \
rm llama.cpp.tar.gz

# Download whisper.cpp
RUN WHISPER_VERSION=$(go run ./cmd/versioncmd whisper.cpp) && \
echo "Downloading whisper.cpp ${WHISPER_VERSION}..." && \
wget -qO whisper.cpp.tar.gz "https://github.com/ggerganov/whisper.cpp/archive/refs/tags/${WHISPER_VERSION}.tar.gz" && \
mkdir -p whisper-src && \
tar xzf whisper.cpp.tar.gz --strip-components=1 -C whisper-src && \
rm whisper.cpp.tar.gz

# Build llama.cpp
RUN cd llama-src && \
cmake -B build -DBUILD_SHARED_LIBS=OFF && \
cmake --build build --config Release -j$(nproc)

# Collect artifacts
# Build whisper.cpp
RUN cd whisper-src && \
cmake -B build -DBUILD_SHARED_LIBS=OFF && \
cmake --build build --config Release -j$(nproc)

# Collect llama.cpp artifacts
RUN mkdir -p /out/llama.cpp/linux-amd64 /out/llama.cpp/include /out/llama.cpp/ggml/include /out/llama.cpp/common && \
find llama-src/build -name "*.a" -exec cp {} /out/llama.cpp/linux-amd64/ \; && \
cp llama-src/include/*.h /out/llama.cpp/include/ && \
cp llama-src/ggml/include/*.h /out/llama.cpp/ggml/include/ && \
cp llama-src/common/common.h /out/llama.cpp/common/ && \
cp llama-src/common/sampling.h /out/llama.cpp/common/

# Collect whisper.cpp artifacts
RUN mkdir -p /out/whisper.cpp/linux-amd64 /out/whisper.cpp/include /out/whisper.cpp/ggml/include && \
find whisper-src/build -name "*.a" -exec cp {} /out/whisper.cpp/linux-amd64/ \; && \
cp whisper-src/include/*.h /out/whisper.cpp/include/ && \
cp whisper-src/ggml/include/*.h /out/whisper.cpp/ggml/include/

# Output stage — docker build -o extracts from here
FROM scratch
COPY --from=builder /out/ /
91 changes: 65 additions & 26 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@
#
# For consumers:
# go get github.com/footprintai/go-nativeml
# go build -tags llamacpp ./... # just works — prebuilt .a files are in the module
# go build -tags llamacpp ./... # just works — prebuilt .a files are in the module
# go build -tags whispercpp ./... # whisper.cpp bindings
#
# For maintainers (rebuild .a files from source):
# make build-libs # Build all libraries for current platform
# make build-libs-llama # Build llama.cpp only
# make build-libs-whisper # Build whisper.cpp only
# make build-libs-linux # Build linux-amd64 .a files via Docker
# make build-libs-all # Build native + linux-amd64
# make clean # Remove temp build dirs (keeps prebuilt .a + headers)
Expand All @@ -21,15 +23,18 @@ PLATFORM := $(shell go env GOOS)-$(shell go env GOARCH)
# Parallel build cores
NPROC := $(shell if which nproc > /dev/null 2>&1; then nproc; elif [ "$$(uname)" = "Darwin" ]; then sysctl -n hw.ncpu; else echo 4; fi)

# Paths
THIRD_PARTY := third_party
LLAMA_DIR := $(THIRD_PARTY)/llama.cpp
LLAMA_SRC := $(LLAMA_DIR)/src
LLAMA_PREBUILT := $(LLAMA_DIR)/prebuilt/$(PLATFORM)
# Paths — assets live inside the Go package directories
LLAMA_THIRD_PARTY := ggml/llamacpp/third_party
LLAMA_SRC := $(LLAMA_THIRD_PARTY)/src
LLAMA_PREBUILT := $(LLAMA_THIRD_PARTY)/prebuilt/$(PLATFORM)

.PHONY: build-libs build-libs-llama build-libs-linux build-libs-all clean verify
WHISPER_THIRD_PARTY := ggml/whispercpp/third_party
WHISPER_SRC := $(WHISPER_THIRD_PARTY)/src
WHISPER_PREBUILT := $(WHISPER_THIRD_PARTY)/prebuilt/$(PLATFORM)

build-libs: build-libs-llama
.PHONY: build-libs build-libs-llama build-libs-whisper build-libs-linux build-libs-all clean verify

build-libs: build-libs-llama build-libs-whisper

# Build both native platform and linux-amd64 (via Docker)
build-libs-all: build-libs build-libs-linux
Expand All @@ -46,13 +51,13 @@ $(LLAMA_PREBUILT): $(LLAMA_SRC)
@mkdir -p $(LLAMA_PREBUILT)
find $(LLAMA_SRC)/build -name "*.a" -exec cp {} $(LLAMA_PREBUILT)/ \;
@echo "==> Copying llama.cpp headers..."
@mkdir -p $(LLAMA_DIR)/include
cp $(LLAMA_SRC)/include/*.h $(LLAMA_DIR)/include/
@mkdir -p $(LLAMA_DIR)/ggml/include
cp $(LLAMA_SRC)/ggml/include/*.h $(LLAMA_DIR)/ggml/include/
@mkdir -p $(LLAMA_DIR)/common
cp $(LLAMA_SRC)/common/common.h $(LLAMA_DIR)/common/
cp $(LLAMA_SRC)/common/sampling.h $(LLAMA_DIR)/common/
@mkdir -p $(LLAMA_THIRD_PARTY)/include
cp $(LLAMA_SRC)/include/*.h $(LLAMA_THIRD_PARTY)/include/
@mkdir -p $(LLAMA_THIRD_PARTY)/ggml/include
cp $(LLAMA_SRC)/ggml/include/*.h $(LLAMA_THIRD_PARTY)/ggml/include/
@mkdir -p $(LLAMA_THIRD_PARTY)/common
cp $(LLAMA_SRC)/common/common.h $(LLAMA_THIRD_PARTY)/common/
cp $(LLAMA_SRC)/common/sampling.h $(LLAMA_THIRD_PARTY)/common/
@echo "==> llama.cpp $(LLAMA_VERSION) ready: $(LLAMA_PREBUILT)/"

$(LLAMA_SRC):
Expand All @@ -62,37 +67,71 @@ $(LLAMA_SRC):
tar xzf llama.cpp.tar.gz --strip-components=1 -C $(LLAMA_SRC)
rm llama.cpp.tar.gz

# ============================================================================
# whisper.cpp
# ============================================================================
build-libs-whisper: $(WHISPER_PREBUILT)

$(WHISPER_PREBUILT): $(WHISPER_SRC)
@echo "==> Building whisper.cpp $(WHISPER_VERSION) for $(PLATFORM)..."
cd $(WHISPER_SRC) && cmake -B build -DBUILD_SHARED_LIBS=OFF && \
cmake --build build --config Release -j$(NPROC)
@mkdir -p $(WHISPER_PREBUILT)
find $(WHISPER_SRC)/build -name "*.a" -exec cp {} $(WHISPER_PREBUILT)/ \;
@echo "==> Copying whisper.cpp headers..."
@mkdir -p $(WHISPER_THIRD_PARTY)/include
cp $(WHISPER_SRC)/include/*.h $(WHISPER_THIRD_PARTY)/include/
@mkdir -p $(WHISPER_THIRD_PARTY)/ggml/include
cp $(WHISPER_SRC)/ggml/include/*.h $(WHISPER_THIRD_PARTY)/ggml/include/
@echo "==> whisper.cpp $(WHISPER_VERSION) ready: $(WHISPER_PREBUILT)/"

$(WHISPER_SRC):
@echo "==> Downloading whisper.cpp $(WHISPER_VERSION)..."
wget -qO whisper.cpp.tar.gz https://github.com/ggerganov/whisper.cpp/archive/refs/tags/$(WHISPER_VERSION).tar.gz
mkdir -p $(WHISPER_SRC)
tar xzf whisper.cpp.tar.gz --strip-components=1 -C $(WHISPER_SRC)
rm whisper.cpp.tar.gz

# ============================================================================
# Docker build for linux-amd64 (cross-compile from macOS)
# ============================================================================
build-libs-linux:
@echo "==> Building linux-amd64 static libraries via Docker..."
docker build -f Dockerfile.libs -o ./out .
@mkdir -p $(LLAMA_DIR)/prebuilt/linux-amd64
cp out/llama.cpp/linux-amd64/*.a $(LLAMA_DIR)/prebuilt/linux-amd64/
@# Copy headers if not already present
@mkdir -p $(LLAMA_DIR)/include $(LLAMA_DIR)/ggml/include $(LLAMA_DIR)/common
cp out/llama.cpp/include/*.h $(LLAMA_DIR)/include/
cp out/llama.cpp/ggml/include/*.h $(LLAMA_DIR)/ggml/include/
cp out/llama.cpp/common/common.h $(LLAMA_DIR)/common/
cp out/llama.cpp/common/sampling.h $(LLAMA_DIR)/common/
@# llama.cpp
@mkdir -p $(LLAMA_THIRD_PARTY)/prebuilt/linux-amd64
cp out/llama.cpp/linux-amd64/*.a $(LLAMA_THIRD_PARTY)/prebuilt/linux-amd64/
@mkdir -p $(LLAMA_THIRD_PARTY)/include $(LLAMA_THIRD_PARTY)/ggml/include $(LLAMA_THIRD_PARTY)/common
cp out/llama.cpp/include/*.h $(LLAMA_THIRD_PARTY)/include/
cp out/llama.cpp/ggml/include/*.h $(LLAMA_THIRD_PARTY)/ggml/include/
cp out/llama.cpp/common/common.h $(LLAMA_THIRD_PARTY)/common/
cp out/llama.cpp/common/sampling.h $(LLAMA_THIRD_PARTY)/common/
@# whisper.cpp
@mkdir -p $(WHISPER_THIRD_PARTY)/prebuilt/linux-amd64
cp out/whisper.cpp/linux-amd64/*.a $(WHISPER_THIRD_PARTY)/prebuilt/linux-amd64/
@mkdir -p $(WHISPER_THIRD_PARTY)/include $(WHISPER_THIRD_PARTY)/ggml/include
cp out/whisper.cpp/include/*.h $(WHISPER_THIRD_PARTY)/include/
cp out/whisper.cpp/ggml/include/*.h $(WHISPER_THIRD_PARTY)/ggml/include/
rm -rf out
@echo "==> linux-amd64 libraries ready"

# ============================================================================
# Verification
# ============================================================================
verify:
@echo "==> Verifying stub build (no tag)..."
@echo "==> Verifying stub builds (no tags)..."
go build ./ggml/llamacpp/...
@echo "==> Verifying CGO build (with tag)..."
go build ./ggml/whispercpp/...
@echo "==> Verifying CGO builds (with tags)..."
CGO_ENABLED=1 go build -tags llamacpp ./ggml/llamacpp/...
CGO_ENABLED=1 go build -tags whispercpp ./ggml/whispercpp/...
@echo "==> Running stub tests..."
go test ./ggml/llamacpp/...
go test ./ggml/whispercpp/...
@echo "==> All checks passed"

# ============================================================================
# Cleanup
# ============================================================================
clean:
rm -rf $(LLAMA_SRC) out
rm -rf $(LLAMA_SRC) $(WHISPER_SRC) out
Loading
Loading