libduckdb-sys: expose DEP_DUCKDB_INCLUDE for downstream C/C++ shims#753
Open
frhack wants to merge 1 commit intoduckdb:mainfrom
Open
libduckdb-sys: expose DEP_DUCKDB_INCLUDE for downstream C/C++ shims#753frhack wants to merge 1 commit intoduckdb:mainfrom
frhack wants to merge 1 commit intoduckdb:mainfrom
Conversation
Crates that ship their own C/C++ extension code (e.g. an
OptimizerExtension shim that #include "duckdb.hpp") need the path to
libduckdb-sys's resolved DuckDB headers at their own build time. Today
they have to glob the target tree for libduckdb-sys-<hash>/out/duckdb
or vendor a copy of the headers; both are fragile.
This change adds `links = "duckdb"` to libduckdb-sys's Cargo.toml so
its build script's metadata is exported as `DEP_DUCKDB_*` environment
variables to downstream build scripts, then emits `cargo:include=...`
from each backend that resolves a real header directory:
- build_bundled_cc.rs → <OUT_DIR>/duckdb/src/include
- build_bundled_cmake.rs → <duckdb-sources>/src/include
- build_linked::main → DUCKDB_INCLUDE_DIR / DUCKDB_LIB_DIR /
vcpkg / pkg-config / download dir
Wrapper-only mode (system DuckDB found via pkg-config without an
explicit include path) intentionally skips the emission: there's no
single directory to publish, the system header is on the default
search path already, and downstream shims can fall back to the same
default include resolution.
Downstream crates can now use:
fn main() {
let inc = std::env::var("DEP_DUCKDB_INCLUDE").unwrap();
cc::Build::new()
.cpp(true)
.file("cpp/extension_shim.cpp")
.include(&inc)
.compile("my_extension_shim");
}
No behaviour change for downstream Rust users who don't compile native
code; this only adds opt-in metadata for native build hooks.
frhack
added a commit
to typeeffect/dbfy
that referenced
this pull request
May 1, 2026
After upstream PR duckdb/duckdb-rs#753 lands in a released libduckdb-sys, our build.rs can drop the target-tree glob and read DEP_DUCKDB_INCLUDE directly. Until then we try DEP_DUCKDB_INCLUDE first (no-op against today's upstream) and fall back to the glob, so the same code path works whether the user is on stock libduckdb-sys or a future patched one.
mlafeldt
reviewed
May 4, 2026
Member
mlafeldt
left a comment
There was a problem hiding this comment.
Thanks!
Happy to merge this once you address the mentioned path bug and format your code with cargo fmt.
| println!("cargo:rerun-if-env-changed=MACOSX_DEPLOYMENT_TARGET"); | ||
|
|
||
| write_bindings(&source_dir.join("src/include"), out_path); | ||
| let include_path = source_dir.join("src/include"); |
Member
There was a problem hiding this comment.
This is currently relative but should be absolute so downstream build scripts can actually use it.
Suggested change
| let include_path = source_dir.join("src/include"); | |
| let include_path = source_dir.join("src/include").canonicalize().unwrap(); |
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.
What
Add
links = "duckdb"tolibduckdb-sys's manifest and emitcargo:include=<path>from each backend so downstream crates that compile their own C/C++ code can read the resolved DuckDB include directory fromDEP_DUCKDB_INCLUDEin their own build scripts.Why
Crates that ship native extension code (e.g. an
OptimizerExtensionshim that#include "duckdb.hpp") need access to libduckdb-sys's DuckDB headers at their own build time.Today they have to either:
target/<profile>/build/libduckdb-sys-<hash>/out/duckdb/src/includefrom theirbuild.rs, orBoth are fragile: the glob breaks across cargo versions and is awkward in cross-builds; vendoring drifts from the bundled DuckDB ABI on every
libduckdb-sysupgrade.The standard Cargo mechanism for this is the
linksdirective pluscargo:KEY=VALUEmetadata. With this PR, downstream code can simply:This unblocks downstream crates from registering things like
duckdb::OptimizerExtensionfrom their own native code without resorting to the C API (which the issue at duckdb/duckdb#19093 is still working out).Changes
crates/libduckdb-sys/Cargo.toml: addlinks = "duckdb"so build-script metadata flows to downstreamDEP_DUCKDB_*env vars.crates/libduckdb-sys/build_bundled_cc.rs: emitcargo:include=<OUT_DIR>/duckdb/src/include.crates/libduckdb-sys/build_bundled_cmake.rs: emitcargo:include=<duckdb-sources>/src/include.crates/libduckdb-sys/build.rs(thebuild_linkedpath): emitcargo:include=...derived from the resolvedHeaderLocation—DUCKDB_INCLUDE_DIR,DUCKDB_LIB_DIR, vcpkg, pkg-config, or download dir.Wrapper-only mode (system DuckDB found via pkg-config without an explicit include path) intentionally skips the emission — there's no single directory to publish; the system header is already on the default search path, and downstream shims fall through to the same default include resolution.
Behaviour change
None for existing Rust consumers — the only public-surface change is a new
linksdirective, which doesn't affect compilation of crates that don't run their ownbuild.rsagainst duckdb headers.Validation
The companion downstream project that motivated this PR (
dbfy— embedded SQL federation engine, github.com/frhack/dbfy) ships anOptimizerExtensionshim in bundled mode (--features duckdb) that needs these headers. Itsbuild.rscurrently uses the target-tree glob hack as a documented workaround; once this PR is in a release, the shim can switch to the cleanDEP_DUCKDB_INCLUDEpath.Happy to add a small test or example exercising the metadata if useful.