Skip to content
Merged
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
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ jobs:
runs-on: ubuntu-latest
env:
LBUG_VERSION: main
LBUG_SOURCE_DIR: lbug-src
LBUG_BUILD_FROM_SOURCE: 1
CARGO_HOME: ${{ github.workspace }}/.cargo
RUSTC_WRAPPER: sccache
SCCACHE_GHA_ENABLED: "true"
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
target
.cache
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "lbug"
version = "0.11.1"
version = "0.16.0"
description = "An in-process property graph database management system built for query speed and scalability"
keywords = ["database", "graph", "ffi"]
readme = "lbug-src/README.md"
Expand All @@ -15,6 +15,7 @@ edition = "2021"
# Only include files required to build to keep the crate size small
include = [
"build.rs",
"/scripts",
"/src",
"/include",
# If more files are added to lbug-src, they should also be added to the rerun-if-changed
Expand Down
153 changes: 140 additions & 13 deletions build.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::env;
use std::path::{Path, PathBuf};

const PREBUILT_LIB_DIR: &str = ".cache/lbug-prebuilt/lib";

fn link_mode() -> &'static str {
if env::var("LBUG_SHARED").is_ok() {
"dylib"
Expand All @@ -13,7 +15,7 @@ fn get_target() -> String {
env::var("PROFILE").unwrap()
}

fn link_libraries() {
fn link_libraries(link_bundled_deps: bool, prebuilt_lbug_root: Option<&Path>) {
// This also needs to be set by any crates using it if they want to use extensions
if !cfg!(windows) && link_mode() == "static" {
println!("cargo:rustc-link-arg=-rdynamic");
Expand All @@ -38,6 +40,13 @@ fn link_libraries() {
println!("cargo:rustc-link-lib=dylib=stdc++");
}

if !link_bundled_deps {
if let Some(lbug_root) = prebuilt_lbug_root {
link_prebuilt_libraries(lbug_root);
}
return;
}

for lib in [
"utf8proc",
"antlr4_cypher",
Expand Down Expand Up @@ -66,12 +75,125 @@ fn link_libraries() {
}
}

fn link_prebuilt_libraries(lbug_root: &Path) {
let build_dir = lbug_root.join("build").join("release");
for (dir, lib) in [
("antlr4_cypher", "antlr4_cypher"),
("antlr4_runtime", "antlr4_runtime"),
("brotli", "brotlidec"),
("brotli", "brotlicommon"),
("utf8proc", "utf8proc"),
("re2", "re2"),
("fastpfor", "fastpfor"),
("parquet", "parquet"),
("snappy", "snappy"),
("thrift", "thrift"),
("yyjson", "yyjson"),
("zstd", "zstd"),
("miniz", "miniz"),
("mbedtls", "mbedtls"),
("lz4", "lz4"),
("roaring_bitmap", "roaring_bitmap"),
("simsimd", "simsimd"),
] {
let lib_dir = build_dir.join("third_party").join(dir);
let lib_path = lib_dir.join(format!("lib{lib}.a"));
if lib_path.exists() {
println!("cargo:rustc-link-search=native={}", lib_dir.display());
println!("cargo:rustc-link-lib=static={lib}");
}
}
}

fn manifest_dir() -> PathBuf {
PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap())
}

fn static_lbug_file_name() -> &'static str {
if cfg!(windows) {
"lbug.lib"
} else {
"liblbug.a"
}
}

fn try_download_prebuilt_lbug(manifest_dir: &Path) -> bool {
if link_mode() != "static" {
return false;
}
if env::var("LBUG_BUILD_FROM_SOURCE").is_ok() || env::var("LBUG_RUST_BUILD_FROM_SOURCE").is_ok()
{
println!("cargo:warning=Skipping prebuilt liblbug because source build was requested");
return false;
}

let lib_dir = manifest_dir.join(PREBUILT_LIB_DIR);
let lib_path = lib_dir.join(static_lbug_file_name());
if lib_path.exists() {
return true;
}

let script = manifest_dir.join("scripts").join("download_lbug.sh");
if !script.exists() {
return false;
}

println!("cargo:warning=Downloading prebuilt liblbug static archive...");
let status = std::process::Command::new("sh")
.arg(&script)
.current_dir(manifest_dir)
.status();

match status {
Ok(status) if status.success() && lib_path.exists() => true,
Ok(status) => {
println!(
"cargo:warning=Prebuilt liblbug download failed with status {status}; building from source"
);
false
}
Err(error) => {
println!(
"cargo:warning=Could not run prebuilt liblbug downloader ({error}); building from source"
);
false
}
}
}

fn use_prebuilt_lbug(manifest_dir: &Path) -> Option<(Vec<PathBuf>, PathBuf)> {
if !try_download_prebuilt_lbug(manifest_dir) {
return None;
}

let lib_dir = manifest_dir.join(PREBUILT_LIB_DIR);
let lbug_root = get_lbug_root();
println!("cargo:rustc-link-search=native={}", lib_dir.display());
println!("cargo:rerun-if-changed={}", lib_dir.display());
println!(
"cargo:warning=Using prebuilt liblbug from {}",
lib_dir.join(static_lbug_file_name()).display()
);
Some((vec![lib_dir, lbug_root.join("src/include")], lbug_root))
}

fn get_lbug_root() -> PathBuf {
let manifest_dir_str = std::env::var("CARGO_MANIFEST_DIR").unwrap();
let manifest_dir = Path::new(&manifest_dir_str);
let root = manifest_dir.join("lbug-src");
if root.is_symlink() || root.is_dir() {
return root;
let manifest_dir = manifest_dir();
if let Ok(lbug_source_dir) = std::env::var("LBUG_SOURCE_DIR") {
let root = PathBuf::from(lbug_source_dir);
if root.is_symlink() || root.is_dir() {
return root;
}
}

let sibling_root = manifest_dir.join("../ladybug");
if sibling_root.is_symlink() || sibling_root.is_dir() {
return sibling_root;
}

let bundled_root = manifest_dir.join("lbug-src");
if bundled_root.is_symlink() || bundled_root.is_dir() {
return bundled_root;
}
if cfg!(windows) {
return manifest_dir.join("../..");
Expand Down Expand Up @@ -99,7 +221,7 @@ fn get_lbug_root() -> PathBuf {
.args(["-sL", &url])
.arg("-o")
.arg("ladybug.tar.gz")
.current_dir(manifest_dir)
.current_dir(&manifest_dir)
.output()
.expect("Failed to download ladybug source");

Expand All @@ -116,7 +238,7 @@ fn get_lbug_root() -> PathBuf {
"-C",
"lbug-src",
])
.current_dir(manifest_dir)
.current_dir(&manifest_dir)
.status()
.expect("Failed to extract ladybug source");

Expand Down Expand Up @@ -212,7 +334,6 @@ fn build_ffi(
if link_mode() == "static" {
build.define("LBUG_STATIC_DEFINE", None);
}

build.includes(include_paths);

println!("cargo:rerun-if-env-changed=LBUG_SHARED");
Expand Down Expand Up @@ -243,22 +364,28 @@ fn main() {
return;
}

let manifest_dir = manifest_dir();
let mut bundled = false;
let mut include_paths =
vec![Path::new(&std::env::var("CARGO_MANIFEST_DIR").unwrap()).join("include")];
let mut link_bundled_deps = false;
let mut prebuilt_lbug_root = None;
let mut include_paths = vec![manifest_dir.join("include")];

if let (Ok(lbug_lib_dir), Ok(lbug_include)) =
(env::var("LBUG_LIBRARY_DIR"), env::var("LBUG_INCLUDE_DIR"))
{
println!("cargo:rustc-link-search=native={lbug_lib_dir}");
println!("cargo:rustc-link-arg=-Wl,-rpath,{lbug_lib_dir}");
include_paths.push(Path::new(&lbug_include).to_path_buf());
} else if let Some((prebuilt_include_paths, lbug_root)) = use_prebuilt_lbug(&manifest_dir) {
include_paths.extend(prebuilt_include_paths);
prebuilt_lbug_root = Some(lbug_root);
} else {
include_paths.extend(build_bundled_cmake());
bundled = true;
link_bundled_deps = true;
}
if link_mode() == "static" {
link_libraries();
link_libraries(link_bundled_deps, prebuilt_lbug_root.as_deref());
}
build_ffi(
"src/ffi.rs",
Expand All @@ -278,6 +405,6 @@ fn main() {
);
}
if link_mode() == "dylib" {
link_libraries();
link_libraries(link_bundled_deps, prebuilt_lbug_root.as_deref());
}
}
2 changes: 1 addition & 1 deletion examples/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions examples/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ fn main() -> Result<(), Error> {
)?;
let connection = Connection::new(&db)?;

// Load the full-text search extension.
connection.query("install fts; load fts;")?;

// Create schema.
connection.query("CREATE NODE TABLE Person(name STRING, age INT64, PRIMARY KEY(name));")?;
// Create nodes.
Expand Down
1 change: 1 addition & 0 deletions include/lbug_rs.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "storage/storage_version_info.h"
#else
#include <lbug.hpp>
#include "common/enums/statement_type.h"
#endif

namespace lbug_rs {
Expand Down
Loading
Loading