From 825fc88c1ab52a0e23ec36159b10b5939cde2616 Mon Sep 17 00:00:00 2001 From: Joe Isaacs Date: Mon, 1 Jun 2026 19:33:04 +0100 Subject: [PATCH 1/2] fix(vortex-duckdb): make build.rs cross-platform for Windows The DuckDB extension build script was unix-only, which broke the Windows build of the duckdb-vortex extension (E0433: `std::os::unix` not found): - Drop the unconditional `use std::os::unix::fs::symlink`. The symlink of the extracted source into `crate_dir/duckdb` is only a dev/tooling convenience (the build uses the extracted `inner_dir` directly), so move it into a `#[cfg(unix)]` helper that is a no-op elsewhere. - Add the Windows targets (x86_64/aarch64-pc-windows-msvc) to the prebuilt-libduckdb download match; DuckDB ships libduckdb-windows-amd64 /-arm64.zip. Recognise duckdb.dll as a build artifact. - In compile_cpp, gate the GCC/Clang `-W*`/`-isystem` flags behind a non-MSVC check and use `/W4` + a normal include on MSVC (`cl` rejects the GNU-style flags). - Skip the `-Wl,-rpath` link arg on Windows (MSVC's linker rejects it; the DLL is resolved via PATH instead). Platform conditionals use CARGO_CFG_TARGET_OS/ENV (the build target), not `cfg!()`, which in a build script reflects the host. This lets vortex-duckdb build on windows_amd64 and windows_arm64 so the duckdb-vortex extension can opt those CI targets in. (The aws-lc-sys ARM64 assembly link failure that previously blocked windows_arm64 no longer applies: the TLS stack now resolves to rustls + ring.) Co-Authored-By: Claude Opus 4.8 (1M context) Signed-off-by: Joe Isaacs --- vortex-duckdb/build.rs | 62 ++++++++++++++++++++++++++++++++---------- 1 file changed, 48 insertions(+), 14 deletions(-) diff --git a/vortex-duckdb/build.rs b/vortex-duckdb/build.rs index 3451af771bc..ea8dc1467d9 100644 --- a/vortex-duckdb/build.rs +++ b/vortex-duckdb/build.rs @@ -8,7 +8,6 @@ use std::env; use std::fs; use std::io; -use std::os::unix::fs::symlink; use std::path::Path; use std::path::PathBuf; use std::process::Command; @@ -22,7 +21,12 @@ const DUCKDB_SOURCE_RELEASE_URL: &str = "https://github.com/duckdb/duckdb/archiv const DUCKDB_SOURCE_COMMIT_URL: &str = "https://github.com/duckdb/duckdb/archive"; const DEFAULT_DUCKDB_VERSION: &str = "1.5.3"; -const BUILD_ARTIFACTS: [&str; 3] = ["libduckdb.dylib", "libduckdb.so", "libduckdb_static.a"]; +const BUILD_ARTIFACTS: [&str; 4] = [ + "libduckdb.dylib", + "libduckdb.so", + "libduckdb_static.a", + "duckdb.dll", +]; const SOURCE_FILES: [&str; 17] = [ "cpp/client_context.cpp", @@ -178,6 +182,8 @@ fn download(version: &DuckDBVersion, library_dir: &Path) { "aarch64-apple-darwin" | "x86_64-apple-darwin" => ("osx", "universal"), "x86_64-unknown-linux-gnu" => ("linux", "amd64"), "aarch64-unknown-linux-gnu" => ("linux", "arm64"), + "x86_64-pc-windows-msvc" => ("windows", "amd64"), + "aarch64-pc-windows-msvc" => ("windows", "arm64"), _ => { println!("cargo:error=Unsupported target {target}"); exit(1); @@ -353,13 +359,21 @@ fn bindgen_c2rust(crate_dir: &Path, duckdb_include_dir: &Path) { /// Generate libvortex_duckdb.* fn compile_cpp(duckdb_include_dir: &Path) { - cc::Build::new() - .std("c++20") - .flags(["-Wall", "-Wextra", "-Wpedantic", "-Werror"]) - .cpp(true) - // We don't want compiler warnings inside duckdb headers, pass as flags - .flag("-isystem") - .flag(duckdb_include_dir) + let mut build = cc::Build::new(); + build.std("c++20").cpp(true); + if env::var("CARGO_CFG_TARGET_ENV").as_deref() == Ok("msvc") { + // MSVC's `cl` does not understand the GCC/Clang `-W*`/`-isystem` flags. Use the + // `/W4` warning level and add the DuckDB headers as a normal include. We do not + // enable `/WX`, so warnings originating in those headers don't fail the build. + build.flag("/W4").include(duckdb_include_dir); + } else { + build + .flags(["-Wall", "-Wextra", "-Wpedantic", "-Werror"]) + // We don't want compiler warnings inside duckdb headers, pass as flags + .flag("-isystem") + .flag(duckdb_include_dir); + } + build .include("include") .include("cpp/include") .files(SOURCE_FILES) @@ -396,6 +410,21 @@ fn cbindgen_rust2c(crate_dir: &Path) { } } +/// Create a convenience symlink from `duckdb_dir` to the extracted DuckDB source tree. +/// This is purely for editor/tooling navigation; the build uses the source path directly. +/// Only created on unix, where the symlink API needs no special privilege. +#[cfg(unix)] +fn symlink_duckdb_source(source_dir: &Path, duckdb_dir: &Path) { + drop(fs::remove_file(duckdb_dir)); + drop(fs::remove_dir_all(duckdb_dir)); + std::os::unix::fs::symlink(source_dir, duckdb_dir).unwrap(); +} + +/// No-op on non-unix platforms (e.g. Windows): the symlink is only a convenience and +/// Windows directory symlinks require elevated privileges. +#[cfg(not(unix))] +fn symlink_duckdb_source(_source_dir: &Path, _duckdb_dir: &Path) {} + fn main() { println!("cargo:rerun-if-env-changed=DUCKDB_VERSION"); println!("cargo:rerun-if-env-changed=VX_DUCKDB_DEBUG"); @@ -427,8 +456,12 @@ fn main() { println!("cargo:rustc-link-lib=dylib=duckdb"); // Set rpath for binaries built directly from this crate. This is not - // inherited by downstream crates. - println!("cargo:rustc-link-arg=-Wl,-rpath,{library_dir_str}"); + // inherited by downstream crates. `-Wl,-rpath` is GNU/Clang linker syntax that + // MSVC's linker rejects; on Windows the DLL is resolved via PATH / the executable + // directory instead, so skip it there. + if env::var("CARGO_CFG_TARGET_OS").as_deref() != Ok("windows") { + println!("cargo:rustc-link-arg=-Wl,-rpath,{library_dir_str}"); + } // Export the library path for downstream crates via the `links` manifest key. // Downstream crates can access this via `env::var("DEP_DUCKDB_LIB_DIR")` in their build.rs @@ -467,9 +500,10 @@ fn main() { fs::write(&extract_marker, version.to_string()).unwrap(); } - drop(fs::remove_file(&duckdb_dir)); - drop(fs::remove_dir_all(&duckdb_dir)); - symlink(&source_dir, &duckdb_dir).unwrap(); + // Convenience symlink `crate_dir/duckdb` -> extracted source, for editor/tooling + // navigation only; the build itself uses `inner_dir` below. Created on unix where + // the symlink API is privilege-free; skipped elsewhere (e.g. Windows). + symlink_duckdb_source(&source_dir, &duckdb_dir); let has_debug_env = env::var("VX_DUCKDB_DEBUG").is_ok_and(|v| matches!(v.as_str(), "1" | "true")); From 4cd6b6b67083d88eef82ba51f4a9db4d4066df65 Mon Sep 17 00:00:00 2001 From: Joe Isaacs Date: Mon, 1 Jun 2026 19:53:20 +0100 Subject: [PATCH 2/2] fix(vortex-duckdb): satisfy clippy::absolute_paths in Windows build.rs Use a #[cfg(unix)] import for std::os::unix::fs::symlink instead of the fully-qualified path, which tripped the repo's denied clippy::absolute_paths lint. The cfg gate keeps the symbol out of the Windows build. Co-Authored-By: Claude Opus 4.8 (1M context) Signed-off-by: Joe Isaacs --- vortex-duckdb/build.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/vortex-duckdb/build.rs b/vortex-duckdb/build.rs index ea8dc1467d9..0195b1dea84 100644 --- a/vortex-duckdb/build.rs +++ b/vortex-duckdb/build.rs @@ -8,6 +8,8 @@ use std::env; use std::fs; use std::io; +#[cfg(unix)] +use std::os::unix::fs::symlink; use std::path::Path; use std::path::PathBuf; use std::process::Command; @@ -417,7 +419,7 @@ fn cbindgen_rust2c(crate_dir: &Path) { fn symlink_duckdb_source(source_dir: &Path, duckdb_dir: &Path) { drop(fs::remove_file(duckdb_dir)); drop(fs::remove_dir_all(duckdb_dir)); - std::os::unix::fs::symlink(source_dir, duckdb_dir).unwrap(); + symlink(source_dir, duckdb_dir).unwrap(); } /// No-op on non-unix platforms (e.g. Windows): the symlink is only a convenience and