1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 // Copyright 2018 Jacob Lifshay
10 use std::path::{Path, PathBuf};
14 const VULKAN_HEADERS_INCLUDE_PATH: &'static str = "../external/Vulkan-Headers/include";
16 fn detect_vulkan_calling_convention() -> io::Result<String> {
17 let code = bindgen::builder()
20 r#"#include <vulkan/vk_platform.h>
25 VKAPI_ATTR void VKAPI_CALL detect_fn();
33 .clang_arg(env::var("TARGET").unwrap())
34 .clang_arg(format!("-I{}", VULKAN_HEADERS_INCLUDE_PATH))
35 .whitelist_function("detect_fn")
37 .map_err(|_| io::Error::new(io::ErrorKind::Other, "generate() failed"))?
39 if let Some(captures) = regex::Regex::new(r#"extern "([^"]+)""#)
43 Ok(captures[1].to_owned())
45 eprintln!("code:\n{}", code);
46 Err(io::Error::new(io::ErrorKind::Other, "regex not found"))
50 fn main() -> io::Result<()> {
51 let vulkan_wrapper_header_path = "vulkan-wrapper.h";
52 let vulkan_vk_xml_path = "../external/Vulkan-Headers/registry/vk.xml";
53 println!("cargo:rerun-if-changed={}", vulkan_wrapper_header_path);
54 println!("cargo:rerun-if-changed={}", VULKAN_HEADERS_INCLUDE_PATH);
55 println!("cargo:rerun-if-changed={}", vulkan_vk_xml_path);
56 let parsed_xml = Element::parse(fs::File::open(&PathBuf::from(vulkan_vk_xml_path))?)
57 .map_err(|v| io::Error::new(io::ErrorKind::Other, format!("{}", v)))?;
58 let types = parsed_xml.get_child("types").unwrap();
59 let header_version: u32 = types
63 if v.get_child("name")
64 .and_then(|v| v.text.as_ref().map(Deref::deref))
65 == Some("VK_HEADER_VERSION")
67 Some(v.text.as_ref().unwrap())
77 let vulkan_calling_convention = detect_vulkan_calling_convention()?;
78 let match_calling_convention_regex = regex::Regex::new(r#"extern "([^"]+)""#).unwrap();
79 let mut builder = bindgen::builder()
80 .header(vulkan_wrapper_header_path)
82 .clang_arg(env::var("TARGET").unwrap())
83 .clang_arg(format!("-I{}", VULKAN_HEADERS_INCLUDE_PATH))
84 .prepend_enum_name(false)
86 .whitelist_var("VK_.*")
87 .whitelist_var("ICD_LOADER_MAGIC");
91 .filter(|v| v.attributes.get("category").map(|v| &**v) == Some("handle"))
93 let name = if let Some(name) = t.attributes.get("name") {
96 t.get_child("name").unwrap().text.as_ref().unwrap()
98 if name.ends_with("NVX") {
102 .blacklist_type(format!("^{}$", name))
103 .blacklist_type(format!("^{}_T$", name));
106 .whitelist_type("PFN_.*")
107 .whitelist_type("^Vk.*")
108 .blacklist_type("^xcb_.*")
109 .blacklist_type("^VkDebugReportCallbackCreateInfoEXT$")
110 .blacklist_type("^VkDebugUtilsMessengerCreateInfoEXT$")
111 .blacklist_type("^VkAllocationCallbacks$")
113 .constified_enum(".*");
114 let mut code = builder
116 .map_err(|_| io::Error::new(io::ErrorKind::Other, "generate() failed"))?
118 code = match_calling_convention_regex
119 .replace_all(&code, |captures: ®ex::Captures| {
120 if captures[1] == vulkan_calling_convention {
124 PathBuf::from(env::var("OUT_DIR").unwrap()).join("vulkan-types.rs"),
127 eprintln!("vulkan_calling_convention: {:?}", vulkan_calling_convention);
128 panic!("unhandled non-vulkan calling convention");
133 PathBuf::from(env::var("OUT_DIR").unwrap()).join("vulkan-types.rs"),
136 let target_family = env::var("CARGO_CFG_TARGET_FAMILY").unwrap();
137 let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap();
138 println!("target_family = {:?}", target_family);
139 println!("target_os = {:?}", target_os);
140 let driver_name_prefix = if target_family == "unix" {
142 } else if target_os == "windows" {
147 let driver_name_suffix = if target_os == "linux" || target_os == "android" {
149 } else if target_os == "macos" || target_os == "ios" {
151 } else if target_os == "windows" {
156 let driver_name = format!("{}kazan_driver{}", driver_name_prefix, driver_name_suffix);
158 PathBuf::from(env::var("OUT_DIR").unwrap()).join("kazan_driver.json"),
161 "file_format_version": "1.0.0",
163 "library_path": "{}",
164 "api_version": "1.1.{}"
167 PathBuf::from(env::var("OUT_DIR").unwrap())
169 .and_then(Path::parent)
170 .and_then(Path::parent)
171 .unwrap_or_else(|| Path::new(""))