Skip to content

Compile SQLite from a vendored amalgamation instead of downloading it - #99

Merged
aquasolterra merged 1 commit into
mainfrom
compile-sqlite
Oct 4, 2026
Merged

aquasolterra merged 1 commit into
mainfrom
compile-sqlite

Conversation

@aquasolterra

Copy link
Copy Markdown
Member

F-Droid requires native libraries to be built from source, and a maintainer confirmed on fdroiddata!47901 that this applies to the libsqlite3.so that package:sqlite3's build hook downloads from GitHub. Because our published APKs are verified against F-Droid's build, the release build has to compile SQLite too, so the source lives here.

What changes

  • third_party/sqlite3/: the unmodified SQLite 3.53.4 amalgamation (sqlite3.c, sqlite3.h), checked against the SHA3-256 sqlite.org publishes. 3.53.4 is also what package:sqlite3 3.7.0 ships prebuilt, so SQLite itself does not change.
  • pubspec.yaml: hooks.user_defines.sqlite3 with source: source, default compile options left on.
  • tool/update_sqlite.sh: takes the current release off sqlite.org, refuses an archive that does not match the published hash, replaces the two files, and rewrites the provenance block in the README. Needed because bumping package:sqlite3 no longer moves the SQLite version, and Dependabot cannot see the vendored copy.
  • CI: new step in the Android job, Check SQLite was compiled, not downloaded.
  • .gitattributes marks third_party/** as vendored, so GitHub's language statistics are not dominated by 9 MB of C.
  • AGENTS.md, SECURITY.md, docs/fdroid.md, CHANGELOG.

Measured

  • Two cold release builds (flutter clean each time) produce byte-identical APKs for all three ABIs.
  • The compiled library has no GNU build ID and no embedded paths, the two things that made libdartjni.so non-reproducible, so no extra linker flag is needed.
  • Compiled with NDK r28c, the version the app pins and the F-Droid recipe uses.
  • Cost: 10–22 KB per ABI; about one minute more on a cold release build (198 s vs. 139 s on main). The hook runner caches the result, so incremental builds pay nothing.
  • main builds create three download-* directories under .dart_tool/hooks_runner; this branch creates none, which is what the CI step checks.
  • flutter test (1606 tests), flutter analyze, dart format: all pass. The host library used by the tests is compiled from the vendored copy too.
  • tool/update_sqlite.sh tested end to end against a copy whose version was wound back to 3.53.3: it restored both files and the README block byte for byte.

Not yet verified

The Linux and Windows builds now compile SQLite as well. Linux is covered by the tests above; Windows can only be checked by this PR's CI.

After merging

A new release (the reviewer asked for a new tag so the reference APKs match), then the F-Droid recipe is updated and all three ABIs are re-verified with fdroid build before pushing to the MR.

Supersedes #45, whose branch predates 57 commits on main and argued that F-Droid would probably not mind.

🤖 Generated with Claude Code

package:sqlite3's build hook downloads a prebuilt libsqlite3.so per ABI
from its GitHub releases unless told otherwise, and that binary is what
the APK shipped. F-Droid requires native libraries built from source; a
maintainer confirmed it applies here (fdroiddata!47901). Because the
published APKs are verified against F-Droid's build, compiling only in
the recipe would break that match, so the copy lives here and the release
build compiles it too.

third_party/sqlite3 holds the unmodified 3.53.4 amalgamation, checked
against the SHA3-256 sqlite.org publishes, and pubspec.yaml points the
hook at it with the default compile options left on. 3.53.4 is also what
package:sqlite3 3.7.0 ships prebuilt, so SQLite itself does not change.

Bumping package:sqlite3 no longer moves the SQLite version, so
tool/update_sqlite.sh takes the current release off sqlite.org, refuses
an archive that does not match the published hash, and rewrites the
provenance block in the README. Tested end to end against a copy whose
version was wound back.

Measured: two cold release builds give byte-identical APKs, and the
library carries no GNU build ID and no embedded path, so the verified
builds need no extra flag. It is compiled with the NDK the app pins
(r28c, as the recipe does). Cost: 10-22 KB per ABI, and about a minute
on a cold build (198 s against 139 s); the hook caches the result. A new
CI step fails an Android build that downloads SQLite again.

Supersedes #45, whose branch predates 57 commits on main and argued that
F-Droid would probably not mind.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@codecov

codecov Bot commented Oct 4, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@aquasolterra
aquasolterra merged commit 96fa7b7 into main Oct 4, 2026
5 checks passed
@aquasolterra
aquasolterra deleted the compile-sqlite branch October 4, 2026 19:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant