Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions crates/libduckdb-sys/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ homepage = { workspace = true }
keywords = { workspace = true }
readme = { workspace = true }
build = "build.rs"
# `links = "duckdb"` lets the build script publish metadata
# (`cargo:include`, `cargo:lib_dir`) that downstream crates can read
# via `DEP_DUCKDB_*` environment variables in their own build scripts.
# Required for crates that need to compile their own C/C++ code that
# `#include "duckdb.hpp"` against the bundled headers.
links = "duckdb"
categories = ["external-ffi-bindings", "database"]
description = "Native bindings to the libduckdb library, C API"
exclude = ["duckdb-sources"]
Expand Down
25 changes: 25 additions & 0 deletions crates/libduckdb-sys/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,16 @@
#[allow(unused_variables)]
let header = find_duckdb(out_dir);

// Publish the resolved include directory so downstream crates
// that compile their own C/C++ code can read it from
// `DEP_DUCKDB_INCLUDE`. Wrapper-only mode (no explicit dir
// from env / vcpkg / pkg-config / download) intentionally
// skips the emission — there's no single directory to point
// at; the system header is on the default search path already.
if let Some(include_dir) = include_dir_for(&header) {
println!("cargo:include={include_dir}");
}

#[cfg(not(feature = "buildtime_bindgen"))]
{
std::fs::copy(
Expand All @@ -138,6 +148,21 @@
}
}

/// The `HeaderLocation` enum string conversion appends a filename to
/// the path it resolved. For `cargo:include=...` we want the
/// directory itself, not a file path. Re-derive it.

Check warning on line 153 in crates/libduckdb-sys/build.rs

View workflow job for this annotation

GitHub Actions / Test Linux

Diff in /home/runner/work/duckdb-rs/duckdb-rs/crates/libduckdb-sys/build.rs
fn include_dir_for(header: &HeaderLocation) -> Option<String> {
match header {
HeaderLocation::FromEnvironment => {
env::var("DUCKDB_INCLUDE_DIR")
.or_else(|_| env::var("DUCKDB_LIB_DIR"))
.ok()
}
HeaderLocation::FromPath(path) => Some(path.clone()),
HeaderLocation::Wrapper => None,
}
}

fn link_directive() -> &'static str {
// If the user specifies DUCKDB_STATIC, do static
// linking, unless it's explicitly set to 0.
Expand Down
10 changes: 9 additions & 1 deletion crates/libduckdb-sys/build_bundled_cc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,15 @@ fn untar_archive(out_dir: &str) {
pub fn main(out_dir: &str, out_path: &Path) {
untar_archive(out_dir);

write_bindings(&Path::new(out_dir).join("duckdb/src/include"), out_path);
let include_path = Path::new(out_dir).join("duckdb/src/include");
write_bindings(&include_path, out_path);

// Publish the include directory so downstream crates that compile
// their own C/C++ code (e.g. extension shims that #include
// "duckdb.hpp") can pick it up from `DEP_DUCKDB_INCLUDE` without
// having to glob the target tree. Requires `links = "duckdb"` in
// the package manifest.
println!("cargo:include={}", include_path.display());

let manifest_file = std::fs::File::open(format!("{out_dir}/duckdb/manifest.json")).expect("manifest file");
let manifest: Manifest = serde_json::from_reader(manifest_file).expect("reading manifest file");
Expand Down
9 changes: 8 additions & 1 deletion crates/libduckdb-sys/build_bundled_cmake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,14 @@ pub fn main(_out_dir: &str, out_path: &Path) {
println!("cargo:rerun-if-env-changed=CMAKE_CXX_COMPILER_LAUNCHER");
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");
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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();

write_bindings(&include_path, out_path);

// Publish the include directory so downstream crates that compile
// their own C/C++ code can read it from `DEP_DUCKDB_INCLUDE`.
// See the matching emission in build_bundled_cc.rs.
println!("cargo:include={}", include_path.display());

if let Some(configs) = env_var("DUCKDB_EXTENSION_CONFIGS") {
if !configs.trim().is_empty() {
panic!(
Expand Down
Loading