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

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
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=7.0",
]

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

[target.x86_64-apple-watchos-sim]
rustflags = [
"-C", "link-arg=-mwatchos-version-min=7.0",
]
6 changes: 4 additions & 2 deletions .github/workflows/ios.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@ jobs:
aarch64-apple-darwin \
aarch64-apple-ios \
aarch64-apple-ios-sim \
x86_64-apple-ios

x86_64-apple-ios \
aarch64-apple-watchos \
aarch64-apple-watchos-sim \
x86_64-apple-watchos-sim
- name: setup-cocoapods
uses: maxim-lobanov/setup-cocoapods@v1
with:
Expand Down
6 changes: 4 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,10 @@ jobs:
aarch64-apple-darwin \
aarch64-apple-ios \
aarch64-apple-ios-sim \
x86_64-apple-ios

x86_64-apple-ios \
aarch64-apple-watchos \
aarch64-apple-watchos-sim \
x86_64-apple-watchos-sim
- name: setup-cocoapods
uses: maxim-lobanov/setup-cocoapods@v1
with:
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,4 @@ repository = "https://github.com/powersync-ja/powersync-sqlite-core"

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

19 changes: 13 additions & 6 deletions crates/shell/build.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@

fn main() {
let mut cfg = cc::Build::new();
let target = std::env::var("TARGET").unwrap();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we building crates/shell and crates/sqlite for watchOS somewhere? These are mostly used for testing and development, IIRC we don't ship them for iOS either. So I wonder if the changes are necessary.

let is_watchos = target.contains("watchos") || target.contains("watchsimulator");

// Compile the SQLite source
cfg.file("../sqlite/sqlite/sqlite3.c");
cfg.file("../sqlite/sqlite/shell.c");
cfg.include("../sqlite/sqlite");

// General SQLite options
Expand All @@ -14,15 +14,22 @@ fn main() {
// Call core_init() in main.rs
cfg.define("SQLITE_EXTRA_INIT", Some("core_init"));

// Compile with readline support (also requires -lreadline / cargo:rustc-link-lib=readline below)
cfg.define("HAVE_READLINE", Some("1"));
if is_watchos {
// For watchOS, don't build the shell and disable readline
cfg.define("HAVE_READLINE", Some("0"));
cfg.define("HAVE_EDITLINE", Some("0"));
cfg.define("SQLITE_OMIT_SYSTEM", Some("1"));
} else {
// For other platforms, build the shell with readline
cfg.file("../sqlite/sqlite/shell.c");
cfg.define("HAVE_READLINE", Some("1"));
println!("cargo:rustc-link-lib=readline");
}

// Silence warnings generated for SQLite
cfg.flag("-Wno-implicit-fallthrough");
cfg.flag("-Wno-unused-parameter");
cfg.flag("-Wno-null-pointer-subtraction");

cfg.compile("sqlite-ps");

println!("cargo:rustc-link-lib=readline");
}
1 change: 0 additions & 1 deletion crates/shell/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ fn panic(_info: &core::panic::PanicInfo) -> ! {
#[lang = "eh_personality"]
extern "C" fn eh_personality() {}


#[no_mangle]
pub extern "C" fn core_init(_dummy: *mut c_char) -> c_int {
powersync_init_static()
Expand Down
18 changes: 13 additions & 5 deletions crates/sqlite/build.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,32 @@
fn main() {
let mut cfg = cc::Build::new();
let target = std::env::var("TARGET").unwrap();
let is_watchos = target.contains("watchos") || target.contains("watchsimulator");

// Compile the SQLite source
cfg.file("./sqlite/sqlite3.c");
cfg.file("./sqlite/shell.c");
cfg.include("./sqlite");

// General SQLite options
cfg.define("SQLITE_THREADSAFE", Some("0"));
cfg.define("SQLITE_ENABLE_BYTECODE_VTAB", Some("1"));

// Compile with readline support (also requires -lreadline / cargo:rustc-link-lib=readline below)
cfg.define("HAVE_READLINE", Some("1"));
if is_watchos {
// For watchOS, don't build the shell and disable readline
cfg.define("HAVE_READLINE", Some("0"));
cfg.define("HAVE_EDITLINE", Some("0"));
cfg.define("SQLITE_OMIT_SYSTEM", Some("1"));
} else {
// For other platforms, build the shell with readline
cfg.file("./sqlite/shell.c");
cfg.define("HAVE_READLINE", Some("1"));
println!("cargo:rustc-link-lib=readline");
}

// Silence warnings generated for SQLite
cfg.flag("-Wno-implicit-fallthrough");
cfg.flag("-Wno-unused-parameter");
cfg.flag("-Wno-null-pointer-subtraction");

cfg.compile("sqlite");

println!("cargo:rustc-link-lib=readline");
}
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 = '7.0'
end
92 changes: 81 additions & 11 deletions tool/build_xcframework.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,11 @@ 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

function createXcframework() {
plist=$(cat << EOF
ios_plist=$(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's technically not just ios, we're using this for macOS too. I don't know what a better name would be either though, maybe common_plist?

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 @@ -34,26 +33,76 @@ function createXcframework() {
</dict>
</plist>
EOF
)
)

watchos_plist=$(
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">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>powersync-sqlite-core</string>
<key>CFBundleIdentifier</key>
<string>co.powersync.sqlitecore</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>MinimumOSVersion</key>
<string>7.0</string>
<key>CFBundleVersion</key>
<string>0.3.12</string>
<key>CFBundleShortVersionString</key>
<string>0.3.12</string>
Comment on lines +58 to +61
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice if we could extract the common prefix of those files into a shared variable, e.g. this one uses 0.3.12 while our other builds are at 0.3.14. Keeping those in sync would be easier that way.

<key>UIDeviceFamily</key>
<array>
<integer>4</integer>
</array>
<key>DTSDKName</key>
<string>watchos</string>
<key>DTPlatformName</key>
<string>watchos</string>
<key>DTPlatformVersion</key>
<string>7.0</string>
<key>DTXcode</key>
<string>1500</string>
<key>DTXcodeBuild</key>
<string>15A240d</string>
<key>DTCompiler</key>
<string>com.apple.compilers.llvm.clang.1_0</string>
<key>DTPlatformBuild</key>
<string>21R355</string>
<key>BuildMachineOSBuild</key>
<string>23D60</string>
</dict>
</plist>
EOF
)

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,20 +111,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/powersync-sqlite-core.framework/Versions/A/Resources"
echo "${watchos_plist}" >"${BUILD_DIR}/watchos-arm64/powersync-sqlite-core.framework/Versions/A/Resources/Info.plist"
cp -f "./target/aarch64-apple-watchos/release_apple/libpowersync.a" "${BUILD_DIR}/watchos-arm64/powersync-sqlite-core.framework/Versions/A/powersync-sqlite-core"
ln -sf A "${BUILD_DIR}/watchos-arm64/powersync-sqlite-core.framework/Versions/Current"
ln -sf Versions/Current/powersync-sqlite-core "${BUILD_DIR}/watchos-arm64/powersync-sqlite-core.framework/powersync-sqlite-core"
ln -sf Versions/Current/Resources "${BUILD_DIR}/watchos-arm64/powersync-sqlite-core.framework/Resources"

echo "===================== create watchos simulator framework ====================="
mkdir -p "${BUILD_DIR}/watchos-arm64-simulator/powersync-sqlite-core.framework/Versions/A/Resources"
echo "${watchos_plist}" >"${BUILD_DIR}/watchos-arm64-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-simulator/powersync-sqlite-core.framework/Versions/A/powersync-sqlite-core"
ln -sf A "${BUILD_DIR}/watchos-arm64-simulator/powersync-sqlite-core.framework/Versions/Current"
ln -sf Versions/Current/powersync-sqlite-core "${BUILD_DIR}/watchos-arm64-simulator/powersync-sqlite-core.framework/powersync-sqlite-core"
ln -sf Versions/Current/Resources "${BUILD_DIR}/watchos-arm64-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" \
-output "${BUILD_DIR}/powersync-sqlite-core.xcframework"

# how to create a watchOS XCFramework with static libraries, possible?

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
zip -r --symlinks powersync-sqlite-core.xcframework.zip powersync-sqlite-core.xcframework "${BUILD_DIR}/watchos-arm64/powersync-sqlite-core.framework/libpowersync.a" "${BUILD_DIR}/watchos-arm64-simulator/powersync-sqlite-core.framework/libpowersync.a" LICENSE README.md
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm also not a watchOS expert, but is there a reason for requiring static libraries here? Why would the regular framework not work?

rm -rf ${BUILD_DIR}
}

Expand All @@ -92,5 +158,9 @@ cargo build -p powersync_loadable --profile release_apple --target x86_64-apple-
# 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
# watchOS
cargo build -p powersync_loadable --profile release_apple -Zbuild-std=std,panic_abort --target aarch64-apple-watchos
cargo build -p powersync_loadable --profile release_apple -Zbuild-std=std,panic_abort --target aarch64-apple-watchos-sim
cargo build -p powersync_loadable --profile release_apple -Zbuild-std=std,panic_abort --target x86_64-apple-watchos-sim

createXcframework