zaplib_cef_sys 0.0.3

The CEF bindings for Zaplib
use std::env;
use std::path::Path;

enum Platform {
    Windows,
    Mac,
    Linux,
}

fn get_platform() -> Platform {
    match std::env::var("CARGO_CFG_TARGET_OS").unwrap().as_str() {
        "windows" => Platform::Windows,
        "macos" => Platform::Mac,
        "linux" => Platform::Linux,
        other => panic!("Sorry, platform \"{}\" is not supported by CEF.", other),
    }
}

fn choose_source_dir() -> Option<String> {
    if let Ok(path) = env::var("CEF_ROOT") {
        if Path::new(&path).exists() {
            return Some(path);
        }
    }

    // Check out `zaplib/main/bind/cef-sys/README.md` file for notes on the current CEF/Chromium version.
    let cef_build = "cef_binary_91.1.23+g04c8d56+chromium-91.0.4472.164";
    let default_path = match get_platform() {
        Platform::Windows => Path::new(env!("CARGO_MANIFEST_DIR")).join("deps").join(format!("{}_windows64", cef_build)),
        Platform::Mac => Path::new(env!("CARGO_MANIFEST_DIR")).join("deps").join(format!("{}_macosx64", cef_build)),
        // TODO(Dmitry): switch linux version from minimal
        Platform::Linux => Path::new(env!("CARGO_MANIFEST_DIR")).join("deps").join(format!("{}_linux64_minimal", cef_build)),
    };
    if default_path.exists() {
        return Some(default_path.to_str().unwrap().to_string());
    }
    None
}

fn main() {
    if std::env::var("CARGO_CFG_TARGET_FAMILY").unwrap() == "wasm" {
        return;
    }

    let source_dir = choose_source_dir().expect("Failed to locate CEF lib path");

    // Inform rust what to link.
    match get_platform() {
        Platform::Windows => println!("cargo:rustc-link-lib=libcef"),
        Platform::Mac => println!("cargo:rustc-link-lib=framework=Chromium Embedded Framework"),
        Platform::Linux => println!("cargo:rustc-link-lib=cef"),
    };

    // Generate bindings.rs.
    println!("cargo:rerun-if-changed=wrapper.h");
    let bindings = bindgen::Builder::default()
        .header("wrapper.h")
        .parse_callbacks(Box::new(bindgen::CargoCallbacks))
        .clang_arg("-I".to_string() + &source_dir)
        .default_enum_style(bindgen::EnumVariation::Rust { non_exhaustive: false })
        .allowlist_type("cef_.*")
        .allowlist_function("cef_.*")
        .bitfield_enum(".*_mask_t")
        .generate()
        .expect("Unable to generate bindings");
    bindings.write_to_file(Path::new(&env::var("OUT_DIR").unwrap()).join("bindings.rs")).expect("Couldn't write bindings!");

    // Get the "Release" dir, which contains the resources (or "Debug" when using the "debug" feature).
    #[allow(unused_mut, unused_assignments)]
    let mut release_dir = Path::new(&source_dir).join("Release");
    #[cfg(feature = "debug")]
    {
        release_dir = Path::new(&source_dir).join("Debug");
    }

    if !release_dir.exists() {
        panic!("CEF Release directory ({}) does not exist", release_dir.to_str().unwrap_or(""));
    }

    let opts = fs_extra::dir::CopyOptions {
        overwrite: true,
        skip_exist: false,
        buffer_size: 64000, // Default
        copy_inside: true,
        depth: 0,
        content_only: false,
    };

    if let Platform::Mac = get_platform() {
        // Add the release dir as a framework search path.
        if let Some(release_dir) = release_dir.to_str() {
            println!("cargo:rustc-link-search=framework={}", release_dir);
        }

        // Copy the framework to "../Frameworks" relative to the final executable, which is where it will
        // automatically get linked to. This is pretty brittle. TODO(JP): Figure out something better here,
        // e.g. absolute paths during debugging (at least that is more stable and seems to be done for system
        // frameworks) and "@rpath" for release builds? See also https://github.com/rust-lang/cargo/issues/5077.
        // Or keep the current behavior for release builds and put everything in the correct place in the final
        // `.app`.
        let dest_path = Path::new(&env::var("OUT_DIR").unwrap()).join("../../../../Frameworks");
        if dest_path.exists() {
            fs_extra::remove_items(&[&dest_path]).unwrap();
        }
        let all_items = vec![release_dir.to_str().unwrap()];
        fs_extra::copy_items(&all_items, &dest_path, &opts).unwrap();
    } else {
        if let Some(release_dir) = release_dir.to_str() {
            println!("cargo:rustc-link-search=native={}", release_dir);
        }

        let resources_dir = Path::new(&source_dir).join("Resources");
        if !resources_dir.exists() {
            panic!("CEF Resources directory ({}) does not exist", resources_dir.to_str().unwrap_or(""));
        }

        // Copy the required Resources & Release contents to OUT_DIR so that a cargo run works.
        let dest_path = Path::new(&env::var("OUT_DIR").unwrap()).join("../../..");

        let mut release_items = fs_extra::dir::get_dir_content(&release_dir).unwrap();
        let mut resources_items = fs_extra::dir::get_dir_content(&resources_dir).unwrap();

        let mut all_items = Vec::new();
        all_items.append(&mut release_items.directories);
        all_items.append(&mut release_items.files);
        all_items.append(&mut resources_items.directories);
        all_items.append(&mut resources_items.files);

        fs_extra::copy_items(&all_items, &dest_path, &opts).unwrap();
    }
}