Skip to content

Commit e57ffe2

Browse files
committed
Update GitHub Actions workflow and Makefile to support Linux MUSL builds, Apple XCFramework builds and sign and notarization process for Apple builds.
1 parent 50264f9 commit e57ffe2

File tree

2 files changed

+161
-44
lines changed

2 files changed

+161
-44
lines changed

.github/workflows/main.yml

Lines changed: 82 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -9,58 +9,113 @@ permissions:
99
jobs:
1010
build:
1111
runs-on: ${{ matrix.os }}
12-
name: ${{ matrix.name }}${{ matrix.arch && format('-{0}', matrix.arch) || '' }} build${{ matrix.arch != 'arm64-v8a' && matrix.name != 'isim' && matrix.name != 'ios' && ' + test' || ''}}
12+
container: ${{ matrix.container && matrix.container || '' }}
13+
name: ${{ matrix.name }}${{ matrix.arch && format('-{0}', matrix.arch) || '' }} build${{ matrix.arch != 'arm64-v8a' && matrix.name != 'ios-sim' && matrix.name != 'ios' && matrix.name != 'apple-xcframework' && ' + test' || ''}}
1314
timeout-minutes: 20
1415
strategy:
1516
fail-fast: false
1617
matrix:
1718
include:
18-
- os: ubuntu-latest
19+
- os: ubuntu-22.04
1920
arch: x86_64
2021
name: linux
21-
- os: LinuxARM64
22+
- os: ubuntu-22.04-arm
2223
arch: arm64
2324
name: linux
24-
- os: macos-latest
25+
- os: ubuntu-22.04
26+
arch: x86_64
27+
name: linux-musl
28+
container: alpine:latest
29+
- os: ubuntu-22.04-arm
30+
arch: arm64
31+
name: linux-musl
32+
- os: macos-15
2533
name: macos
26-
- os: windows-latest
34+
- os: windows-2022
2735
arch: x86_64
2836
name: windows
29-
- os: ubuntu-latest
37+
- os: ubuntu-22.04
3038
arch: arm64-v8a
3139
name: android
3240
make: PLATFORM=android ARCH=arm64-v8a
33-
- os: ubuntu-latest
41+
- os: ubuntu-22.04
3442
arch: x86_64
3543
name: android
3644
make: PLATFORM=android ARCH=x86_64
3745
sqlite-amalgamation-zip: https://sqlite.org/2025/sqlite-amalgamation-3490100.zip
38-
- os: macos-latest
46+
- os: macos-15
3947
name: ios
4048
make: PLATFORM=ios
41-
- os: macos-latest
42-
name: isim
43-
make: PLATFORM=isim
49+
- os: macos-15
50+
name: ios-sim
51+
make: PLATFORM=ios-sim
52+
- os: macos-15
53+
name: apple-xcframework
54+
make: xcframework
4455

4556
defaults:
4657
run:
47-
shell: bash
58+
shell: ${{ matrix.container && 'sh' || 'bash' }}
4859

4960
steps:
5061

5162
- uses: actions/[email protected]
5263

53-
- name: build sqlite-vector
54-
run: make extension ${{ matrix.make && matrix.make || ''}}
55-
56-
- name: windows install sqlite3
57-
if: matrix.os == 'windows-latest'
64+
- name: windows install dependencies
65+
if: matrix.name == 'windows'
5866
run: choco install sqlite -y
5967

60-
- name: macos install sqlite3 without SQLITE_OMIT_LOAD_EXTENSION
68+
- name: macos install dependencies
6169
if: matrix.name == 'macos'
6270
run: brew link sqlite --force
6371

72+
- name: linux-musl x86_64 install dependencies
73+
if: matrix.name == 'linux-musl' && matrix.arch == 'x86_64'
74+
run: apk update && apk add --no-cache gcc make sqlite musl-dev linux-headers
75+
76+
- name: linux-musl arm64 setup container
77+
if: matrix.name == 'linux-musl' && matrix.arch == 'arm64'
78+
run: |
79+
docker run -d --name alpine \
80+
--platform linux/arm64 \
81+
-v ${{ github.workspace }}:/workspace \
82+
-w /workspace \
83+
alpine:latest \
84+
tail -f /dev/null
85+
docker exec alpine sh -c "apk update && apk add --no-cache gcc make sqlite musl-dev linux-headers"
86+
87+
- name: build sqlite-vector
88+
run: ${{ matrix.name == 'linux-musl' && matrix.arch == 'arm64' && 'docker exec alpine' || '' }} make extension ${{ matrix.make && matrix.make || ''}}
89+
90+
- name: create keychain for codesign
91+
if: matrix.os == 'macos-15'
92+
run: |
93+
echo "${{ secrets.APPLE_CERTIFICATE }}" | base64 --decode > certificate.p12
94+
security create-keychain -p "${{ secrets.KEYCHAIN_PASSWORD }}" build.keychain
95+
security default-keychain -s build.keychain
96+
security unlock-keychain -p "${{ secrets.KEYCHAIN_PASSWORD }}" build.keychain
97+
security import certificate.p12 -k build.keychain -P "${{ secrets.CERTIFICATE_PASSWORD }}" -T /usr/bin/codesign
98+
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "${{ secrets.KEYCHAIN_PASSWORD }}" build.keychain
99+
100+
- name: codesign dylib
101+
if: matrix.os == 'macos-15' && matrix.name != 'apple-xcframework'
102+
run: codesign --sign "${{ secrets.APPLE_TEAM_ID }}" --timestamp --options runtime dist/vector.dylib
103+
104+
- name: codesign and notarize xcframework
105+
if: matrix.name == 'apple-xcframework'
106+
run: |
107+
find dist/vector.xcframework -name "*.framework" -exec echo "Signing: {}" \; -exec codesign --sign "${{ secrets.APPLE_TEAM_ID }}" --timestamp --options runtime {} \; # Sign each individual framework FIRST
108+
codesign --sign "${{ secrets.APPLE_TEAM_ID }}" --timestamp --options runtime dist/vector.xcframework # Then sign the xcframework wrapper
109+
ditto -c -k --keepParent dist/vector.xcframework dist/vector.xcframework.zip
110+
xcrun notarytool submit dist/vector.xcframework.zip --apple-id "${{ secrets.APPLE_ID }}" --password "${{ secrets.APPLE_PASSWORD }}" --team-id "${{ secrets.APPLE_TEAM_ID }}" --wait
111+
rm dist/vector.xcframework.zip
112+
113+
- name: cleanup keychain for codesign
114+
if: matrix.os == 'macos-15'
115+
run: |
116+
rm certificate.p12
117+
security delete-keychain build.keychain
118+
64119
- name: android setup test environment
65120
if: matrix.name == 'android' && matrix.arch != 'arm64-v8a'
66121
run: |
@@ -77,7 +132,7 @@ jobs:
77132
export ${{ matrix.make }}
78133
$ANDROID_NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/${{ matrix.arch }}-linux-android26-clang sqlite-amalgamation-*/shell.c sqlite-amalgamation-*/sqlite3.c -o sqlite3 -ldl
79134
# remove unused folders to save up space
80-
rm -rf sqlite-amalgamation-*.zip sqlite-amalgamation-* openssl
135+
rm -rf sqlite-amalgamation-*.zip sqlite-amalgamation-*
81136
echo "::endgroup::"
82137
83138
echo "::group::prepare the test script"
@@ -102,8 +157,8 @@ jobs:
102157
adb shell "sh /data/local/tmp/commands.sh"
103158
104159
- name: test sqlite-vector
105-
if: matrix.name == 'linux' || matrix.name == 'windows' || matrix.name == 'macos'
106-
run: make test
160+
if: contains(matrix.name, 'linux') || matrix.name == 'windows' || matrix.name == 'macos'
161+
run: ${{ matrix.name == 'linux-musl' && matrix.arch == 'arm64' && 'docker exec alpine' || '' }} make test ${{ matrix.make && matrix.make || ''}}
107162

108163
- uses: actions/[email protected]
109164
if: always()
@@ -113,7 +168,7 @@ jobs:
113168
if-no-files-found: error
114169

115170
release:
116-
runs-on: ubuntu-latest
171+
runs-on: ubuntu-22.04
117172
name: release
118173
needs: build
119174
if: github.ref == 'refs/heads/main'
@@ -132,8 +187,7 @@ jobs:
132187
- name: release tag version from sqlite-vector.h
133188
id: tag
134189
run: |
135-
FILE="src/sqlite-vector.h"
136-
VERSION=$(grep -oP '#define SQLITE_VECTOR_VERSION\s+"\K[^"]+' "$FILE")
190+
VERSION=$(make version)
137191
if [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
138192
LATEST=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" https://api.github.com/repos/${{ github.repository }}/releases/latest | jq -r '.name')
139193
if [[ "$VERSION" != "$LATEST" || "$GITHUB_EVENT_NAME" == "workflow_dispatch" ]]; then
@@ -151,9 +205,10 @@ jobs:
151205
for folder in "artifacts"/*; do
152206
if [ -d "$folder" ]; then
153207
name=$(basename "$folder")
154-
zip -jq "${name}-${{ steps.tag.outputs.version }}.zip" "$folder"/*
155-
tar -cJf "${name}-${{ steps.tag.outputs.version }}.tar.xz" -C "$folder" .
156-
tar -czf "${name}-${{ steps.tag.outputs.version }}.tar.gz" -C "$folder" .
208+
if [[ "$name" != "vector-apple-xcframework" ]]; then
209+
tar -czf "${name}-${{ steps.tag.outputs.version }}.tar.gz" -C "$folder" .
210+
fi
211+
(cd "$folder" && zip -rq "../../${name}-${{ steps.tag.outputs.version }}.zip" .)
157212
fi
158213
done
159214
@@ -164,6 +219,5 @@ jobs:
164219
tag_name: ${{ steps.tag.outputs.version }}
165220
files: |
166221
vector-*-${{ steps.tag.outputs.version }}.zip
167-
vector-*-${{ steps.tag.outputs.version }}.tar.xz
168222
vector-*-${{ steps.tag.outputs.version }}.tar.gz
169223
make_latest: true

Makefile

Lines changed: 79 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -45,44 +45,43 @@ ifeq ($(PLATFORM),windows)
4545
LDFLAGS += -shared
4646
# Create .def file for Windows
4747
DEF_FILE := $(BUILD_DIR)/vector.def
48+
STRIP = strip --strip-unneeded $@
4849
else ifeq ($(PLATFORM),macos)
4950
TARGET := $(DIST_DIR)/vector.dylib
5051
LDFLAGS += -arch x86_64 -arch arm64 -dynamiclib -undefined dynamic_lookup
5152
CFLAGS += -arch x86_64 -arch arm64
53+
STRIP = strip -x -S $@
5254
else ifeq ($(PLATFORM),android)
53-
# Set ARCH to find Android NDK's Clang compiler, the user should set the ARCH
54-
ifeq ($(filter %,$(ARCH)),)
55+
ifndef ARCH # Set ARCH to find Android NDK's Clang compiler, the user should set the ARCH
5556
$(error "Android ARCH must be set to ARCH=x86_64 or ARCH=arm64-v8a")
5657
endif
57-
# Set ANDROID_NDK path to find android build tools
58-
# e.g. on MacOS: export ANDROID_NDK=/Users/username/Library/Android/sdk/ndk/25.2.9519653
59-
ifeq ($(filter %,$(ANDROID_NDK)),)
58+
ifndef ANDROID_NDK # Set ANDROID_NDK path to find android build tools; e.g. on MacOS: export ANDROID_NDK=/Users/username/Library/Android/sdk/ndk/25.2.9519653
6059
$(error "Android NDK must be set")
6160
endif
62-
6361
BIN = $(ANDROID_NDK)/toolchains/llvm/prebuilt/$(HOST)-x86_64/bin
64-
PATH := $(BIN):$(PATH)
65-
6662
ifneq (,$(filter $(ARCH),arm64 arm64-v8a))
6763
override ARCH := aarch64
6864
endif
69-
7065
CC = $(BIN)/$(ARCH)-linux-android26-clang
7166
TARGET := $(DIST_DIR)/vector.so
7267
LDFLAGS += -lm -shared
68+
STRIP = $(BIN)/llvm-strip --strip-unneeded $@
7369
else ifeq ($(PLATFORM),ios)
7470
TARGET := $(DIST_DIR)/vector.dylib
7571
SDK := -isysroot $(shell xcrun --sdk iphoneos --show-sdk-path) -miphoneos-version-min=11.0
7672
LDFLAGS += -dynamiclib $(SDK)
7773
CFLAGS += -arch arm64 $(SDK)
78-
else ifeq ($(PLATFORM),isim)
74+
STRIP = strip -x -S $@
75+
else ifeq ($(PLATFORM),ios-sim)
7976
TARGET := $(DIST_DIR)/vector.dylib
8077
SDK := -isysroot $(shell xcrun --sdk iphonesimulator --show-sdk-path) -miphonesimulator-version-min=11.0
8178
LDFLAGS += -arch x86_64 -arch arm64 -dynamiclib $(SDK)
8279
CFLAGS += -arch x86_64 -arch arm64 $(SDK)
80+
STRIP = strip -x -S $@
8381
else # linux
8482
TARGET := $(DIST_DIR)/vector.so
8583
LDFLAGS += -shared
84+
STRIP = strip --strip-unneeded $@
8685
endif
8786

8887
# Windows .def file generation
@@ -107,6 +106,8 @@ ifeq ($(PLATFORM),windows)
107106
# Generate import library for Windows
108107
dlltool -D $@ -d $(DEF_FILE) -l $(DIST_DIR)/vector.lib
109108
endif
109+
# Strip debug symbols
110+
$(STRIP)
110111

111112
# Object files
112113
$(BUILD_DIR)/%.o: %.c
@@ -119,6 +120,67 @@ test: $(TARGET)
119120
clean:
120121
rm -rf $(BUILD_DIR)/* $(DIST_DIR)/* *.gcda *.gcno *.gcov *.sqlite
121122

123+
.NOTPARALLEL: %.dylib
124+
%.dylib:
125+
rm -rf $(BUILD_DIR) && $(MAKE) PLATFORM=$*
126+
mv $(DIST_DIR)/vector.dylib $(DIST_DIR)/$@
127+
128+
define PLIST
129+
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\
130+
<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\
131+
<plist version=\"1.0\">\
132+
<dict>\
133+
<key>CFBundleDevelopmentRegion</key>\
134+
<string>en</string>\
135+
<key>CFBundleExecutable</key>\
136+
<string>vector</string>\
137+
<key>CFBundleIdentifier</key>\
138+
<string>ai.sqlite.vector</string>\
139+
<key>CFBundleInfoDictionaryVersion</key>\
140+
<string>6.0</string>\
141+
<key>CFBundlePackageType</key>\
142+
<string>FMWK</string>\
143+
<key>CFBundleSignature</key>\
144+
<string>????</string>\
145+
<key>CFBundleVersion</key>\
146+
<string>$(shell make version)</string>\
147+
<key>CFBundleShortVersionString</key>\
148+
<string>$(shell make version)</string>\
149+
<key>MinimumOSVersion</key>\
150+
<string>11.0</string>\
151+
</dict>\
152+
</plist>
153+
endef
154+
155+
define MODULEMAP
156+
framework module vector {\
157+
umbrella header \"sqlite-vector.h\"\
158+
export *\
159+
}
160+
endef
161+
162+
LIB_NAMES = ios.dylib ios-sim.dylib macos.dylib
163+
FMWK_NAMES = ios-arm64 ios-arm64_x86_64-simulator macos-arm64_x86_64
164+
$(DIST_DIR)/%.xcframework: $(LIB_NAMES)
165+
@$(foreach i,1 2 3,\
166+
lib=$(word $(i),$(LIB_NAMES)); \
167+
fmwk=$(word $(i),$(FMWK_NAMES)); \
168+
mkdir -p $(DIST_DIR)/$$fmwk/vector.framework/Headers; \
169+
mkdir -p $(DIST_DIR)/$$fmwk/vector.framework/Modules; \
170+
cp src/sqlite-vector.h $(DIST_DIR)/$$fmwk/vector.framework/Headers; \
171+
printf "$(PLIST)" > $(DIST_DIR)/$$fmwk/vector.framework/Info.plist; \
172+
printf "$(MODULEMAP)" > $(DIST_DIR)/$$fmwk/vector.framework/Modules/module.modulemap; \
173+
mv $(DIST_DIR)/$$lib $(DIST_DIR)/$$fmwk/vector.framework/vector; \
174+
install_name_tool -id "@rpath/vector.framework/vector" $(DIST_DIR)/$$fmwk/vector.framework/vector; \
175+
)
176+
xcodebuild -create-xcframework $(foreach fmwk,$(FMWK_NAMES),-framework $(DIST_DIR)/$(fmwk)/vector.framework) -output $@
177+
rm -rf $(foreach fmwk,$(FMWK_NAMES),$(DIST_DIR)/$(fmwk))
178+
179+
xcframework: $(DIST_DIR)/vector.xcframework
180+
181+
version:
182+
@echo $(shell sed -n 's/^#define SQLITE_VECTOR_VERSION[[:space:]]*"\([^"]*\)".*/\1/p' src/sqlite-vector.h)
183+
122184
# Help message
123185
help:
124186
@echo "SQLite Vector Extension Makefile"
@@ -131,12 +193,13 @@ help:
131193
@echo " windows (default on Windows)"
132194
@echo " android (needs ARCH to be set to x86_64 or arm64-v8a and ANDROID_NDK to be set)"
133195
@echo " ios (only on macOS)"
134-
@echo " isim (only on macOS)"
196+
@echo " ios-sim (only on macOS)"
135197
@echo ""
136198
@echo "Targets:"
137-
@echo " all - Build the extension (default)"
138-
@echo " clean - Remove built files"
139-
@echo " test - Test the extension"
140-
@echo " help - Display this help message"
199+
@echo " all - Build the extension (default)"
200+
@echo " clean - Remove built files"
201+
@echo " test - Test the extension"
202+
@echo " help - Display this help message"
203+
@echo " xcframework - Build the Apple XCFramework"
141204

142-
.PHONY: all clean test extension help
205+
.PHONY: all clean test extension help version xcframework

0 commit comments

Comments
 (0)