| // Copyright 2017 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| extern crate bindgen; |
| |
| use std::env; |
| use std::fs::{self, File}; |
| use std::io::{self, Write}; |
| use std::path::{Path, PathBuf}; |
| |
| fn main() { |
| let root_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); |
| let root_dir = Path::new(&root_dir); |
| let meson_build_root = env::var("MESON_BUILD_ROOT").unwrap(); |
| let meson_build_root = Path::new(&meson_build_root); |
| assert!( |
| meson_build_root.join("libmosys.a").exists(), |
| "libmosys.a is not present, see the README for instructions on building Mosys" |
| ); |
| println!( |
| "cargo:rustc-link-search=native={}", |
| meson_build_root.display() |
| ); |
| println!("cargo:rustc-link-lib=dylib=mosys"); |
| println!("cargo:rustc-link-lib=dylib=uuid"); |
| if !env::var("USE").is_err() && env::var("USE").unwrap().contains("unibuild") { |
| println!("cargo:rustc-link-lib=dylib=fdt"); |
| } |
| println!("cargo:rustc-link-lib=dylib=fmap"); |
| let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); |
| let prune = vec![ |
| root_dir.join(".git"), |
| root_dir.join("src"), |
| root_dir.join("target"), |
| ]; |
| let wrapper = out_path.join("wrapper.h"); |
| generate_wrapper(root_dir, &wrapper, &prune).expect("Failed to generate wrapper.h"); |
| let bindings = bindgen::Builder::default() |
| .header(wrapper.to_str().unwrap()) |
| .clang_arg("-Iinclude") |
| .whitelist_function("kv_.*") |
| .whitelist_function("log_.*") |
| .whitelist_function("lprintf") |
| .whitelist_function("lperror") |
| .whitelist_function(".*platform.*") |
| .whitelist_function("print_.*") |
| .whitelist_function("mosys_.*") |
| .generate() |
| .expect("Unable to generate bindings"); |
| bindings |
| .write_to_file(out_path.join("bindings.rs")) |
| .expect("Couldn't write bindings!"); |
| } |
| |
| /// Generates a Bindgen wrapper at target (e.g. target/debug/wrapper.h) using root dir to search |
| /// for C headers to include. Takes slice of paths based at root to prune from search. |
| fn generate_wrapper(root: &Path, target: &Path, prune: &[PathBuf]) -> io::Result<()> { |
| let mut found_headers = Vec::new(); |
| find_headers(root, prune, &mut found_headers).expect("Failed to build headers"); |
| // fs::read_dir is non-deterministic ordering |
| found_headers.sort(); |
| let mut file = File::create(target)?; |
| writeln!(&mut file, "// This file autogenerated from build.rs")?; |
| writeln!(&mut file, "#include <stdint.h>")?; |
| writeln!(&mut file, "#include <stddef.h>")?; |
| writeln!(&mut file, "#include \"mosys/platform.h\"")?; |
| for header in found_headers { |
| writeln!(&mut file, "#include \"{}\"", header.display())?; |
| } |
| |
| Ok(()) |
| } |
| |
| fn find_headers(dir: &Path, prune: &[PathBuf], found: &mut Vec<PathBuf>) -> io::Result<()> { |
| if dir.is_dir() { |
| 'outer: for entry in fs::read_dir(dir)? { |
| let path = entry?.path(); |
| |
| for prune_path in prune { |
| if path.starts_with(prune_path.as_path()) { |
| continue 'outer; |
| } |
| } |
| |
| if path.is_dir() { |
| find_headers(&path, prune, found)?; |
| } else if path.to_str().unwrap().ends_with(".h") { |
| found.push(path); |
| } |
| } |
| } |
| Ok(()) |
| } |