Skip to content

Commit b02f016

Browse files
committed
Add Swift Package Manager support and fix Makefile build directory path
1 parent bf0bf46 commit b02f016

File tree

6 files changed

+152
-16
lines changed

6 files changed

+152
-16
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@
88
/dist
99
*.sqlite
1010
*.a
11-
.vscode
11+
.vscode
12+
.build

Makefile

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ endif
197197
$(STRIP)
198198

199199
# Object files
200-
$(BUILD_DIR)/%.o: %.c build/llama.cpp.stamp
200+
$(BUILD_DIR)/%.o: %.c $(BUILD_DIR)/llama.cpp.stamp
201201
$(CC) $(CFLAGS) -O3 -fPIC -c $< -o $@
202202

203203
test: $(TARGET)
@@ -209,25 +209,25 @@ ifeq ($(PLATFORM),windows)
209209
else
210210
ARGS = -- -j$(CPUS)
211211
endif
212-
build/llama.cpp.stamp:
212+
$(BUILD_DIR)/llama.cpp.stamp:
213213
cmake -B $(BUILD_LLAMA) $(LLAMA_OPTIONS) $(LLAMA_DIR)
214214
cmake --build $(BUILD_LLAMA) --config Release $(LLAMA_ARGS) $(ARGS)
215215
cmake --install $(BUILD_LLAMA) --prefix $(BUILD_GGML)
216216
touch $@
217217

218-
build/whisper.cpp.stamp: build/llama.cpp.stamp
218+
$(BUILD_DIR)/whisper.cpp.stamp: $(BUILD_DIR)/llama.cpp.stamp
219219
cmake -Dggml_DIR=$(shell pwd)/$(BUILD_GGML)/lib/cmake/ggml -B $(BUILD_WHISPER) $(WHISPER_OPTIONS) $(WHISPER_DIR)
220220
cmake --build $(BUILD_WHISPER) --config Release $(WHISPER_ARGS) $(ARGS)
221221
touch $@
222222

223-
build/miniaudio.stamp:
223+
$(BUILD_DIR)/miniaudio.stamp:
224224
cmake -B $(BUILD_MINIAUDIO) $(MINIAUDIO_OPTIONS) $(MINIAUDIO_DIR)
225225
cmake --build $(BUILD_MINIAUDIO) --config Release $(MINIAUDIO_ARGS) $(ARGS)
226226
touch $@
227227

228-
$(LLAMA_LIBS): build/llama.cpp.stamp
229-
$(WHISPER_LIBS): build/whisper.cpp.stamp
230-
$(MINIAUDIO_LIBS): build/miniaudio.stamp
228+
$(LLAMA_LIBS): $(BUILD_DIR)/llama.cpp.stamp
229+
$(WHISPER_LIBS): $(BUILD_DIR)/whisper.cpp.stamp
230+
$(MINIAUDIO_LIBS): $(BUILD_DIR)/miniaudio.stamp
231231

232232
# Tools
233233
version:

Package.swift

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// swift-tools-version: 6.1
2+
// The swift-tools-version declares the minimum version of Swift required to build this package.
3+
4+
import PackageDescription
5+
6+
let package = Package(
7+
name: "ai",
8+
platforms: [.macOS(.v11), .iOS(.v11)],
9+
products: [
10+
// Products can be used to vend plugins, making them visible to other packages.
11+
.plugin(
12+
name: "aiPlugin",
13+
targets: ["aiPlugin"]),
14+
.library(
15+
name: "ai",
16+
targets: ["ai"])
17+
],
18+
targets: [
19+
// Build tool plugin that invokes the Makefile
20+
.plugin(
21+
name: "aiPlugin",
22+
capability: .buildTool(),
23+
path: "packages/swift/plugin"
24+
),
25+
// ai library target
26+
.target(
27+
name: "ai",
28+
dependencies: [],
29+
path: "packages/swift/extension",
30+
plugins: ["aiPlugin"]
31+
),
32+
]
33+
)

README.md

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,27 @@ Download the appropriate pre-built binary for your platform from the official [R
3030
- Android
3131
- iOS
3232

33-
### Loading the Extension
34-
35-
```sql
36-
-- In SQLite CLI
37-
.load ./ai
38-
39-
-- In SQL
40-
SELECT load_extension('./ai');
33+
### Swift Package
34+
35+
You can [add this repository as a package dependency to your Swift project](https://developer.apple.com/documentation/xcode/adding-package-dependencies-to-your-app#Add-a-package-dependency). After adding the package, you'll need to set up SQLite with extension loading by following steps 4 and 5 of [this guide](https://github.com/sqliteai/sqlite-extensions-guide/blob/main/platforms/ios.md#4-set-up-sqlite-with-extension-loading).
36+
37+
Here's an example of how to use the package:
38+
```swift
39+
import ai
40+
41+
...
42+
43+
var db: OpaquePointer?
44+
sqlite3_open(":memory:", &db)
45+
sqlite3_enable_load_extension(db, 1)
46+
var errMsg: UnsafeMutablePointer<Int8>? = nil
47+
sqlite3_load_extension(db, ai.path, nil, &errMsg)
48+
var stmt: OpaquePointer?
49+
sqlite3_prepare_v2(db, "SELECT ai_version()", -1, &stmt, nil)
50+
defer { sqlite3_finalize(stmt) }
51+
sqlite3_step(stmt)
52+
log("ai_version(): \(String(cString: sqlite3_column_text(stmt, 0)))")
53+
sqlite3_close(db)
4154
```
4255

4356
### Python Package
@@ -50,6 +63,15 @@ pip install sqlite-ai
5063

5164
For usage details and examples, see the [Python package documentation](./packages/python/README.md).
5265

66+
### Loading the Extension
67+
68+
```sql
69+
-- In SQLite CLI
70+
.load ./ai
71+
72+
-- In SQL
73+
SELECT load_extension('./ai');
74+
```
5375

5476
## Getting Started
5577

packages/swift/extension/ai.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// ai.swift
2+
// This file serves as a placeholder for the ai target.
3+
// The actual SQLite extension is built using the Makefile through the build plugin.
4+
5+
import Foundation
6+
7+
/// Placeholder structure for ai
8+
public struct ai {
9+
/// Returns the path to the built ai dylib inside the XCFramework
10+
public static var path: String {
11+
#if os(macOS)
12+
return "ai.xcframework/macos-arm64_x86_64/ai.framework/ai"
13+
#elseif targetEnvironment(simulator)
14+
return "ai.xcframework/ios-arm64_x86_64-simulator/ai.framework/ai"
15+
#else
16+
return "ai.xcframework/ios-arm64/ai.framework/ai"
17+
#endif
18+
}
19+
}

packages/swift/plugin/ai.swift

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import PackagePlugin
2+
import Foundation
3+
4+
@main
5+
struct ai: BuildToolPlugin {
6+
/// Entry point for creating build commands for targets in Swift packages.
7+
func createBuildCommands(context: PluginContext, target: Target) async throws -> [Command] {
8+
let packageDirectory = context.package.directoryURL
9+
let outputDirectory = context.pluginWorkDirectoryURL
10+
return createaiBuildCommands(packageDirectory: packageDirectory, outputDirectory: outputDirectory)
11+
}
12+
}
13+
14+
#if canImport(XcodeProjectPlugin)
15+
import XcodeProjectPlugin
16+
17+
extension ai: XcodeBuildToolPlugin {
18+
// Entry point for creating build commands for targets in Xcode projects.
19+
func createBuildCommands(context: XcodePluginContext, target: XcodeTarget) throws -> [Command] {
20+
let outputDirectory = context.pluginWorkDirectoryURL
21+
return createaiBuildCommands(packageDirectory: nil, outputDirectory: outputDirectory)
22+
}
23+
}
24+
25+
#endif
26+
27+
/// Shared function to create ai build commands
28+
func createaiBuildCommands(packageDirectory: URL?, outputDirectory: URL) -> [Command] {
29+
30+
// For Xcode projects, use current directory; for Swift packages, use provided packageDirectory
31+
let workingDirectory = packageDirectory?.path ?? "$(pwd)"
32+
let packageDirInfo = packageDirectory != nil ? "Package directory: \(packageDirectory!.path)" : "Working directory: $(pwd)"
33+
34+
return [
35+
.prebuildCommand(
36+
displayName: "Building ai XCFramework",
37+
executable: URL(fileURLWithPath: "/bin/bash"),
38+
arguments: [
39+
"-c",
40+
"""
41+
set -e
42+
echo "Starting ai XCFramework prebuild..."
43+
echo "\(packageDirInfo)"
44+
45+
# Clean and create output directory
46+
rm -rf "\(outputDirectory.path)"
47+
mkdir -p "\(outputDirectory.path)"
48+
49+
# Copy source to writable location first due to sandbox restrictions
50+
cp -R "\(workingDirectory)" "\(outputDirectory.path)/src" && \
51+
cd "\(outputDirectory.path)/src" && \
52+
echo "Building XCFramework..." && \
53+
PATH="/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin:/opt/local/bin:/usr/sbin:/sbin:$PATH" make xcframework DIST_DIR="\(outputDirectory.path)" LLAMA="-DGGML_NATIVE=OFF -DGGML_METAL=ON -DGGML_ACCELERATE=ON -DGGML_BLAS=ON -DGGML_BLAS_VENDOR=Apple" WHISPER="-DWHISPER_COREML=ON -DWHISPER_COREML_ALLOW_FALLBACK=ON" && \
54+
rm -rf "\(outputDirectory.path)/src" && \
55+
echo "XCFramework build completed successfully!"
56+
"""
57+
],
58+
outputFilesDirectory: outputDirectory
59+
)
60+
]
61+
}

0 commit comments

Comments
 (0)