Firebird Adds Optional Static fbclient Libraries, Including Symbol-Collision Prevention
Firebird’s client library, libfbclient / fbclient.dll, has always been distributed exclusively as a shared library. PR #9104 by Adriano dos Santos Fernandes, merged into the Firebird source tree on July 24, 2026, changes that: it introduces an optional, non-default static archive (libfbclient.a on POSIX, fbclient_static.lib on Windows) for applications that need to link the client library statically instead of loading it as a shared object/DLL.
Why static linking wasn’t offered before
The blocker wasn’t packaging — it was memory management. Firebird overrides the global C++ operators operator new, operator new[], operator delete, and operator delete[] (in src/common/classes/alloc.cpp) so that any bare, non-pool allocation inside Firebird is routed through its own internal memory pool.
In the shared library, this is harmless: a POSIX version script (and a Windows .def file) keeps those overridden symbols hidden, so an application linking against libfbclient.so or fbclient.dll keeps its own global allocator untouched.
A static archive has no such boundary. Its object files get merged directly into the host application at link time, so the linker would silently resolve the host’s own bare new/delete calls to Firebird’s internal definitions — hijacking the host application’s memory allocation without any warning. That’s a nasty, hard-to-diagnose class of bug, and it’s exactly why a static build was never shipped.
The fix: rename every internal symbol at the archive level
Rather than hand-maintain a list of symbols to hide, the PR takes a systematic approach: every internal global symbol not part of Firebird’s public API gets renamed with a __fbclient_ prefix as a post-processing step on the compiled archive. This covers the global operators, decNumber symbols, C++ mangled names, vtables, typeinfo, guard variables — everything — generated automatically from the existing export list rather than curated by hand.
On POSIX (Linux and macOS), this happens in two steps:
- Archive slimming —
ld -rwith-uflags seeded from every symbol inbuilds/posix/firebird.verspulls in only the archive members actually reachable from the public API, using cross-reference output (--crefon ELF,-mapon Darwin) to identify and repack just those members. - Symbol renaming —
objcopy --redefine-syms(GNUobjcopyon Linux,llvm-objcopyon macOS) renames every non-API global symbol to a__fbclient_-prefixed name, using a rename map generated automatically vianm --defined-only -g.
On Windows, a new fix_fbclient_static.bat parses builds/win32/defs/firebird.def for the public API, runs llvm-nm on every object file to collect defined symbols, and applies the same kind of rename map with llvm-objcopy --redefine-syms.
Regular pool-based allocation via FB_NEW / FB_NEW_POOL — the pattern used throughout the Firebird codebase — was never affected by any of this, since it never touched the global operators in the first place.
A side effect: no DllMain on Windows
A statically linked fbclient has no separate DLL module, so DllMain never runs for it. The one real functional gap this closes is per-thread cleanup, previously tied to DllMain‘s DLL_THREAD_DETACH notification. The PR adds a new ThreadCleanup class using Fiber-Local Storage (FlsAlloc/FlsSetValue/FlsFree) on Windows, mirroring what pthread_key_create‘s destructor already gives the POSIX build for free.
Building it
POSIX:
make -C temp/debug TARGET=Debug client_static
produces <firebird>/lib/libfbclient.a. Most third-party dependencies (tommath, tomcrypt) still need to be linked separately; decNumber/libdecFloat is merged directly into the archive.
Windows:
builds\win32\make_all.bat CLIENT_ONLY=STATIC
builds yvalve as fbclient_static.lib under new DebugStatic/ReleaseStatic configurations, then runs the symbol-fixup script automatically.
What’s in the diff
25 files changed, +2168/-268 lines, across three commits, including new CI workflows (.github/workflows/static-build.yml) to build and validate the static client on Linux, macOS, and Windows, and a new, thorough doc/README.StaticClient.md covering the rationale, build steps, and verification commands for both platforms.
For any project embedding Firebird’s client library directly into a host binary, this closes a real gap — and it does it without punting the symbol-collision risk onto the integrator.
Source: FirebirdSQL/firebird PR #9104. Also posted on Mariuz’s Blog.

