rocks-sys 0.1.1

Raw RocksDB bindings for Rust, used internally in rust-rocks
Documentation
extern crate gcc;
extern crate cmake;

#[cfg(not(feature = "static-link"))]
extern crate pkg_config;

#[cfg(not(feature = "static-link"))]
mod imp {
    pub fn build() {
        #[cfg(feature = "snappy")]
        snappy();

        #[cfg(feature = "zlib")]
        zlib();

        #[cfg(feature = "bzip2")]
        bzip2();

        #[cfg(feature = "lz4")]
        lz4();

        #[cfg(feature = "zstd")]
        zstd();

        rocksdb();
    }

    #[cfg(feature = "snappy")]
    fn snappy() {
        pkg_config::Config::new().probe("snappy").or_else(|_| {
            println!("cargo:rustc-link-lib=dylib=snappy");
        });
    }

    #[cfg(feature = "zlib")]
    fn zlib() {
        pkg_config::Config::new().probe("zlib").or_else(|_| {
            println!("cargo:rustc-link-lib=dylib=z");
        });
    }

    #[cfg(feature = "bzip2")]
    fn bzip2() {
        println!("cargo:rustc-link-lib=dylib=bzip2");
    }

    #[cfg(feature = "lz4")]
    fn lz4() {
        pkg_config::Config::new().probe("liblz4").or_else(|_| {
            println!("cargo:rustc-link-lib=dylib=lz4");
        });
    }

    #[cfg(feature = "zstd")]
    fn zstd() {
        pkg_config::Config::new().probe("libzstd").or_else(|_| {
            println!("cargo:rustc-link-lib=dylib=zstd");
        });
    }

    fn rocksdb() {
        println!("cargo:rustc-link-lib=rocksdb");
    }
}

#[cfg(feature = "static-link")]
mod imp {
    use std::process::Command;
    use std::path::Path;

    use cmake;

    pub fn build() {
        println!("cargo:warning=static link feature enabled, it'll takes some minutes to finish compiling... ");

        #[cfg(feature = "snappy")]
        snappy();

        #[cfg(feature = "zlib")]
        zlib();

        #[cfg(feature = "bzip2")]
        bzip2();

        #[cfg(feature = "lz4")]
        lz4();

        #[cfg(feature = "zstd")]
        zstd();

        rocksdb();
    }

    #[cfg(feature = "snappy")]
    fn snappy() {
        if !Path::new("snappy/.git").exists() {
            let _ = Command::new("git")
                .args(&["submodule", "update", "--init", "snappy"])
                .status();
        }

        Command::new("./autogen.sh")
            .current_dir("snappy")
            .output()
            .expect("failed to execute process");

        Command::new("./configure")
            .current_dir("snappy")
            .arg("--with-pic")
            .arg("--enable-static")
            .output()
            .expect("failed to execute process");

        ::gcc::Build::new()
            .cpp(true)
            .flag("-std=c++11")
            .opt_level(2)
            .warnings(false)
            .include("snappy")
            .file("snappy/snappy.cc")
            .file("snappy/snappy-sinksource.cc")
            .file("snappy/snappy-stubs-internal.cc")
            .file("snappy/snappy-c.cc")
            .compile("libsnappy.a");
    }

    #[cfg(feature = "zlib")]
    fn zlib() {
        if !Path::new("zlib/.git").exists() {
            let _ = Command::new("git")
                .args(&["submodule", "update", "--init", "zlib"])
                .status();
        }

        Command::new("./configure")
            .current_dir("zlib")
            .arg("--static")
            .output()
            .expect("failed to execute process");

        let mut cfg = ::gcc::Build::new();
        cfg.include("zlib");

        // TODO: borrow following list form Makefile
        let filez = "adler32.c crc32.c deflate.c infback.c inffast.c inflate.c inftrees.c trees.c zutil.c";
        let fileg = "compress.c uncompr.c gzclose.c gzlib.c gzread.c gzwrite.c";

        for file in filez.split(" ") {
            cfg.file(format!("zlib/{}", file));
        }
        for file in fileg.split(" ") {
            cfg.file(format!("zlib/{}", file));
        }

        cfg.pic(true);
        cfg.opt_level(2);
        cfg.compile("libz.a");
    }

    // Yes, copied from alexcrichton/bzip2-rs
    #[cfg(feature = "bzip2")]
    fn bzip2() {
        if !Path::new("bzip2/.git").exists() {
            let _ = Command::new("git")
                .args(&["submodule", "update", "--init", "bzip2"])
                .status();
        }

        let mut cfg = ::gcc::Build::new();

        if cfg!(windows) {
            cfg.define("_WIN32", None);
            cfg.define("BZ_EXPORT", None);
        }

        cfg.define("_FILE_OFFSET_BITS", Some("64"));

        cfg.include("bzip2")
            .define("BZ_NO_STDIO", None)
            .opt_level(2)
            .file("bzip2/blocksort.c")
            .file("bzip2/huffman.c")
            .file("bzip2/crctable.c")
            .file("bzip2/randtable.c")
            .file("bzip2/compress.c")
            .file("bzip2/decompress.c")
            .file("bzip2/bzlib.c")
            .compile("libbz2.a");
    }

    #[cfg(feature = "lz4")]
    fn lz4() {
        if !Path::new("lz4/.git").exists() {
            let _ = Command::new("git")
                .args(&["submodule", "update", "--init", "lz4"])
                .status();
        }

        ::gcc::Build::new()
            .include("lz4/lib")
            .opt_level(3)
            .file("lz4/lib/lz4.c")
            .file("lz4/lib/lz4frame.c")
            .file("lz4/lib/lz4hc.c")
            .file("lz4/lib/xxhash.c")
            .compile("liblz4.a");
    }

    #[cfg(feature = "zstd")]
    fn zstd() {
        if !Path::new("zstd/.git").exists() {
            let _ = Command::new("git")
                .args(&["submodule", "update", "--init", "zstd"])
                .status();
        }

        let files = [
            "zstd/lib/common/entropy_common.c",
            "zstd/lib/common/error_private.c",
            "zstd/lib/common/fse_decompress.c",
            "zstd/lib/common/pool.c",
            "zstd/lib/common/threading.c",
            "zstd/lib/common/xxhash.c",
            "zstd/lib/common/zstd_common.c",
            "zstd/lib/compress/fse_compress.c",
            "zstd/lib/compress/huf_compress.c",
            "zstd/lib/compress/zstd_compress.c",
            "zstd/lib/compress/zstdmt_compress.c",
            "zstd/lib/decompress/huf_decompress.c",
            "zstd/lib/decompress/zstd_decompress.c",
            "zstd/lib/dictBuilder/cover.c",
            "zstd/lib/dictBuilder/divsufsort.c",
            "zstd/lib/dictBuilder/zdict.c",
        ];

        ::gcc::Build::new()
            .define("ZSTD_LEGACY_SUPPORT", Some("0"))
            .include("zstd/lib")
            .include("zstd/lib/common")
            .opt_level(3)
            .warnings(false)
            .files(&files)
            .compile("libzstd.a");
    }

    fn rocksdb() {
        if !Path::new("rocksdb/.git").exists() {
            let _ = Command::new("git")
                .args(&["submodule", "update", "--init", "rocksdb"])
                .status();
        }

        let mut cfg = cmake::Config::new("rocksdb");

        #[cfg(feature = "snappy")]
        {
            // FIXME: how to use cmake's define?
            cfg.cxxflag("-DSNAPPY");
            cfg.cxxflag("-Isnappy");
        }

        #[cfg(feature = "zlib")]
        {
            cfg.cxxflag("-DZLIB");
            cfg.cxxflag("-Izlib");
        }

        #[cfg(feature = "bzip2")]
        {
            cfg.cxxflag("-DBZIP2");
            cfg.cxxflag("-Ibzip2");
        }

        #[cfg(feature = "lz4")]
        {
            cfg.cxxflag("-DLZ4");
            cfg.cxxflag("-Ilz4/lib");
        }

        #[cfg(feature = "zstd")]
        {
            cfg.cxxflag("-DZSTD");
            cfg.cxxflag("-Izstd/lib");
        }

        cfg.build_target("rocksdb");
        let dst = cfg.build();

        println!("cargo:rustc-link-search=native={}/build/", dst.display());
        println!("cargo:rustc-link-lib=static=rocksdb");
    }
}

fn main() {
    println!("cargo:rerun-if-changed=build.rs");
    println!("cargo:rerun-if-changed=./");
    println!("cargo:rerun-if-changed=./rocks");

    imp::build();

    ::gcc::Build::new()
        .cpp(true)
        .pic(true)
        .opt_level(2)
        .warnings(false)
        .flag("-std=c++11")
        .include("rocksdb/include")
        .include(".")
        .file("rocks/cache.cc")
        .file("rocks/comparator.cc")
        .file("rocks/convenience.cc")
        .file("rocks/db.cc")
        .file("rocks/db_dump_tool.cc")
        .file("rocks/env.cc")
        .file("rocks/filter_policy.cc")
        .file("rocks/iostats_context.cc")
        .file("rocks/iterator.cc")
        .file("rocks/merge_operator.cc")
        .file("rocks/metadata.cc")
        .file("rocks/options.cc")
        .file("rocks/perf_context.cc")
        .file("rocks/perf_level.cc")
        .file("rocks/rate_limiter.cc")
        .file("rocks/slice.cc")
        .file("rocks/snapshot.cc")
        .file("rocks/sst_file_writer.cc")
        .file("rocks/statistics.cc")
        .file("rocks/status.cc")
        .file("rocks/table.cc")
        .file("rocks/table_properties.cc")
        .file("rocks/transaction_log.cc")
        .file("rocks/universal_compaction.cc")
        .file("rocks/util.cc")
        .file("rocks/write_batch.cc")
        .file("rocks/write_buffer_manager.cc")
        .file("rocks/debug.cc")
        .file("rocks/listener.cc")
        .file("rocks/compaction_job_stats.cc")
        .compile("librocksdb_wrap.a");
}