diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dea8abd --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.build/ +.DS_Store +.swiftpm/ +Sources/ +sqlite-android-custom/ diff --git a/Package.resolved b/Package.resolved new file mode 100644 index 0000000..b8a43e3 --- /dev/null +++ b/Package.resolved @@ -0,0 +1,123 @@ +{ + "originHash" : "63d8efd39ff42dbce61b9d3aa4a4ec8e02658e133add2ea4308bfff507949048", + "pins" : [ + { + "identity" : "combine-schedulers", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/combine-schedulers", + "state" : { + "revision" : "fd16d76fd8b9a976d88bfb6cacc05ca8d19c91b6", + "version" : "1.1.0" + } + }, + { + "identity" : "swift-clocks", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-clocks", + "state" : { + "revision" : "cc46202b53476d64e824e0b6612da09d84ffde8e", + "version" : "1.0.6" + } + }, + { + "identity" : "swift-collections", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-collections", + "state" : { + "revision" : "7b847a3b7008b2dc2f47ca3110d8c782fb2e5c7e", + "version" : "1.3.0" + } + }, + { + "identity" : "swift-concurrency-extras", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-concurrency-extras", + "state" : { + "revision" : "5a3825302b1a0d744183200915a47b508c828e6f", + "version" : "1.3.2" + } + }, + { + "identity" : "swift-custom-dump", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-custom-dump", + "state" : { + "revision" : "82645ec760917961cfa08c9c0c7104a57a0fa4b1", + "version" : "1.3.3" + } + }, + { + "identity" : "swift-dependencies", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-dependencies", + "state" : { + "revision" : "a10f9feeb214bc72b5337b6ef6d5a029360db4cc", + "version" : "1.10.0" + } + }, + { + "identity" : "swift-identified-collections", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-identified-collections", + "state" : { + "revision" : "322d9ffeeba85c9f7c4984b39422ec7cc3c56597", + "version" : "1.1.1" + } + }, + { + "identity" : "swift-perception", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-perception", + "state" : { + "revision" : "4f47ebafed5f0b0172cf5c661454fa8e28fb2ac4", + "version" : "2.0.9" + } + }, + { + "identity" : "swift-sharing", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-sharing", + "state" : { + "revision" : "3bfc408cc2d0bee2287c174da6b1c76768377818", + "version" : "2.7.4" + } + }, + { + "identity" : "swift-snapshot-testing", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-snapshot-testing", + "state" : { + "revision" : "a8b7c5e0ed33d8ab8887d1654d9b59f2cbad529b", + "version" : "1.18.7" + } + }, + { + "identity" : "swift-structured-queries", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-structured-queries", + "state" : { + "revision" : "9c84335373bae5f5c9f7b5f0adf3ae10f2cab5b9", + "version" : "0.25.2" + } + }, + { + "identity" : "swift-syntax", + "kind" : "remoteSourceControl", + "location" : "https://github.com/swiftlang/swift-syntax", + "state" : { + "revision" : "4799286537280063c85a32f09884cfbca301b1a1", + "version" : "602.0.0" + } + }, + { + "identity" : "xctest-dynamic-overlay", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/xctest-dynamic-overlay", + "state" : { + "revision" : "4c27acf5394b645b70d8ba19dc249c0472d5f618", + "version" : "1.7.0" + } + } + ], + "version" : 3 +} diff --git a/Package.swift b/Package.swift new file mode 100644 index 0000000..121ff7d --- /dev/null +++ b/Package.swift @@ -0,0 +1,151 @@ +// swift-tools-version: 6.1 + +import PackageDescription + +let package = Package( + name: "sqlite-libs", + platforms: [ + .iOS(.v13), + .macOS(.v10_15), + .tvOS(.v13), + .watchOS(.v6), + ], + products: [ + .library(name: "GRDB", targets: ["GRDB"]), + .library(name: "SQLiteExtensions", targets: ["SQLiteExtensions"]), + .library(name: "SQLiteData", targets: ["SQLiteData"]), + ], + dependencies: [ + .package(url: "https://github.com/apple/swift-collections", from: "1.0.0"), + .package(url: "https://github.com/pointfreeco/swift-concurrency-extras", from: "1.0.0"), + .package(url: "https://github.com/pointfreeco/swift-dependencies", from: "1.9.0"), + .package(url: "https://github.com/pointfreeco/swift-sharing", from: "2.3.0"), + .package(url: "https://github.com/pointfreeco/swift-structured-queries", from: "0.24.0"), + .package(url: "https://github.com/pointfreeco/xctest-dynamic-overlay", from: "1.5.0"), + ], + targets: [ + .target( + name: "GRDBSQLite", + path: "Sources/SQLiteCustom", + exclude: ["sqlean/LICENSE"], + sources: [ + "sqlite3.c", + "series.c", + "sqlean/sqlite3-uuid.c", + "sqlean/uuid/extension.c", + "sqlean/sqlite3-text.c", + "sqlean/text/extension.c", + "sqlean/text/bstring.c", + "sqlean/text/rstring.c", + "sqlean/text/runes.c", + "sqlean/text/utf8/case.c", + "sqlean/text/utf8/rune.c", + "sqlean/text/utf8/utf8.c", + ], + publicHeadersPath: "include", + cSettings: [ + .headerSearchPath("include"), + .define("SQLITE_EXTRA_INIT_MUTEXED", to: "sqlite_extensions_init"), + .define("SQLITE_ENABLE_SNAPSHOT"), + .define("SQLITE_ENABLE_FTS5"), + .define("SQLITE_ENABLE_PREUPDATE_HOOK"), + .define("SQLITE_ENABLE_RTREE"), + .define("SQLITE_THREADSAFE", to: "2"), + .define("SQLITE_DQS", to: "0"), + .define("SQLITE_DEFAULT_MEMSTATUS", to: "0"), + .define("SQLITE_LIKE_DOESNT_MATCH_BLOBS"), + .define("SQLITE_MAX_EXPR_DEPTH", to: "0"), + .define("SQLITE_OMIT_PROGRESS_CALLBACK"), + .define("SQLITE_OMIT_SHARED_CACHE"), + .define("SQLITE_USE_ALLOCA"), + .define("SQLITE_OMIT_DEPRECATED"), + .define("SQLITE_TEMP_STORE", to: "2"), + .define("SQLITE_ENABLE_STAT4"), + .define("SQLITE_CORE"), + .define("SQLITE_DEFAULT_CACHE_SIZE", to: "10000"), + .define("SQLITE_DEFAULT_WAL_SYNCHRONOUS"), + .define("SQLITE_DEFAULT_BUSY_TIMEOUT", to: "30000"), + .define("SQLITE_DEFAULT_FOREIGN_KEYS", to: "1"), + .define("SQLITE_ENABLE_PERCENTILE"), + .define("SQLITE_ENABLE_MATH_FUNCTIONS"), + .define("SQLITE_UNTESTABLE"), + .define("SQLITE_OMIT_TCL_VARIABLE"), + .define("SQLITE_HAVE_ISNAN"), + .define("SQLITE_HAVE_LOCALTIME_R"), + .define("SQLITE_HAVE_MALLOC_USABLE_SIZE"), + .define("SQLITE_HAVE_STRCHRNUL"), + .define("SQLITE_ENABLE_GEOPOLY"), + .define("SQLITE_ENABLE_DBSTAT_VTAB"), + .define("SQLITE_ENABLE_CARRAY"), + .define("SQLITE_STAT4_SAMPLES", to: "64"), + .define("NDEBUG", .when(configuration: .release)), + .headerSearchPath("sqlean"), + .headerSearchPath("sqlean/uuid"), + .headerSearchPath("sqlean/text"), + .headerSearchPath("sqlean/text/utf8"), + .unsafeFlags(["-Wno-ambiguous-macro", "-O3"]), + ], + ), + .target( + name: "GRDB", + dependencies: ["GRDBSQLite"], + path: "Sources/GRDB", + exclude: ["Documentation.docc", "PrivacyInfo.xcprivacy", "LICENSE"], + swiftSettings: [ + .define("SQLITE_ENABLE_SNAPSHOT"), + .define("SQLITE_ENABLE_FTS5"), + .define("SQLITE_ENABLE_PREUPDATE_HOOK"), + .define("GRDBCUSTOMSQLITE"), + .unsafeFlags(["-O"]), + ] + ), + .target( + name: "SQLiteExtensions", + dependencies: ["GRDBSQLite"], + path: "Sources/SQLiteExtensions", + exclude: [ + "usearch/LICENSE", + "usearch/stringzilla/LICENSE", + "usearch/simsimd/LICENSE", + "usearch/fp16/LICENSE", + ], + sources: [ + "initialize-extensions.c", + "usearch/lib.cpp", + ], + publicHeadersPath: "include", + cSettings: [ + .define("SQLITE_CORE"), + .unsafeFlags(["-O3"]), + ], + cxxSettings: [ + .headerSearchPath("include"), + .headerSearchPath("usearch/include"), + .headerSearchPath("usearch/stringzilla/include"), + .headerSearchPath("usearch/simsimd/include"), + .headerSearchPath("usearch/fp16/include"), + .define("SQLITE_CORE"), + .define("USEARCH_USE_SIMSIMD"), + .define("USEARCH_USE_FP16LIB"), + .unsafeFlags(["-O3", "-ffast-math"]), + ] + ), + .target( + name: "SQLiteData", + dependencies: [ + "GRDB", + .product(name: "ConcurrencyExtras", package: "swift-concurrency-extras"), + .product(name: "Dependencies", package: "swift-dependencies"), + .product(name: "IssueReporting", package: "xctest-dynamic-overlay"), + .product(name: "OrderedCollections", package: "swift-collections"), + .product(name: "Sharing", package: "swift-sharing"), + .product(name: "StructuredQueriesSQLite", package: "swift-structured-queries"), + ], + path: "Sources/SQLiteData", + exclude: ["LICENSE"], + swiftSettings: [.unsafeFlags(["-O"])] + ), + ], + cLanguageStandard: .c11, + cxxLanguageStandard: .cxx17 +) diff --git a/README.md b/README.md new file mode 100644 index 0000000..0191ba5 --- /dev/null +++ b/README.md @@ -0,0 +1,55 @@ +# SQLite Libraries + +This repository bundles a custom SQLite build for use as a dependency in iOS and Android apps via SPM, JitPack, pub and CocoaPods. Included are: + +- SQLite amalgamation, built with optimized settings and the following official extensions: + - snapshot + - fts5 + - rtree + - math + - percentile + - geopoly + - carray + - series +- USearch vector extension (SIMD vector search and various distance metrics) +- SQLean's uuid extension (native UUID support, including UUIDv7) +- SQLean's text extension (QoL helpers that exist in PostgreSQL) +- GRDB (Swift SQLite driver, statically linked to custom SQLite) +- SQLiteData (Swift query builder, built on GRDB) + +The dependencies are prepared via `scripts/setup.sh`, which downloads and organizes the relevant source code and adds a few shims. + +## Installation + +### Flutter (Drift) +```yaml +dependency_overrides: + sqlite3_flutter_libs: + git: + url: https://github.com/immich-app/sqlite-libs + path: flutter + ref: +``` + +### Android (Room/Gradle) +```groovy +repositories { + maven { url 'https://jitpack.io' } +} +dependencies { + implementation 'com.github.immich-app.sqlite-libs:sqlite-android:' +} +``` + +To use with Room: +```kotlin +Room.databaseBuilder(context, AppDatabase::class.java, "db") + .openHelperFactory(RequerySQLiteOpenHelperFactory()) + .build() +``` + +### iOS (Swift Package Manager) +Add to your `Package.swift` or Xcode project: +``` +https://github.com/immich-app/sqlite-libs @ +``` diff --git a/flutter/.gitignore b/flutter/.gitignore new file mode 100644 index 0000000..3e5e0c1 --- /dev/null +++ b/flutter/.gitignore @@ -0,0 +1,9 @@ +.dart_tool/ +.packages +.pub/ +pubspec.lock +*.iml +.idea/ +build/ +.flutter-plugins +.flutter-plugins-dependencies diff --git a/flutter/android/build.gradle b/flutter/android/build.gradle new file mode 100644 index 0000000..0325d0a --- /dev/null +++ b/flutter/android/build.gradle @@ -0,0 +1,49 @@ +group 'eu.simonbinder.sqlite3_flutter_libs' +version '1.0' + +buildscript { + repositories { + google() + mavenCentral() + } + dependencies { + classpath 'com.android.tools.build:gradle:8.1.0' + classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.0' + } +} + +rootProject.allprojects { + repositories { + google() + mavenCentral() + mavenLocal() + maven { url 'https://jitpack.io' } + } +} + +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' + +android { + namespace 'eu.simonbinder.sqlite3_flutter_libs' + compileSdk 34 + + defaultConfig { + minSdk 26 + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 + } + + kotlinOptions { + jvmTarget = '17' + } +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib:1.9.0" + + implementation 'com.github.immich-app.sqlite-libs:sqlite-android:v0.1.0' +} diff --git a/flutter/android/settings.gradle b/flutter/android/settings.gradle new file mode 100644 index 0000000..74634a6 --- /dev/null +++ b/flutter/android/settings.gradle @@ -0,0 +1,8 @@ +rootProject.name = 'sqlite3_flutter_libs' + +// Include the sqlite-android module from the parent project +def sqliteAndroidPath = file('../sqlite-android-custom/sqlite-android') +if (sqliteAndroidPath.exists()) { + include ':sqlite-android' + project(':sqlite-android').projectDir = sqliteAndroidPath +} diff --git a/flutter/android/src/main/AndroidManifest.xml b/flutter/android/src/main/AndroidManifest.xml new file mode 100644 index 0000000..a2f47b6 --- /dev/null +++ b/flutter/android/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + + diff --git a/flutter/android/src/main/kotlin/eu/simonbinder/sqlite3_flutter_libs/Sqlite3FlutterLibsPlugin.kt b/flutter/android/src/main/kotlin/eu/simonbinder/sqlite3_flutter_libs/Sqlite3FlutterLibsPlugin.kt new file mode 100644 index 0000000..836ab21 --- /dev/null +++ b/flutter/android/src/main/kotlin/eu/simonbinder/sqlite3_flutter_libs/Sqlite3FlutterLibsPlugin.kt @@ -0,0 +1,15 @@ +package eu.simonbinder.sqlite3_flutter_libs + +import io.flutter.embedding.engine.plugins.FlutterPlugin + +/** + * Flutter plugin that bundles custom SQLite with extensions. + * + * This plugin ensures the custom SQLite library (with FTS5, USearch, SQLean extensions) + * is bundled with the app via the sqlite-android dependency. The plugin class itself + * is a no-op required by Flutter's plugin system. + */ +class Sqlite3FlutterLibsPlugin : FlutterPlugin { + override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) {} + override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {} +} diff --git a/flutter/darwin/sqlite3_flutter_libs.podspec b/flutter/darwin/sqlite3_flutter_libs.podspec new file mode 100644 index 0000000..71fb9e5 --- /dev/null +++ b/flutter/darwin/sqlite3_flutter_libs.podspec @@ -0,0 +1,33 @@ +Pod::Spec.new do |s| + s.name = 'sqlite3_flutter_libs' + s.version = '0.0.1' + s.summary = 'Custom SQLite build with extensions for Flutter' + s.description = <<-DESC +Flutter plugin providing a custom SQLite build with FTS5, USearch vector search, +and SQLean extensions (uuid, text). The native library is provided by the +sqlite-libs Swift Package. + DESC + s.homepage = 'https://github.com/immich-app/sqlite-libs' + s.license = { :type => 'AGPLv3' } + s.author = { 'Mert Alev' => '' } + s.source = { :path => '.' } + + s.source_files = 'sqlite3_flutter_libs/Sources/sqlite3_flutter_libs/**/*.swift' + + s.ios.dependency 'Flutter' + s.osx.dependency 'FlutterMacOS' + + s.ios.deployment_target = '13.0' + s.osx.deployment_target = '10.15' + s.swift_version = '5.0' + + # The actual SQLite library comes from the sqlite-libs SPM package, + # which is added to the iOS/macOS app via SPM or through the podspec's + # script phase below. + + s.pod_target_xcconfig = { + 'DEFINES_MODULE' => 'YES', + # Ensure we can find the SQLite symbols from the parent SPM package + 'OTHER_LDFLAGS' => '-lsqlite3', + } +end diff --git a/flutter/darwin/sqlite3_flutter_libs/Package.resolved b/flutter/darwin/sqlite3_flutter_libs/Package.resolved new file mode 100644 index 0000000..973a23c --- /dev/null +++ b/flutter/darwin/sqlite3_flutter_libs/Package.resolved @@ -0,0 +1,122 @@ +{ + "pins" : [ + { + "identity" : "combine-schedulers", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/combine-schedulers", + "state" : { + "revision" : "fd16d76fd8b9a976d88bfb6cacc05ca8d19c91b6", + "version" : "1.1.0" + } + }, + { + "identity" : "swift-clocks", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-clocks", + "state" : { + "revision" : "cc46202b53476d64e824e0b6612da09d84ffde8e", + "version" : "1.0.6" + } + }, + { + "identity" : "swift-collections", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-collections", + "state" : { + "revision" : "7b847a3b7008b2dc2f47ca3110d8c782fb2e5c7e", + "version" : "1.3.0" + } + }, + { + "identity" : "swift-concurrency-extras", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-concurrency-extras", + "state" : { + "revision" : "5a3825302b1a0d744183200915a47b508c828e6f", + "version" : "1.3.2" + } + }, + { + "identity" : "swift-custom-dump", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-custom-dump", + "state" : { + "revision" : "82645ec760917961cfa08c9c0c7104a57a0fa4b1", + "version" : "1.3.3" + } + }, + { + "identity" : "swift-dependencies", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-dependencies", + "state" : { + "revision" : "a10f9feeb214bc72b5337b6ef6d5a029360db4cc", + "version" : "1.10.0" + } + }, + { + "identity" : "swift-identified-collections", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-identified-collections", + "state" : { + "revision" : "322d9ffeeba85c9f7c4984b39422ec7cc3c56597", + "version" : "1.1.1" + } + }, + { + "identity" : "swift-perception", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-perception", + "state" : { + "revision" : "4f47ebafed5f0b0172cf5c661454fa8e28fb2ac4", + "version" : "2.0.9" + } + }, + { + "identity" : "swift-sharing", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-sharing", + "state" : { + "revision" : "3bfc408cc2d0bee2287c174da6b1c76768377818", + "version" : "2.7.4" + } + }, + { + "identity" : "swift-snapshot-testing", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-snapshot-testing", + "state" : { + "revision" : "a8b7c5e0ed33d8ab8887d1654d9b59f2cbad529b", + "version" : "1.18.7" + } + }, + { + "identity" : "swift-structured-queries", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-structured-queries", + "state" : { + "revision" : "9c84335373bae5f5c9f7b5f0adf3ae10f2cab5b9", + "version" : "0.25.2" + } + }, + { + "identity" : "swift-syntax", + "kind" : "remoteSourceControl", + "location" : "https://github.com/swiftlang/swift-syntax", + "state" : { + "revision" : "4799286537280063c85a32f09884cfbca301b1a1", + "version" : "602.0.0" + } + }, + { + "identity" : "xctest-dynamic-overlay", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/xctest-dynamic-overlay", + "state" : { + "revision" : "4c27acf5394b645b70d8ba19dc249c0472d5f618", + "version" : "1.7.0" + } + } + ], + "version" : 2 +} diff --git a/flutter/darwin/sqlite3_flutter_libs/Package.swift b/flutter/darwin/sqlite3_flutter_libs/Package.swift new file mode 100644 index 0000000..8e6550e --- /dev/null +++ b/flutter/darwin/sqlite3_flutter_libs/Package.swift @@ -0,0 +1,26 @@ +// swift-tools-version: 5.9 + +import PackageDescription + +let package = Package( + name: "sqlite3_flutter_libs", + platforms: [ + .iOS(.v13), + .macOS(.v10_15) + ], + products: [ + .library(name: "sqlite3-flutter-libs", type: .static, targets: ["sqlite3_flutter_libs"]) + ], + dependencies: [ + // Reference the parent sqlite-libs package + .package(path: "../../.."), + ], + targets: [ + .target( + name: "sqlite3_flutter_libs", + dependencies: [ + .product(name: "SQLiteExtensions", package: "sqlite-libs"), + ] + ) + ] +) diff --git a/flutter/darwin/sqlite3_flutter_libs/Sources/sqlite3_flutter_libs/Sqlite3FlutterLibsPlugin.swift b/flutter/darwin/sqlite3_flutter_libs/Sources/sqlite3_flutter_libs/Sqlite3FlutterLibsPlugin.swift new file mode 100644 index 0000000..4a2203b --- /dev/null +++ b/flutter/darwin/sqlite3_flutter_libs/Sources/sqlite3_flutter_libs/Sqlite3FlutterLibsPlugin.swift @@ -0,0 +1,19 @@ +import Foundation + +#if os(iOS) +import Flutter +#elseif os(macOS) +import FlutterMacOS +#endif + +/// Flutter plugin that provides custom SQLite with extensions. +/// +/// This plugin itself is a no-op - its purpose is to ensure the custom SQLite +/// library (with FTS5, USearch, SQLean extensions) is linked into the app. +/// The actual SQLite symbols come from the sqlite-libs SPM package. +public class Sqlite3FlutterLibsPlugin: NSObject, FlutterPlugin { + public static func register(with registrar: FlutterPluginRegistrar) { + // No method channel needed on iOS/macOS. + // The plugin just ensures SQLite is linked via the SPM dependency. + } +} diff --git a/flutter/lib/sqlite3_flutter_libs.dart b/flutter/lib/sqlite3_flutter_libs.dart new file mode 100644 index 0000000..2d845e1 --- /dev/null +++ b/flutter/lib/sqlite3_flutter_libs.dart @@ -0,0 +1,12 @@ +/// Flutter plugin providing custom SQLite build with extensions. +/// +/// This package bundles a custom SQLite build with FTS5, USearch vector search, +/// and SQLean extensions (uuid, text). It serves as a drop-in replacement for +/// the standard sqlite3_flutter_libs package. +library sqlite3_flutter_libs; + +/// No-op for API compatibility with sqlite3_flutter_libs. +/// +/// The original function worked around a bug in Android 6.0.1's dynamic linker. +/// This is unnecessary for minSdk 26+. +Future applyWorkaroundToOpenSqlite3OnOldAndroidVersions() async {} diff --git a/flutter/pubspec.yaml b/flutter/pubspec.yaml new file mode 100644 index 0000000..06d1a64 --- /dev/null +++ b/flutter/pubspec.yaml @@ -0,0 +1,28 @@ +name: sqlite3_flutter_libs +description: >- + Flutter plugin providing custom SQLite build with extensions (FTS5, USearch, SQLean). + Drop-in replacement for sqlite3_flutter_libs. +version: 0.5.40 + +homepage: https://github.com/immich-app/sqlite-libs + +environment: + sdk: ">=2.17.0 <4.0.0" + flutter: ">=3.7.0" + +dependencies: + flutter: + sdk: flutter + +flutter: + plugin: + platforms: + android: + package: eu.simonbinder.sqlite3_flutter_libs + pluginClass: Sqlite3FlutterLibsPlugin + ios: + pluginClass: Sqlite3FlutterLibsPlugin + sharedDarwinSource: true + macos: + pluginClass: Sqlite3FlutterLibsPlugin + sharedDarwinSource: true diff --git a/scripts/android/Android.mk b/scripts/android/Android.mk new file mode 100644 index 0000000..e372509 --- /dev/null +++ b/scripts/android/Android.mk @@ -0,0 +1,4 @@ + +LOCAL_PATH:= $(call my-dir) +include $(LOCAL_PATH)/sqlite/Android.mk + diff --git a/scripts/android/Application.mk b/scripts/android/Application.mk new file mode 100644 index 0000000..bd6c41f --- /dev/null +++ b/scripts/android/Application.mk @@ -0,0 +1,6 @@ +APP_STL := c++_static +APP_CPPFLAGS := -std=c++17 -fexceptions -frtti +APP_OPTIM := release +APP_ABI := arm64-v8a,x86_64 +NDK_TOOLCHAIN_VERSION := clang +NDK_APP_LIBS_OUT := ../jniLibs diff --git a/scripts/android/sqlite/Android.mk b/scripts/android/sqlite/Android.mk new file mode 100644 index 0000000..ffb549d --- /dev/null +++ b/scripts/android/sqlite/Android.mk @@ -0,0 +1,116 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +# Custom SQLite flags +# Note: Some flags differ from iOS to maintain compatibility with requery's JNI code: +# - SQLITE_OMIT_TRACE: removed (requery uses sqlite3_trace) +# - SQLITE_OMIT_PROGRESS_CALLBACK: removed (requery uses sqlite3_progress_handler) +# - SQLITE_OMIT_DEPRECATED: removed (sqlite3_trace/profile are deprecated) +sqlite_flags := \ + -DNDEBUG=1 \ + -DSQLITE_EXTRA_INIT_MUTEXED=sqlite_extensions_init \ + -DSQLITE_ENABLE_SNAPSHOT \ + -DSQLITE_ENABLE_FTS5 \ + -DSQLITE_ENABLE_PREUPDATE_HOOK \ + -DSQLITE_ENABLE_RTREE \ + -DSQLITE_THREADSAFE=2 \ + -DSQLITE_DQS=0 \ + -DSQLITE_DEFAULT_MEMSTATUS=0 \ + -DSQLITE_LIKE_DOESNT_MATCH_BLOBS \ + -DSQLITE_MAX_EXPR_DEPTH=0 \ + -DSQLITE_OMIT_SHARED_CACHE \ + -DSQLITE_USE_ALLOCA \ + -DSQLITE_OMIT_AUTOINIT \ + -DSQLITE_TEMP_STORE=2 \ + -DSQLITE_ENABLE_STAT4 \ + -DSQLITE_CORE \ + -DSQLITE_DEFAULT_CACHE_SIZE=10000 \ + -DSQLITE_DEFAULT_WAL_SYNCHRONOUS \ + -DSQLITE_DEFAULT_BUSY_TIMEOUT=30000 \ + -DSQLITE_DEFAULT_FOREIGN_KEYS=1 \ + -DSQLITE_ENABLE_PERCENTILE \ + -DSQLITE_ENABLE_MATH_FUNCTIONS \ + -DSQLITE_UNTESTABLE \ + -DSQLITE_OMIT_TCL_VARIABLE \ + -DSQLITE_HAVE_ISNAN \ + -DSQLITE_HAVE_LOCALTIME_R \ + -DSQLITE_HAVE_MALLOC_USABLE_SIZE \ + -DSQLITE_HAVE_STRCHRNUL \ + -DSQLITE_ENABLE_GEOPOLY \ + -DSQLITE_ENABLE_DBSTAT_VTAB \ + -DSQLITE_ENABLE_CARRAY \ + -DHAVE_USLEEP=1 \ + -DSQLITE_DEFAULT_JOURNAL_SIZE_LIMIT=1048576 \ + -DSQLITE_POWERSAFE_OVERWRITE=1 \ + -DSQLITE_DEFAULT_FILE_FORMAT=4 \ + -DSQLITE_ENABLE_MEMORY_MANAGEMENT=1 \ + -DSQLITE_DEFAULT_FILE_PERMISSIONS=0600 \ + -DSQLITE_ENABLE_BATCH_ATOMIC_WRITE \ + -O3 + +LOCAL_CFLAGS += $(sqlite_flags) +LOCAL_CFLAGS += -Wno-unused-parameter -Wno-int-to-pointer-cast +LOCAL_CFLAGS += -Wno-uninitialized -Wno-parentheses +LOCAL_CPPFLAGS += -Wno-conversion-null + +ifeq ($(TARGET_ARCH), arm) + LOCAL_CFLAGS += -DPACKED="__attribute__ ((packed))" +else + LOCAL_CFLAGS += -DPACKED="" +endif + +# USearch extension flags +usearch_flags := \ + -DSQLITE_CORE \ + -DUSEARCH_USE_SIMSIMD \ + -DUSEARCH_USE_FP16LIB \ + -O3 \ + -ffast-math + +LOCAL_CPPFLAGS += $(usearch_flags) + +# Source files +LOCAL_SRC_FILES := \ + android_database_SQLiteCommon.cpp \ + android_database_SQLiteConnection.cpp \ + android_database_SQLiteFunction.cpp \ + android_database_SQLiteGlobal.cpp \ + android_database_SQLiteDebug.cpp \ + android_database_CursorWindow.cpp \ + CursorWindow.cpp \ + JNIHelp.cpp \ + JNIString.cpp \ + sqlite3.c \ + sqlite_extensions_init.c \ + series.c \ + ../usearch/lib.cpp \ + ../sqlean/sqlite3-uuid.c \ + ../sqlean/uuid/extension.c \ + ../sqlean/sqlite3-text.c \ + ../sqlean/text/extension.c \ + ../sqlean/text/bstring.c \ + ../sqlean/text/rstring.c \ + ../sqlean/text/runes.c \ + ../sqlean/text/utf8/case.c \ + ../sqlean/text/utf8/rune.c \ + ../sqlean/text/utf8/utf8.c + +# Include paths +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH) \ + $(LOCAL_PATH)/../usearch/include \ + $(LOCAL_PATH)/../usearch/stringzilla/include \ + $(LOCAL_PATH)/../usearch/simsimd/include \ + $(LOCAL_PATH)/../usearch/fp16/include \ + $(LOCAL_PATH)/../sqlean \ + $(LOCAL_PATH)/../sqlean/uuid \ + $(LOCAL_PATH)/../sqlean/text \ + $(LOCAL_PATH)/../sqlean/text/utf8 + +# Export include path so usearch can find sqlite3ext.h +LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH) + +LOCAL_MODULE := libsqlite3 +LOCAL_LDLIBS += -ldl -llog -latomic + +include $(BUILD_SHARED_LIBRARY) diff --git a/scripts/android/sqlite/sqlite_extensions_init.c b/scripts/android/sqlite/sqlite_extensions_init.c new file mode 100644 index 0000000..b7d2e8f --- /dev/null +++ b/scripts/android/sqlite/sqlite_extensions_init.c @@ -0,0 +1,19 @@ +#define SQLITE_CORE 1 +#include "sqlite3.h" + +// Extension entry points +extern int sqlite3_series_init(sqlite3*, char**, const void*); +extern int sqlite3_uuid_init(sqlite3*, char**, const void*); +extern int sqlite3_text_init(sqlite3*, char**, const void*); +extern int sqlite3_usearch_sqlite_init(sqlite3*, char**, const void*); + +// Called automatically during sqlite3_initialize() via SQLITE_EXTRA_INIT_MUTEXED +// Runs under the init mutex, so thread-safe +int sqlite_extensions_init(const char *unused) { + (void)unused; + sqlite3_auto_extension((void (*)(void))sqlite3_series_init); + sqlite3_auto_extension((void (*)(void))sqlite3_uuid_init); + sqlite3_auto_extension((void (*)(void))sqlite3_text_init); + sqlite3_auto_extension((void (*)(void))sqlite3_usearch_sqlite_init); + return SQLITE_OK; +} diff --git a/scripts/ios/GRDBSQLite.h b/scripts/ios/GRDBSQLite.h new file mode 100644 index 0000000..6647b75 --- /dev/null +++ b/scripts/ios/GRDBSQLite.h @@ -0,0 +1,17 @@ +#ifndef GRDBSQLITE_H +#define GRDBSQLITE_H + +// Umbrella header for the GRDBSQLite module +// This header exposes SQLite and the GRDB shim to Swift + +// SQLITE_CORE must be defined before including sqlite3ext.h +// to prevent it from redefining functions to use sqlite3_api +#ifndef SQLITE_CORE +#define SQLITE_CORE 1 +#endif + +#include "sqlite3.h" +#include "sqlite3ext.h" +#include "shim.h" + +#endif /* GRDBSQLITE_H */ diff --git a/scripts/ios/SQLiteExtensions/include/initialize-extensions.h b/scripts/ios/SQLiteExtensions/include/initialize-extensions.h new file mode 100644 index 0000000..50919e9 --- /dev/null +++ b/scripts/ios/SQLiteExtensions/include/initialize-extensions.h @@ -0,0 +1,8 @@ +#ifndef INITIALIZE_EXTENSIONS_H +#define INITIALIZE_EXTENSIONS_H + +// This function is called automatically during sqlite3_initialize() +// via SQLITE_EXTRA_INIT_MUTEXED - no need to call it manually +int sqlite_extensions_init(const char *unused); + +#endif diff --git a/scripts/ios/SQLiteExtensions/initialize-extensions.c b/scripts/ios/SQLiteExtensions/initialize-extensions.c new file mode 100644 index 0000000..ee75446 --- /dev/null +++ b/scripts/ios/SQLiteExtensions/initialize-extensions.c @@ -0,0 +1,19 @@ +#define SQLITE_CORE 1 +#include "sqlite3.h" + +// Extension entry points (C extensions in GRDBSQLite, USearch in SQLiteExtensions) +extern int sqlite3_series_init(sqlite3*, char**, const void*); +extern int sqlite3_uuid_init(sqlite3*, char**, const void*); +extern int sqlite3_text_init(sqlite3*, char**, const void*); +extern int sqlite3_usearchsqlite_init(sqlite3*, char**, const void*); + +// Called automatically during sqlite3_initialize() via SQLITE_EXTRA_INIT_MUTEXED +// Runs under the init mutex, so thread-safe +int sqlite_extensions_init(const char *unused) { + (void)unused; + sqlite3_auto_extension((void (*)(void))sqlite3_series_init); + sqlite3_auto_extension((void (*)(void))sqlite3_uuid_init); + sqlite3_auto_extension((void (*)(void))sqlite3_text_init); + sqlite3_auto_extension((void (*)(void))sqlite3_usearchsqlite_init); + return SQLITE_OK; +} diff --git a/scripts/ios/shim.h b/scripts/ios/shim.h new file mode 100644 index 0000000..748e90c --- /dev/null +++ b/scripts/ios/shim.h @@ -0,0 +1,79 @@ +#ifndef GRDB_SHIM_H +#define GRDB_SHIM_H + +#include "sqlite3.h" + +// MARK: - Variadic Functions Support + +// sqlite3_config() is a variadic function that can't be directly called from +// Swift. This shim provides a typed wrapper for the specific use case needed. + +static inline void _registerErrorLogCallback(void (*callback)(void *pArg, int iErrCode, const char *zMsg)) { + sqlite3_config(SQLITE_CONFIG_LOG, callback, 0); +} + +// sqlite3_db_config() is also variadic. These helpers provide typed access. + +static inline void _enableDoubleQuotedStringLiterals(sqlite3 *db) { + sqlite3_db_config(db, SQLITE_DBCONFIG_DQS_DML, 1, (void *)0); + sqlite3_db_config(db, SQLITE_DBCONFIG_DQS_DDL, 1, (void *)0); +} + +static inline void _disableDoubleQuotedStringLiterals(sqlite3 *db) { + sqlite3_db_config(db, SQLITE_DBCONFIG_DQS_DML, 0, (void *)0); + sqlite3_db_config(db, SQLITE_DBCONFIG_DQS_DDL, 0, (void *)0); +} + +static inline void _disableDefensiveMode(sqlite3 *db) { + sqlite3_db_config(db, SQLITE_DBCONFIG_DEFENSIVE, 0, (void *)0); +} + +// MARK: - Preupdate Hook Functions + +// These functions are always declared since they're compiled into our custom +// SQLite build with SQLITE_ENABLE_PREUPDATE_HOOK defined. +// Note: We cannot use #ifdef here because SPM cSettings don't propagate +// to header preprocessing. + +SQLITE_API void *sqlite3_preupdate_hook( + sqlite3 *db, + void(*xPreUpdate)( + void *pCtx, + sqlite3 *db, + int op, + char const *zDb, + char const *zName, + sqlite3_int64 iKey1, + sqlite3_int64 iKey2 + ), + void* +); +SQLITE_API int sqlite3_preupdate_old(sqlite3 *, int, sqlite3_value **); +SQLITE_API int sqlite3_preupdate_count(sqlite3 *); +SQLITE_API int sqlite3_preupdate_depth(sqlite3 *); +SQLITE_API int sqlite3_preupdate_new(sqlite3 *, int, sqlite3_value **); + +// MARK: - Snapshot Functions + +SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_get( + sqlite3 *db, + const char *zSchema, + sqlite3_snapshot **ppSnapshot +); + +SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_open( + sqlite3 *db, + const char *zSchema, + sqlite3_snapshot *pSnapshot +); + +SQLITE_API SQLITE_EXPERIMENTAL void sqlite3_snapshot_free(sqlite3_snapshot*); + +SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp( + sqlite3_snapshot *p1, + sqlite3_snapshot *p2 +); + +SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb); + +#endif /* GRDB_SHIM_H */ diff --git a/scripts/setup-android.sh b/scripts/setup-android.sh new file mode 100755 index 0000000..b6a30a1 --- /dev/null +++ b/scripts/setup-android.sh @@ -0,0 +1,102 @@ +#!/usr/bin/env bash + +set -eu + +# Setup script for Android SQLite build +# This regenerates the sqlite-android fork with custom SQLite and USearch extension + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +ROOT_DIR="$(dirname "$SCRIPT_DIR")" +ANDROID_DIR="$ROOT_DIR/sqlite-android-custom" +TEMPLATE_DIR="$SCRIPT_DIR/android" +SQLITE_ANDROID_REPO="https://github.com/requery/sqlite-android.git" + +echo "=== SQLite Android Setup ===" +echo "Root directory: $ROOT_DIR" +echo "Android directory: $ANDROID_DIR" + +echo "Cloning sqlite-android..." +rm -rf "$ANDROID_DIR" +git clone "$SQLITE_ANDROID_REPO" "$ANDROID_DIR" +rm -rf "$ANDROID_DIR/.git" + +JNI_DIR="$ANDROID_DIR/sqlite-android/src/main/jni" +SQLITE_DIR="$JNI_DIR/sqlite" +USEARCH_DIR="$JNI_DIR/usearch" +SQLEAN_DIR="$JNI_DIR/sqlean" + +# Copy SQLite source files +echo "Copying SQLite source files..." +cp "$ROOT_DIR/Sources/SQLiteCustom/sqlite3.c" "$SQLITE_DIR/" +cp "$ROOT_DIR/Sources/SQLiteCustom/include/sqlite3.h" "$SQLITE_DIR/" +cp "$ROOT_DIR/Sources/SQLiteCustom/include/sqlite3ext.h" "$SQLITE_DIR/" + +# Copy USearch extension +echo "Copying USearch extension..." +rm -rf "$USEARCH_DIR" +mkdir -p "$USEARCH_DIR" +cp -r "$ROOT_DIR/Sources/SQLiteExtensions/usearch/include" "$USEARCH_DIR/" +cp -r "$ROOT_DIR/Sources/SQLiteExtensions/usearch/stringzilla" "$USEARCH_DIR/" +cp -r "$ROOT_DIR/Sources/SQLiteExtensions/usearch/simsimd" "$USEARCH_DIR/" +cp -r "$ROOT_DIR/Sources/SQLiteExtensions/usearch/fp16" "$USEARCH_DIR/" +cp "$ROOT_DIR/Sources/SQLiteExtensions/usearch/lib.cpp" "$USEARCH_DIR/" +cp "$ROOT_DIR/Sources/SQLiteExtensions/usearch/LICENSE" "$USEARCH_DIR/" + +# Copy SQLean extensions (uuid and text) +echo "Copying SQLean extensions..." +rm -rf "$SQLEAN_DIR" +mkdir -p "$SQLEAN_DIR" +cp -r "$ROOT_DIR/Sources/SQLiteCustom/sqlean/"* "$SQLEAN_DIR/" + +# Copy SQLite series extension +echo "Copying series extension..." +cp "$ROOT_DIR/Sources/SQLiteCustom/series.c" "$SQLITE_DIR/" + +# Patch SQLean uuid for Android (timespec_get is not available in Bionic libc) +echo "Patching SQLean uuid for Android..." +UUID_EXT="$SQLEAN_DIR/uuid/extension.c" +sed -i.bak 's/timespec_get(&ts, TIME_UTC)/clock_gettime(CLOCK_REALTIME, \&ts)/' "$UUID_EXT" && rm "$UUID_EXT.bak" + +# Copy build configuration files from templates +echo "Copying build configuration files..." +cp "$TEMPLATE_DIR/Application.mk" "$JNI_DIR/" +cp "$TEMPLATE_DIR/Android.mk" "$JNI_DIR/" +cp "$TEMPLATE_DIR/sqlite/Android.mk" "$SQLITE_DIR/" +cp "$TEMPLATE_DIR/sqlite/sqlite_extensions_init.c" "$SQLITE_DIR/" + +# Patch library name from sqlite3x to sqlite3 +echo "Patching library name..." +SQLITE_DB_FILE="$ANDROID_DIR/sqlite-android/src/main/java/io/requery/android/database/sqlite/SQLiteDatabase.java" +sed -i.bak 's/LIBRARY_NAME = "sqlite3x"/LIBRARY_NAME = "sqlite3"/' "$SQLITE_DB_FILE" && rm "$SQLITE_DB_FILE.bak" + +# Patch build.gradle +echo "Patching build.gradle..." +BUILD_GRADLE="$ANDROID_DIR/sqlite-android/build.gradle" + +awk ' +/abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64"/ { + sub(/abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64"/, "abiFilters \"arm64-v8a\", \"x86_64\"") +} +/^ext \{/,/^preBuild.dependsOn installSqlite/ { + next +} +{ print } +' "$BUILD_GRADLE" > "$BUILD_GRADLE.tmp" && mv "$BUILD_GRADLE.tmp" "$BUILD_GRADLE" + +# Patch gradle.properties for JitPack +echo "Patching gradle.properties for JitPack..." +GRADLE_PROPS="$ANDROID_DIR/gradle.properties" +sed -i.bak 's/^GROUP=.*/GROUP=com.github.immich-app.sqlite-libs/' "$GRADLE_PROPS" && rm "$GRADLE_PROPS.bak" + +echo "" +echo "=== Setup complete ===" +echo "" +echo "To build the Android library:" +echo " cd $ANDROID_DIR" +echo " ./gradlew :sqlite-android:assembleRelease" +echo "" +echo "To publish to local Maven:" +echo " ./gradlew :sqlite-android:publishToMavenLocal" +echo "" +echo "The AAR will be at:" +echo " $ANDROID_DIR/sqlite-android/build/outputs/aar/sqlite-android-release.aar" diff --git a/scripts/setup.sh b/scripts/setup.sh new file mode 100755 index 0000000..22bad03 --- /dev/null +++ b/scripts/setup.sh @@ -0,0 +1,104 @@ +#!/usr/bin/env bash + +set -eu + +# renovate: datasource=github-tags depName=sqlite/sqlite +SQLITE_COMMIT="${SQLITE_COMMIT:-ba76c160c735437de974c6ea24c890a663214c6b}" # version-3.51.2 + +# renovate: datasource=github-tags depName=groue/GRDB.swift +GRDB_COMMIT="${GRDB_COMMIT:-36e30a6f1ef10e4194f6af0cff90888526f0c115}" # v7.10.0 + +# renovate: datasource=github-tags depName=pointfreeco/sqlite-data +SQLITEDATA_COMMIT="${SQLITEDATA_COMMIT:-5de18896e7a0358084bb4e3c83f7227500ba029b}" # 1.5.2 + +# renovate: datasource=github-tags depName=unum-cloud/USearch +USEARCH_COMMIT="${USEARCH_COMMIT:-40d127f472e9073875566f0e9308c0302b89100a}" # v2.24.0 + +# renovate: datasource=github-tags depName=nalgeon/sqlean +SQLEAN_COMMIT="${SQLEAN_COMMIT:-0e2985467a5da3d7641447616609f8a8b8665b0a}" # 0.28.1 + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +ROOT_DIR="$(dirname "$SCRIPT_DIR")" +OUTPUT_DIR="${1:-$ROOT_DIR}" +TEMPLATES_DIR="${SCRIPT_DIR}/ios" + +if [ ! -d "${TEMPLATES_DIR}" ]; then + echo "Error: ios/ templates directory not found at ${TEMPLATES_DIR}" + exit 1 +fi + +echo "Creating GRDB + SQLiteData package..." +echo " SQLite: ${SQLITE_COMMIT}" +echo " GRDB: ${GRDB_COMMIT}" +echo " SQLiteData: ${SQLITEDATA_COMMIT}" +echo " USearch: ${USEARCH_COMMIT}" +echo " SQLean: ${SQLEAN_COMMIT}" + +rm -rf "${OUTPUT_DIR}/Sources" +mkdir -p "${OUTPUT_DIR}/Sources"/{GRDB,SQLiteCustom/include,SQLiteData,SQLiteExtensions/include} +mkdir -p "${OUTPUT_DIR}/Sources"/SQLiteExtensions/usearch/{include/usearch,stringzilla/include/stringzilla,stringzilla/c,simsimd/include/simsimd,fp16/include/fp16} +cd "${OUTPUT_DIR}" + +TEMP=$(mktemp -d) +trap "rm -rf ${TEMP}" EXIT + +echo "Downloading GRDB..." +curl -sL "https://github.com/groue/GRDB.swift/archive/${GRDB_COMMIT}.tar.gz" \ + | tar -xz -C "${TEMP}" +cp -R "${TEMP}"/GRDB.swift-*/GRDB/. Sources/GRDB/ +cp "${TEMP}"/GRDB.swift-*/LICENSE Sources/GRDB/LICENSE + +echo "Building SQLite amalgamation..." +curl -sL "https://github.com/sqlite/sqlite/archive/${SQLITE_COMMIT}.tar.gz" \ + | tar -xz -C "${TEMP}" +SQLITE_SRC="${TEMP}/sqlite-${SQLITE_COMMIT}" +(cd "${SQLITE_SRC}" && ./configure --quiet --enable-update-limit && make -j sqlite3.c) +cp "${SQLITE_SRC}/sqlite3.c" Sources/SQLiteCustom/ +cp "${SQLITE_SRC}/sqlite3.h" Sources/SQLiteCustom/include/ +cp "${SQLITE_SRC}/sqlite3ext.h" Sources/SQLiteCustom/include/ +cp "${SQLITE_SRC}/ext/misc/series.c" Sources/SQLiteCustom/ + +echo "Downloading SQLiteData..." +curl -sL "https://github.com/pointfreeco/sqlite-data/archive/${SQLITEDATA_COMMIT}.tar.gz" \ + | tar -xz -C "${TEMP}" +cp -R "${TEMP}"/sqlite-data-*/Sources/SQLiteData/. Sources/SQLiteData/ +cp "${TEMP}"/sqlite-data-*/LICENSE Sources/SQLiteData/LICENSE +rm -rf Sources/SQLiteData/CloudKit Sources/SQLiteData/Documentation.docc 2>/dev/null || true + +echo "Downloading USearch..." +git clone --quiet --depth 1 --recursive --shallow-submodules \ + https://github.com/unum-cloud/USearch.git "${TEMP}/usearch" +git -C "${TEMP}/usearch" fetch --quiet --depth 1 origin "${USEARCH_COMMIT}" +git -C "${TEMP}/usearch" checkout --quiet "${USEARCH_COMMIT}" +git -C "${TEMP}/usearch" submodule update --quiet --recursive +cp "${TEMP}/usearch/include/usearch/"*.hpp Sources/SQLiteExtensions/usearch/include/usearch/ +cp "${TEMP}/usearch/sqlite/lib.cpp" Sources/SQLiteExtensions/usearch/ +cp "${TEMP}/usearch/LICENSE" Sources/SQLiteExtensions/usearch/LICENSE +cp "${TEMP}/usearch/stringzilla/include/stringzilla/"*.h Sources/SQLiteExtensions/usearch/stringzilla/include/stringzilla/ +cp "${TEMP}/usearch/stringzilla/include/stringzilla/"*.hpp Sources/SQLiteExtensions/usearch/stringzilla/include/stringzilla/ +cp "${TEMP}/usearch/stringzilla/c/lib.c" Sources/SQLiteExtensions/usearch/stringzilla/c/ +cp "${TEMP}/usearch/stringzilla/LICENSE" Sources/SQLiteExtensions/usearch/stringzilla/LICENSE +cp "${TEMP}/usearch/simsimd/include/simsimd/"*.h Sources/SQLiteExtensions/usearch/simsimd/include/simsimd/ +cp "${TEMP}/usearch/simsimd/LICENSE" Sources/SQLiteExtensions/usearch/simsimd/LICENSE +cp "${TEMP}/usearch/fp16/include/fp16/"*.h Sources/SQLiteExtensions/usearch/fp16/include/fp16/ +cp "${TEMP}/usearch/fp16/LICENSE" Sources/SQLiteExtensions/usearch/fp16/LICENSE + +echo "Downloading SQLean..." +curl -sL "https://github.com/nalgeon/sqlean/archive/${SQLEAN_COMMIT}.tar.gz" \ + | tar -xz -C "${TEMP}" +mkdir -p Sources/SQLiteCustom/sqlean +cp "${TEMP}"/sqlean-*/src/sqlean.h Sources/SQLiteCustom/sqlean/ +cp "${TEMP}"/sqlean-*/src/sqlite3-uuid.c Sources/SQLiteCustom/sqlean/ +cp -R "${TEMP}"/sqlean-*/src/uuid Sources/SQLiteCustom/sqlean/ +cp "${TEMP}"/sqlean-*/src/sqlite3-text.c Sources/SQLiteCustom/sqlean/ +cp -R "${TEMP}"/sqlean-*/src/text Sources/SQLiteCustom/sqlean/ +cp "${TEMP}"/sqlean-*/LICENSE Sources/SQLiteCustom/sqlean/LICENSE + +cp "${TEMPLATES_DIR}/shim.h" Sources/SQLiteCustom/include/ +cp "${TEMPLATES_DIR}/GRDBSQLite.h" Sources/SQLiteCustom/include/ +cp "${TEMPLATES_DIR}/SQLiteExtensions/initialize-extensions.c" Sources/SQLiteExtensions/ +cp "${TEMPLATES_DIR}/SQLiteExtensions/include/initialize-extensions.h" Sources/SQLiteExtensions/include/ + +echo "" +echo "Setting up Android build..." +"${SCRIPT_DIR}/setup-android.sh"