Skip to content

feat: add watchOS support (tentative) #73

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Jun 13, 2025
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
16 changes: 15 additions & 1 deletion .cargo/config.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

# Previously we added this to rustflags for all linux builds:
# "-C", "link-arg=-lgcc_eh"
# It was to fix this error when loading the loadable extension:
Expand Down Expand Up @@ -86,3 +85,18 @@ rustflags = [
rustflags = [
"-C", "link-arg=-Wl,-soname,libpowersync.so",
]

[target.aarch64-apple-watchos]
rustflags = [
"-C", "link-arg=-mwatchos-version-min=9.0",
]

[target.aarch64-apple-watchos-sim]
rustflags = [
"-C", "link-arg=-mwatchsimulator-version-min=9.0",
]

[target.x86_64-apple-watchos-sim]
rustflags = [
"-C", "link-arg=-mwatchos-version-min=9.0",
]
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ target/
*.tar.gz
*.tar.xz
*.zip
.build
8 changes: 8 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,4 @@ repository = "https://github.com/powersync-ja/powersync-sqlite-core"

[workspace.dependencies]
sqlite_nostd = { path="./sqlite-rs-embedded/sqlite_nostd" }

26 changes: 26 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// swift-tools-version: 5.7

// NOTE! This is never released, we're only using this to support local builds builds for the
// Swift SDK.
import PackageDescription
let packageName = "PowerSyncSQLiteCore"

let package = Package(
name: packageName,
platforms: [
.iOS(.v13),
.macOS(.v10_15),
.watchOS(.v9)
],
products: [
.library(
name: packageName,
targets: [packageName]),
],
targets: [
.binaryTarget(
name: packageName,
path: "powersync-sqlite-core.xcframework"
)
]
)
24 changes: 24 additions & 0 deletions crates/static/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[package]
name = "powersync_static"
edition.workspace = true
version.workspace = true
homepage.workspace = true
repository.workspace = true
license.workspace = true
authors.workspace = true
keywords.workspace = true

[lib]
name = "powersync"
crate-type = ["staticlib"]

[dependencies]
sqlite_nostd = { workspace=true }

[dependencies.powersync_core]
path = "../core"
default-features = false
features = []

[features]
default = ["powersync_core/static", "powersync_core/omit_load_extension", "sqlite_nostd/omit_load_extension"]
1 change: 1 addition & 0 deletions crates/static/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Builds the core extension as a static library, exposing the `powersync_init_static` function to load it.
31 changes: 31 additions & 0 deletions crates/static/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#![no_std]
#![feature(vec_into_raw_parts)]
#![feature(core_intrinsics)]
#![allow(internal_features)]
#![feature(lang_items)]

extern crate alloc;

// Defines sqlite3_powersync_init
#[allow(unused_imports)]
use powersync_core;

// Use the SQLite allocator, allowing us to freely transfer memory between SQLite and Rust.
#[cfg(not(test))]
use sqlite_nostd::SQLite3Allocator;

#[cfg(not(test))]
#[global_allocator]
static ALLOCATOR: SQLite3Allocator = SQLite3Allocator {};

// Custom Panic handler for WASM and other no_std builds
#[cfg(not(test))]
#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! {
core::intrinsics::abort()
}

#[cfg(not(target_family = "wasm"))]
#[cfg(not(test))]
#[lang = "eh_personality"]
extern "C" fn eh_personality() {}
2 changes: 1 addition & 1 deletion powersync-sqlite-core.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ PowerSync extension for SQLite.
s.source = { :http => "https://github.com/powersync-ja/powersync-sqlite-core/releases/download/v#{s.version}/powersync-sqlite-core.xcframework.zip" }
s.vendored_frameworks = 'powersync-sqlite-core.xcframework'


s.ios.deployment_target = '11.0'
s.osx.deployment_target = '10.13'
s.watchos.deployment_target = '9.0'
end
110 changes: 89 additions & 21 deletions tool/build_xcframework.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,48 @@ set -e

# Adapted from https://github.com/vlcn-io/cr-sqlite/blob/main/core/all-ios-loadable.sh


BUILD_DIR=./build
DIST_PACKAGE_DIR=./dist
TARGETS=(
# iOS and simulator
aarch64-apple-ios
aarch64-apple-ios-sim
x86_64-apple-ios

function createXcframework() {
plist=$(cat << EOF
# macOS
aarch64-apple-darwin
x86_64-apple-darwin

# watchOS and simulator
aarch64-apple-watchos
aarch64-apple-watchos-sim
x86_64-apple-watchos-sim
arm64_32-apple-watchos
)
VERSION=0.4.0

function generatePlist() {
min_os_version=0
additional_keys=""
# We support versions 11.0 or later for iOS and macOS. For watchOS, we need 9.0 or later.
case $1 in
*"watchos"*)
additional_keys=$(cat <<EOF
<key>CFBundleSupportedPlatforms</key>
<array>
<string>WatchOS</string>
</array>
<key>UIDeviceFamily</key>
<array>
<integer>4</integer>
</array>
EOF
)
min_os_version="9.0";;
*)
min_os_version="11.0";;
esac

cat <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
Expand All @@ -26,34 +62,41 @@ function createXcframework() {
<key>CFBundleSignature</key>
<string>????</string>
<key>MinimumOSVersion</key>
<string>11.0</string>
<string>$min_os_version</string>
<key>CFBundleVersion</key>
<string>0.4.0</string>
<string>$VERSION</string>
<key>CFBundleShortVersionString</key>
<string>0.4.0</string>
<string>$VERSION</string>
$additional_keys
</dict>
</plist>
EOF
)
}

function createXcframework() {
ios_plist=$(generatePlist "ios")
macos_plist=$(generatePlist "macos")
watchos_plist=$(generatePlist "watchos")

echo "===================== create ios device framework ====================="
mkdir -p "${BUILD_DIR}/ios-arm64/powersync-sqlite-core.framework"
echo "${plist}" > "${BUILD_DIR}/ios-arm64/powersync-sqlite-core.framework/Info.plist"
echo "${ios_plist}" > "${BUILD_DIR}/ios-arm64/powersync-sqlite-core.framework/Info.plist"
cp -f "./target/aarch64-apple-ios/release_apple/libpowersync.dylib" "${BUILD_DIR}/ios-arm64/powersync-sqlite-core.framework/powersync-sqlite-core"
install_name_tool -id "@rpath/powersync-sqlite-core.framework/powersync-sqlite-core" "${BUILD_DIR}/ios-arm64/powersync-sqlite-core.framework/powersync-sqlite-core"
# Generate dSYM for iOS Device
dsymutil "${BUILD_DIR}/ios-arm64/powersync-sqlite-core.framework/powersync-sqlite-core" -o "${BUILD_DIR}/ios-arm64/powersync-sqlite-core.framework.dSYM"

echo "===================== create ios simulator framework ====================="
mkdir -p "${BUILD_DIR}/ios-arm64_x86_64-simulator/powersync-sqlite-core.framework"
echo "${plist}" > "${BUILD_DIR}/ios-arm64_x86_64-simulator/powersync-sqlite-core.framework/Info.plist"
echo "${ios_plist}" > "${BUILD_DIR}/ios-arm64_x86_64-simulator/powersync-sqlite-core.framework/Info.plist"
lipo ./target/aarch64-apple-ios-sim/release_apple/libpowersync.dylib ./target/x86_64-apple-ios/release_apple/libpowersync.dylib -create -output "${BUILD_DIR}/ios-arm64_x86_64-simulator/powersync-sqlite-core.framework/powersync-sqlite-core"
install_name_tool -id "@rpath/powersync-sqlite-core.framework/powersync-sqlite-core" "${BUILD_DIR}/ios-arm64_x86_64-simulator/powersync-sqlite-core.framework/powersync-sqlite-core"
# Generate dSYM for iOS Simulator
dsymutil "${BUILD_DIR}/ios-arm64_x86_64-simulator/powersync-sqlite-core.framework/powersync-sqlite-core" -o "${BUILD_DIR}/ios-arm64_x86_64-simulator/powersync-sqlite-core.framework.dSYM"

echo "===================== create macos framework ====================="
mkdir -p "${BUILD_DIR}/macos-arm64_x86_64/powersync-sqlite-core.framework/Versions/A/Resources"
echo "${plist}" > "${BUILD_DIR}/macos-arm64_x86_64/powersync-sqlite-core.framework/Versions/A/Resources/Info.plist"
echo "${ios_plist}" > "${BUILD_DIR}/macos-arm64_x86_64/powersync-sqlite-core.framework/Versions/A/Resources/Info.plist"
lipo ./target/x86_64-apple-darwin/release_apple/libpowersync.dylib ./target/aarch64-apple-darwin/release_apple/libpowersync.dylib -create -output "${BUILD_DIR}/macos-arm64_x86_64/powersync-sqlite-core.framework/Versions/A/powersync-sqlite-core"
install_name_tool -id "@rpath/powersync-sqlite-core.framework/powersync-sqlite-core" "${BUILD_DIR}/macos-arm64_x86_64/powersync-sqlite-core.framework/Versions/A/powersync-sqlite-core"
ln -sf A "${BUILD_DIR}/macos-arm64_x86_64/powersync-sqlite-core.framework/Versions/Current"
Expand All @@ -62,17 +105,37 @@ EOF
# Generate dSYM for macOS
dsymutil "${BUILD_DIR}/macos-arm64_x86_64/powersync-sqlite-core.framework/Versions/A/powersync-sqlite-core" -o "${BUILD_DIR}/macos-arm64_x86_64/powersync-sqlite-core.framework.dSYM"

echo "===================== create watchos device framework ====================="
mkdir -p "${BUILD_DIR}/watchos-arm64_arm64_32_armv7k/powersync-sqlite-core.framework/Versions/A/Resources"
echo "${watchos_plist}" > "${BUILD_DIR}/watchos-arm64_arm64_32_armv7k/powersync-sqlite-core.framework/Versions/A/Resources/Info.plist"
lipo ./target/aarch64-apple-watchos/release_apple/libpowersync.a ./target/arm64_32-apple-watchos/release_apple/libpowersync.a -create -output "${BUILD_DIR}/watchos-arm64_arm64_32_armv7k/powersync-sqlite-core.framework/Versions/A/powersync-sqlite-core"
# install_name_tool isn't necessary, we use a statically-linked library
ln -sf A "${BUILD_DIR}/watchos-arm64_arm64_32_armv7k/powersync-sqlite-core.framework/Versions/Current"
ln -sf Versions/Current/powersync-sqlite-core "${BUILD_DIR}/watchos-arm64_arm64_32_armv7k/powersync-sqlite-core.framework/powersync-sqlite-core"
ln -sf Versions/Current/Resources "${BUILD_DIR}/watchos-arm64_arm64_32_armv7k/powersync-sqlite-core.framework/Resources"

echo "===================== create watchos simulator framework ====================="
mkdir -p "${BUILD_DIR}/watchos-arm64_x86_64-simulator/powersync-sqlite-core.framework/Versions/A/Resources"
echo "${watchos_plist}" > "${BUILD_DIR}/watchos-arm64_x86_64-simulator/powersync-sqlite-core.framework/Versions/A/Resources/Info.plist"
lipo ./target/aarch64-apple-watchos-sim/release_apple/libpowersync.a ./target/x86_64-apple-watchos-sim/release_apple/libpowersync.a -create -output "${BUILD_DIR}/watchos-arm64_x86_64-simulator/powersync-sqlite-core.framework/Versions/A/powersync-sqlite-core"
# install_name_tool isn't necessary, we use a statically-linked library
ln -sf A "${BUILD_DIR}/watchos-arm64_x86_64-simulator/powersync-sqlite-core.framework/Versions/Current"
ln -sf Versions/Current/powersync-sqlite-core "${BUILD_DIR}/watchos-arm64_x86_64-simulator/powersync-sqlite-core.framework/powersync-sqlite-core"
ln -sf Versions/Current/Resources "${BUILD_DIR}/watchos-arm64_x86_64-simulator/powersync-sqlite-core.framework/Resources"

echo "===================== create xcframework ====================="
rm -rf "${BUILD_DIR}/powersync-sqlite-core.xcframework"
# "-debug-symbols" requires the absolute path

xcodebuild -create-xcframework \
-framework "${BUILD_DIR}/ios-arm64/powersync-sqlite-core.framework" \
-debug-symbols "$(pwd -P)/${BUILD_DIR}/ios-arm64/powersync-sqlite-core.framework.dSYM" \
-framework "${BUILD_DIR}/ios-arm64_x86_64-simulator/powersync-sqlite-core.framework" \
-debug-symbols "$(pwd -P)/${BUILD_DIR}/ios-arm64_x86_64-simulator/powersync-sqlite-core.framework.dSYM" \
-framework "${BUILD_DIR}/macos-arm64_x86_64/powersync-sqlite-core.framework" \
-debug-symbols "$(pwd -P)/${BUILD_DIR}/macos-arm64_x86_64/powersync-sqlite-core.framework.dSYM" \
-output "${BUILD_DIR}/powersync-sqlite-core.xcframework" \
-framework "${BUILD_DIR}/watchos-arm64_arm64_32_armv7k/powersync-sqlite-core.framework" \
-framework "${BUILD_DIR}/watchos-arm64_x86_64-simulator/powersync-sqlite-core.framework" \
-output "${BUILD_DIR}/powersync-sqlite-core.xcframework"

cp -Rf "${BUILD_DIR}/powersync-sqlite-core.xcframework" "powersync-sqlite-core.xcframework"
zip -r --symlinks powersync-sqlite-core.xcframework.zip powersync-sqlite-core.xcframework LICENSE README.md
Expand All @@ -84,13 +147,18 @@ EOF

rm -rf powersync-sqlite-core.xcframework

# iOS
cargo build -p powersync_loadable --profile release_apple --target aarch64-apple-ios -Zbuild-std
# Simulator
cargo build -p powersync_loadable --profile release_apple --target aarch64-apple-ios-sim -Zbuild-std
cargo build -p powersync_loadable --profile release_apple --target x86_64-apple-ios -Zbuild-std
# macOS
cargo build -p powersync_loadable --profile release_apple --target aarch64-apple-darwin -Zbuild-std
cargo build -p powersync_loadable --profile release_apple --target x86_64-apple-darwin -Zbuild-std
for TARGET in ${TARGETS[@]}; do
echo "Building PowerSync loadable extension for $TARGET"

if [[ $TARGET == *"watchos"* ]]; then
cargo build \
-p powersync_static \
--profile release_apple \
--target $TARGET \
-Zbuild-std
else
cargo build -p powersync_loadable --profile release_apple --target $TARGET -Zbuild-std
fi
done

createXcframework