Skip to content

Commit be9c2fd

Browse files
authored
chore: build time vendor duckdb (#3831)
Signed-off-by: Alexander Droste <[email protected]>
1 parent 28845f5 commit be9c2fd

File tree

7 files changed

+96
-27
lines changed

7 files changed

+96
-27
lines changed

.gitmodules

Lines changed: 0 additions & 3 deletions
This file was deleted.

bench-vortex/build.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ use std::path::PathBuf;
2222
/// static lib is not self-contained. This means that it includes symbols which
2323
/// are not defined as part of the static library.
2424
fn main() {
25-
const DUCKDB_VERSION: &str = "v1.3.1";
25+
const DUCKDB_VERSION: &str = "v1.3.2";
2626
let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
2727
let target_dir = manifest_dir.parent().unwrap().join("target");
28-
let lib_path = target_dir.join(format!("duckdb-{DUCKDB_VERSION}"));
28+
let lib_path = target_dir.join(format!("duckdb-lib-{DUCKDB_VERSION}"));
2929
println!("cargo:rustc-link-arg=-Wl,-rpath,{}", lib_path.display());
3030
}

vortex-duckdb/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,6 @@
22
# version pinned as part of the lock file, it can generate different output
33
# across machines. rust-bindgen loads libclang dynamically from a system-wide path.
44
src/cpp.rs
5+
6+
# Symlinked DuckDB source is ignored. It is downloaded, extracted and symlinked as part of build.rs
7+
duckdb

vortex-duckdb/build.rs

Lines changed: 89 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@
66
use std::path::PathBuf;
77
use std::{env, fs};
88

9-
const DUCKDB_VERSION: &str = "v1.3.1";
9+
const DUCKDB_VERSION: &str = "1.3.2";
1010
const DUCKDB_BASE_URL: &str = "https://github.com/duckdb/duckdb/releases/download";
1111

12-
fn download_duckdb_archive() -> Result<PathBuf, Box<dyn std::error::Error>> {
12+
fn download_duckdb_lib_archive() -> Result<PathBuf, Box<dyn std::error::Error>> {
1313
let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR")?);
1414
let target_dir = manifest_dir.parent().unwrap().join("target");
15-
let duckdb_dir = target_dir.join(format!("duckdb-{DUCKDB_VERSION}"));
15+
let duckdb_dir = target_dir.join(format!("duckdb-lib-v{DUCKDB_VERSION}"));
1616

1717
let target = env::var("TARGET")?;
1818
let (platform, arch) = match target.as_str() {
@@ -24,7 +24,7 @@ fn download_duckdb_archive() -> Result<PathBuf, Box<dyn std::error::Error>> {
2424
};
2525

2626
let archive_name = format!("libduckdb-{platform}-{arch}.zip");
27-
let url = format!("{DUCKDB_BASE_URL}/{DUCKDB_VERSION}/{archive_name}");
27+
let url = format!("{DUCKDB_BASE_URL}/v{DUCKDB_VERSION}/{archive_name}");
2828
let archive_path = duckdb_dir.join(&archive_name);
2929

3030
// Create directory if it doesn't exist.
@@ -43,29 +43,95 @@ fn download_duckdb_archive() -> Result<PathBuf, Box<dyn std::error::Error>> {
4343
}
4444

4545
fn extract_duckdb_libraries(archive_path: PathBuf) -> Result<PathBuf, Box<dyn std::error::Error>> {
46-
let duckdb_dir = archive_path
46+
let duckdb_lib_dir = archive_path
4747
.parent()
4848
.ok_or("Invalid archive path")?
4949
.to_path_buf();
5050

5151
// Check if already extracted. The archive for Linux only contains a .so library, macOS only .dylib.
52-
if duckdb_dir.join("libduckdb.dylib").exists() || duckdb_dir.join("libduckdb.so").exists() {
52+
if duckdb_lib_dir.join("libduckdb.dylib").exists()
53+
|| duckdb_lib_dir.join("libduckdb.so").exists()
54+
{
5355
println!("DuckDB libraries already extracted, skipping extraction");
54-
return Ok(duckdb_dir);
56+
return Ok(duckdb_lib_dir);
5557
}
5658

5759
let file = fs::File::open(&archive_path)?;
5860
let mut archive = zip::ZipArchive::new(file)?;
59-
archive.extract(&duckdb_dir)?;
60-
println!("Extracting DuckDB libraries to {}", duckdb_dir.display());
61+
archive.extract(&duckdb_lib_dir)?;
62+
println!(
63+
"Extracting DuckDB libraries to {}",
64+
duckdb_lib_dir.display()
65+
);
6166

62-
Ok(duckdb_dir)
67+
Ok(duckdb_lib_dir)
68+
}
69+
70+
fn download_duckdb_source_archive() -> Result<PathBuf, Box<dyn std::error::Error>> {
71+
let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR")?);
72+
let target_dir = manifest_dir.parent().unwrap().join("target");
73+
let duckdb_source_dir = target_dir.join(format!("duckdb-source-v{DUCKDB_VERSION}"));
74+
let archive_name = format!("duckdb-source-v{DUCKDB_VERSION}.zip");
75+
let url = format!("https://github.com/duckdb/duckdb/archive/refs/tags/v{DUCKDB_VERSION}.zip");
76+
let archive_path = duckdb_source_dir.join(&archive_name);
77+
78+
// Create directory if it doesn't exist.
79+
fs::create_dir_all(&duckdb_source_dir)?;
80+
81+
if !archive_path.exists() {
82+
println!("Downloading DuckDB source code from {url}");
83+
let response = reqwest::blocking::get(&url)?;
84+
fs::write(&archive_path, &response.bytes()?)?;
85+
println!("Downloaded to {}", archive_path.display());
86+
} else {
87+
println!("Source archive already exists, skipping download");
88+
}
89+
90+
Ok(archive_path)
91+
}
92+
93+
fn extract_duckdb_source(archive_path: PathBuf) -> Result<PathBuf, Box<dyn std::error::Error>> {
94+
let duckdb_source_dir = archive_path
95+
.parent()
96+
.ok_or("Invalid archive path")?
97+
.to_path_buf();
98+
99+
// Check if the source is already extracted.
100+
if duckdb_source_dir
101+
.join(format!("duckdb-{DUCKDB_VERSION}/CMakeLists.txt"))
102+
.exists()
103+
{
104+
println!("DuckDB source already extracted, skipping extraction");
105+
return Ok(duckdb_source_dir);
106+
}
107+
108+
let file = fs::File::open(&archive_path)?;
109+
let mut archive = zip::ZipArchive::new(file)?;
110+
archive.extract(&duckdb_source_dir)?;
111+
println!(
112+
"Extracting DuckDB source to {}",
113+
duckdb_source_dir.display()
114+
);
115+
116+
Ok(duckdb_source_dir)
63117
}
64118

65119
fn main() {
66120
let crate_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
67121
let duckdb_repo = crate_dir.join("duckdb");
68122

123+
// Download and extract prebuilt DuckDB libraries.
124+
let zip_lib_path = download_duckdb_lib_archive().unwrap();
125+
let extraced_lib_path = extract_duckdb_libraries(zip_lib_path).unwrap();
126+
127+
// Download, extract and symlink DuckDB source code.
128+
let zip_source_path = download_duckdb_source_archive().unwrap();
129+
let extracted_source_path = extract_duckdb_source(zip_source_path).unwrap();
130+
if duckdb_repo.exists() {
131+
fs::remove_file(&duckdb_repo).unwrap();
132+
}
133+
std::os::unix::fs::symlink(&extracted_source_path, &duckdb_repo).unwrap();
134+
69135
// Generate the _imported_ bindings from our C++ code.
70136
bindgen::Builder::default()
71137
.header("cpp/include/duckdb_vx.h")
@@ -81,7 +147,10 @@ fn main() {
81147
//.generate_cstr(true) // This emits invalid syntax and breaks the Rust formatter
82148
.clang_arg(format!(
83149
"-I{}",
84-
duckdb_repo.join("src/include").to_str().unwrap()
150+
duckdb_repo
151+
.join(format!("duckdb-{DUCKDB_VERSION}/src/include"))
152+
.to_str()
153+
.unwrap()
85154
))
86155
.clang_arg(format!(
87156
"-I{}",
@@ -97,14 +166,16 @@ fn main() {
97166
.write_to_file(crate_dir.join("src/cpp.rs"))
98167
.expect("Couldn't write bindings!");
99168

100-
// Download and extract prebuilt DuckDB libraries.
101-
let zip_path = download_duckdb_archive().unwrap();
102-
let lib_path = extract_duckdb_libraries(zip_path).unwrap();
103-
104169
// Link against DuckDB dylib.
105-
println!("cargo:rustc-link-search=native={}", lib_path.display());
170+
println!(
171+
"cargo:rustc-link-search=native={}",
172+
extraced_lib_path.display()
173+
);
106174
println!("cargo:rustc-link-lib=dylib=duckdb");
107-
println!("cargo:rustc-link-arg=-Wl,-rpath,{}", lib_path.display());
175+
println!(
176+
"cargo:rustc-link-arg=-Wl,-rpath,{}",
177+
extraced_lib_path.display()
178+
);
108179

109180
if env::var("TARGET").unwrap().contains("linux") {
110181
println!("cargo:rustc-link-lib=stdc++");
@@ -119,7 +190,7 @@ fn main() {
119190
.flag("-Wno-c++20-designator")
120191
.flag("-Wno-unused-parameter")
121192
// We include DuckDB headers from the DuckDB extension submodule.
122-
.include(duckdb_repo.join("src/include"))
193+
.include(duckdb_repo.join(format!("duckdb-{DUCKDB_VERSION}/src/include")))
123194
.include("cpp/include")
124195
.file("cpp/copy_function.cpp")
125196
.file("cpp/data.cpp")

vortex-duckdb/cpp/CMakeLists.txt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,7 @@ endif()
2424
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic -Wno-unused-parameter -Wno-c++20-designator")
2525

2626
# Include directories
27-
include_directories(./include)
28-
include_directories(../duckdb/src/include)
27+
include_directories(include ../duckdb/src/include)
2928

3029
# Add library with source files
3130
add_library(vortex

vortex-duckdb/cpp/logical_type.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
#include "duckdb_vx.h"
77
#include "duckdb_vx/logical_type.h"
88

9-
#include "../duckdb/src/include/duckdb/common/types.hpp"
9+
#include "duckdb/common/types.hpp"
1010
#include <cassert>
1111

1212
duckdb_logical_type duckdb_vx_logical_type_copy(duckdb_logical_type ty) {

vortex-duckdb/duckdb

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)