Link duckdb_generated_extension_loader when linking duckdb statically - #63
Merged
Conversation
Homebrew's libduckdb_static.a requires the companion
libduckdb_generated_extension_loader.a archive, which provides the init
hooks for duckdb's own statically-bundled extensions (json, parquet,
icu, autocomplete, core_functions). Without it, statically linking the
duckdb extension fails with undefined symbols like
duckdb::DuckDB::LoadStaticExtension<duckdb::ParquetExtension>().
Link the exported duckdb_generated_extension_loader target after
${DuckDB_LIBRARIES} whenever DuckDB_USE_STATIC_LIBS is set, followed by
each bundled extension archive listed in DuckDB_EXTENSIONS (order
matters: the loader references symbols from both).
adsharma
added a commit
to LadybugDB/ladybug
that referenced
this pull request
Aug 22, 2026
Both ladybug's third_party/mbedtls and a statically-linked duckdb (libduckdb_static.a) bundle mbedtls with plain, unprefixed mbedtls_* symbols. When both end up on one link line (e.g. GEN=Ninja make shell EXTENSION_STATIC_LINK_LIST='httpfs'), the linker reports ~19 duplicate symbol errors for _mbedtls_cipher_*. Fix by wrapping our vendored copy in namespace lbug_mbedtls: - third_party/ports/mbedtls/do-patch.py (new): port patch script, following the zstd port pattern. It renames .c -> .cpp, strips the now-dead extern "C" guards (the copy is compiled as C++ everywhere), and wraps top-level code segments in balanced namespace pairs. Segmentation tracks preprocessor conditional context and brace depth per line, so sibling conditional branches (MBEDTLS_AES_ALT vs MBEDTLS_SELF_TEST) and mid-declaration conditionals (lone 'static' followed by a conditional attribute block) stay balanced. It also absorbs the previously-missing format_c_to_cpp.py step, making the port runnable again. - ports/mbedtls/Makefile: invoke do-patch.py during build. - third_party/mbedtls: vendored sources regenerated via the script (57 files; only namespace pairs and extern "C" removals). Public headers re-expose names via 'using namespace lbug_mbedtls', so in-tree consumers (src/common/sha256.cpp, extension/httpfs/src/crypto.cpp) are unchanged. Requires LadybugDB/extensions#63 (submodule bump included here). Verified with GEN=Ninja make shell EXTENSION_STATIC_LINK_LIST='httpfs': the link succeeds, libmbedtls.a exports zero plain _mbedtls_* symbols, and the shell passes a smoke query.
adsharma
added a commit
to LadybugDB/ladybug
that referenced
this pull request
Aug 22, 2026
Both ladybug's third_party/mbedtls and a statically-linked duckdb (libduckdb_static.a) bundle mbedtls with plain, unprefixed mbedtls_* symbols. When both end up on one link line (e.g. GEN=Ninja make shell EXTENSION_STATIC_LINK_LIST='httpfs'), the linker reports ~19 duplicate symbol errors for _mbedtls_cipher_*. Fix by wrapping our vendored copy in namespace lbug_mbedtls: - third_party/ports/mbedtls/do-patch.py (new): port patch script, following the zstd port pattern. It renames .c -> .cpp, strips the now-dead extern "C" guards (the copy is compiled as C++ everywhere), and wraps top-level code segments in balanced namespace pairs. Segmentation tracks preprocessor conditional context and brace depth per line, so sibling conditional branches (MBEDTLS_AES_ALT vs MBEDTLS_SELF_TEST) and mid-declaration conditionals (lone 'static' followed by a conditional attribute block) stay balanced. It also absorbs the previously-missing format_c_to_cpp.py step, making the port runnable again. - ports/mbedtls/Makefile: invoke do-patch.py during build. - third_party/mbedtls: vendored sources regenerated via the script (57 files; only namespace pairs and extern "C" removals). Public headers re-expose names via 'using namespace lbug_mbedtls', so in-tree consumers (src/common/sha256.cpp, extension/httpfs/src/crypto.cpp) are unchanged. Requires LadybugDB/extensions#63 (submodule bump included here). Verified with GEN=Ninja make shell EXTENSION_STATIC_LINK_LIST='httpfs': the link succeeds, libmbedtls.a exports zero plain _mbedtls_* symbols, and the shell passes a smoke query.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Building with
GEN=Ninja make shell EXTENSION_STATIC_LINK_LIST='httpfs'(which flips all extensions to static linking) failed at the final link with undefined symbols:Root cause
When
DuckDB_USE_STATIC_LIBS=ON,find_package(DuckDB)resolvesDuckDB_LIBRARIESto justduckdb_static. But a statically-linked duckdb requires its companionlibduckdb_generated_extension_loader.aarchive (which providesDuckDB::LoadStaticExtension<T>hooks for duckdb's own bundled extensions), and the loader in turn references the bundled extension archives (json,parquet,icu,autocomplete,core_functions), all exported by the DuckDB CMake package.Fix
When
DuckDB_USE_STATIC_LIBSis set, linkduckdb_generated_extension_loaderafter${DuckDB_LIBRARIES}, followed by every${ext}_extensiontarget listed inDuckDB_EXTENSIONS. Order matters: the loader references symbols from bothduckdb_staticand the extension archives.Verified with
GEN=Ninja make shell EXTENSION_STATIC_LINK_LIST='httpfs'against Homebrew duckdb 1.5.1.