Skip to content

Embed native SQLite (e_sqlite3) into the single-file binary; release 0.34.2 - #151

Merged
M0LTE merged 5 commits into
masterfrom
claude/sqlite-library-loading-u80u2u
Jun 21, 2026
Merged

Embed native SQLite (e_sqlite3) into the single-file binary; release 0.34.2#151
M0LTE merged 5 commits into
masterfrom
claude/sqlite-library-loading-u80u2u

Conversation

@M0LTE

@M0LTE M0LTE commented Jun 21, 2026

Copy link
Copy Markdown
Collaborator

Problem

An early adopter's re-installed daemon crashed on first DB touch:

Unhandled exception. System.TypeInitializationException: The type initializer for 'SQLite.SQLiteConnection' threw an exception.
 ---> System.DllNotFoundException: Unable to load shared library 'e_sqlite3' or one of its dependencies.
/opt/dapps/e_sqlite3.so: cannot open shared object file: No such file or directory
/opt/dapps/libe_sqlite3.so: cannot open shared object file: No such file or directory
...
   at SQLitePCL.Batteries_V2.Init()
   at SQLite.SQLiteConnection..cctor()
   at dapps.core.Services.DbStartup.EnsureSchemaAndSeed(ILogger logger)

Root cause

A plain dotnet publish -p:PublishSingleFile=true (the build-from-source / hand-rolled path) emits libe_sqlite3.so as a sibling file next to the exe rather than inside it. DAPPS ships as one downloaded binary — docs/install.sh drops only /opt/dapps/dapps, nothing alongside — so the native lib is absent at runtime and SQLitePCLRaw's static init throws the first time the daemon opens the DB.

The probe paths in the log are the giveaway: they list only /opt/dapps/... (no /tmp/.net/... extraction dir) while Main is running — the signature of a single-file build with neither self-extract flag. CI and scripts/dev-push both pass those flags, but they lived only in those two scripts, so any other publish path silently produced a broken binary.

Fix

Move IncludeNativeLibrariesForSelfExtract + IncludeAllContentForSelfExtract into dapps.core.csproj (conditioned on PublishSingleFile), so every publish path bakes SQLite — and the rest of the native deps — into the binary. The properties are inert for normal build/run/test, so dev and the UI-test fixture's output paths are unchanged.

Also bumps <Version> to 0.34.2 so CI cuts a release carrying the fix (no bump → no release → install.sh keeps serving the old binary).

Verification

Reproduced the exact failure and confirmed the fix locally (.NET 8, linux-x64):

  • Before: copying just the binary from a flagless publish → the exact TypeInitializationException / DllNotFoundException with the /opt/dapps/...e_sqlite3 probes.
  • After: a flagless -p:PublishSingleFile=true publish embeds the lib (no sibling .so); the lone copied binary boots and creates dapps.db standalone — the very code path (DbStartup.EnsureSchemaAndSeed) that was crashing.
  • Normal dotnet build succeeds with the dll still at bin/Release/net8.0/, so the UI-test fixture is unaffected.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Q2kdbKAG4JQTLmf1eSuhtq


Generated by Claude Code

claude added 3 commits June 21, 2026 09:05
…oject level

A re-installed daemon crashed on first DB touch with:

  TypeInitializationException: 'SQLite.SQLiteConnection'
   ---> DllNotFoundException: Unable to load shared library 'e_sqlite3'
        /opt/dapps/e_sqlite3.so: cannot open shared object file: No such file

Root cause: a plain `dotnet publish -p:PublishSingleFile=true` (the
build-from-source / hand-rolled path) emits libe_sqlite3.so as a SIBLING
file next to the exe rather than inside it. DAPPS ships as one downloaded
binary — docs/install.sh drops only /opt/dapps/dapps, nothing alongside —
so the native lib is absent at runtime and SQLitePCLRaw's static init
throws the first time the daemon opens the DB.

The self-extract publish flags previously lived only in the CI and
dev-push publish args, so any other publish path produced a silently
broken single binary. Move IncludeNativeLibrariesForSelfExtract +
IncludeAllContentForSelfExtract into dapps.core.csproj (conditioned on
PublishSingleFile) so every publish path bakes SQLite — and the rest of
the native deps — into the binary. The properties are inert for normal
build/run/test, so dev and the UI-test fixture's output paths are
unchanged.

Reproduced the exact failure and verified the fix: a flagless
`-p:PublishSingleFile=true` publish now embeds the native lib (no sibling
.so), and the lone copied binary boots and creates dapps.db standalone.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q2kdbKAG4JQTLmf1eSuhtq
Bump <Version> so CI cuts a release carrying the e_sqlite3 self-extract
fix. Without a version bump the merge lands as a normal commit and no
release is published, leaving install.sh serving the old binary.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q2kdbKAG4JQTLmf1eSuhtq
…t silently skip a release

The test job gates releases (build/release run only when its
should_release output is true, and a failed step short-circuits the
job), so one intermittent test failure strands a version-bumped release:
the run goes red but no binary publishes. The suite has a known ~1/683
broker-port bind-race flake that must not be able to block a real
release.

Run the suite up to 3 times: a transient flake heals on a later attempt
and the release proceeds; a genuine regression fails all attempts and
loudly blocks it. On each failed attempt, dump the per-test results log
to the console - under `dotnet test`, MTP writes the failing test NAME
only to that log file (stdout has just the summary), so this makes the
flake greppable in the job log instead of requiring an artifact download.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q2kdbKAG4JQTLmf1eSuhtq
claude added 2 commits June 21, 2026 09:47
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q2kdbKAG4JQTLmf1eSuhtq
…env from parallel tests

Fixes the intermittent CI flake (GatewayPathBaseTests.*_UrlSurfaces*
asserting 200 but getting 302). Root cause is test env-var bleed, not the
broker-port race first guessed in #152:

DbStartupTests and Rhpv2InboundServiceTests set DAPPS_*/PDN_* vars
process-wide via Environment.SetEnvironmentVariable. They're in a
different xUnit collection, so they run in parallel with
GatewayPathBaseTests, which spawns `dotnet dapps.core.dll` as a
subprocess - and the subprocess inherits this process's environment.
When e.g. PDN_NODE_CALLSIGN is set at spawn time, DbStartup in the child
derives a real callsign, so the fresh-install /Setup wizard's OnGet sees
a configured callsign and 302s to / instead of rendering the bearer step,
failing the assertion for 200. Purely a function of parallel timing,
which is why it was intermittent and why retrying the whole suite never
healed it (the polluting tests re-run on every attempt).

Scrub all inherited DAPPS_*/PDN_* keys from the subprocess environment
before launch so it always boots a pristine first-run state regardless of
what sibling tests do to the shared process env.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q2kdbKAG4JQTLmf1eSuhtq
@M0LTE
M0LTE merged commit b18b283 into master Jun 21, 2026
4 checks passed
M0LTE added a commit that referenced this pull request Jun 21, 2026
Bump <Version> to 0.34.3 so CI publishes a real release carrying the
embedded-SQLite single-file fix from #151. v0.34.2 was already taken by a
manual pre-fix release, so the post-merge run skipped publishing.
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.

2 participants