use std::env;
use std::path::PathBuf;
fn main() {
println!("cargo::rustc-check-cfg=cfg(dpdk_bindgen)");
println!("cargo::rustc-check-cfg=cfg(dpdk_stubs)");
println!("cargo:rerun-if-env-changed=DPDK_PATH");
println!("cargo:rerun-if-env-changed=PKG_CONFIG_PATH");
let dpdk_found = try_find_dpdk();
if dpdk_found && cfg!(feature = "bindgen") {
println!("cargo:rustc-cfg=dpdk_bindgen");
#[cfg(feature = "bindgen")]
generate_bindings();
compile_shim();
} else {
println!("cargo:rustc-cfg=dpdk_stubs");
if !dpdk_found {
println!("cargo:warning=DPDK not found, using stub implementations");
} else {
println!("cargo:warning=bindgen feature not enabled, using stub implementations");
}
}
}
fn try_find_dpdk() -> bool {
if let Ok(dpdk_path) = env::var("DPDK_PATH") {
let lib_path = PathBuf::from(&dpdk_path).join("lib");
let lib64_path = PathBuf::from(&dpdk_path).join("lib64");
let include_path = PathBuf::from(&dpdk_path).join("include");
if include_path.exists() {
println!("cargo:rustc-link-search=native={}", lib_path.display());
println!("cargo:rustc-link-search=native={}", lib64_path.display());
println!("cargo:include={}", include_path.display());
link_dpdk_libraries();
return true;
}
}
match pkg_config::Config::new()
.atleast_version("21.0")
.probe("libdpdk")
{
Ok(lib) => {
for path in &lib.include_paths {
println!("cargo:include={}", path.display());
}
true
}
Err(_) => false,
}
}
fn link_dpdk_libraries() {
let libs = [
"rte_eal",
"rte_mempool",
"rte_mbuf",
"rte_ring",
"rte_ethdev",
"rte_net",
"rte_kvargs",
"rte_telemetry",
"rte_hash",
"rte_timer",
"rte_cmdline",
];
for lib in &libs {
println!("cargo:rustc-link-lib={}", lib);
}
println!("cargo:rustc-link-lib=numa");
println!("cargo:rustc-link-lib=pthread");
println!("cargo:rustc-link-lib=dl");
}
fn compile_shim() {
let mut build = cc::Build::new();
build.file("csrc/dpdk_shim.c");
let common_paths = [
"/usr/include/dpdk",
"/usr/local/include/dpdk",
"/opt/dpdk/include",
];
for path in &common_paths {
if PathBuf::from(path).exists() {
build.include(path);
}
}
if let Ok(dpdk_path) = env::var("DPDK_PATH") {
let include_path = PathBuf::from(&dpdk_path).join("include");
if include_path.exists() {
build.include(&include_path);
}
}
build.compile("dpdk_shim");
println!("cargo:rerun-if-changed=csrc/dpdk_shim.c");
}
#[cfg(feature = "bindgen")]
fn generate_bindings() {
use std::fs;
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
let include_paths: Vec<PathBuf> = env::var("DEP_DPDK_INCLUDE")
.map(|s| s.split(':').map(PathBuf::from).collect())
.unwrap_or_default();
let mut builder = bindgen::Builder::default()
.header("wrapper.h")
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
.allowlist_function("rte_.*")
.allowlist_type("rte_.*")
.allowlist_var("RTE_.*")
.blocklist_type("max_align_t")
.opaque_type("rte_arp_ipv4") .opaque_type("rte_arp_hdr") .opaque_type("rte_l2tpv2_combined_msg_hdr") .opaque_type("rte_gtp_psc_generic_hdr")
.derive_default(true)
.derive_debug(true)
.layout_tests(false)
.use_core()
.ctypes_prefix("libc");
for path in &include_paths {
builder = builder.clang_arg(format!("-I{}", path.display()));
}
let common_paths = [
"/usr/include/dpdk",
"/usr/local/include/dpdk",
"/opt/dpdk/include",
];
for path in &common_paths {
if PathBuf::from(path).exists() {
builder = builder.clang_arg(format!("-I{}", path));
}
}
let bindings = builder
.generate()
.expect("Unable to generate DPDK bindings");
bindings
.write_to_file(out_path.join("bindings.rs"))
.expect("Couldn't write bindings!");
}