implementing get_proc_address
[kazan.git] / vulkan-driver / build.rs
1 extern crate bindgen;
2 extern crate regex;
3 use std::env;
4 use std::fs;
5 use std::io;
6 use std::path::PathBuf;
7
8 fn detect_vulkan_calling_convention() -> io::Result<String> {
9 let code = bindgen::builder()
10 .header_contents(
11 "vulkan_detect.h",
12 r#"#include <vulkan/vk_platform.h>
13 #ifdef __cplusplus
14 extern "C" {
15 #endif
16
17 VKAPI_ATTR void VKAPI_CALL detect_fn();
18
19 #ifdef __cplusplus
20 }
21 #endif
22 "#,
23 ).clang_arg("-target")
24 .clang_arg(env::var("TARGET").unwrap())
25 .clang_arg("-I../external/Vulkan-Headers/include")
26 .whitelist_function("detect_fn")
27 .generate()
28 .map_err(|_| io::Error::new(io::ErrorKind::Other, "generate() failed"))?
29 .to_string();
30 if let Some(captures) = regex::Regex::new(r#"extern "([^"]+)""#)
31 .unwrap()
32 .captures(&code)
33 {
34 Ok(captures[1].to_owned())
35 } else {
36 eprintln!("code:\n{}", code);
37 Err(io::Error::new(io::ErrorKind::Other, "regex not found"))
38 }
39 }
40
41 fn main() -> io::Result<()> {
42 println!("cargo:rerun-if-changed=vulkan-wrapper.h");
43 println!("cargo:rerun-if-changed=../external/Vulkan-Headers/include");
44 let vulkan_calling_convention = detect_vulkan_calling_convention()?;
45 let match_calling_convention_regex = regex::Regex::new(r#"extern "([^"]+)""#).unwrap();
46 let mut builder = bindgen::builder()
47 .header("vulkan-wrapper.h")
48 .clang_arg("-target")
49 .clang_arg(env::var("TARGET").unwrap())
50 .clang_arg("-I../external/Vulkan-Headers/include")
51 .prepend_enum_name(false)
52 .layout_tests(false)
53 .whitelist_var("VK_.*")
54 .whitelist_var("ICD_LOADER_MAGIC");
55 for &t in &[
56 "VkInstance",
57 "VkPhysicalDevice",
58 "VkDevice",
59 "VkQueue",
60 "VkCommandBuffer",
61 ] {
62 builder = builder.blacklist_type(t).blacklist_type(format!("{}_T", t));
63 }
64 for &t in &[
65 "VkSemaphore",
66 "VkFence",
67 "VkDeviceMemory",
68 "VkBuffer",
69 "VkImage",
70 "VkEvent",
71 "VkQueryPool",
72 "VkBufferView",
73 "VkImageView",
74 "VkShaderModule",
75 "VkPipelineCache",
76 "VkPipelineLayout",
77 "VkRenderPass",
78 "VkPipeline",
79 "VkDescriptorSetLayout",
80 "VkSampler",
81 "VkDescriptorPool",
82 "VkDescriptorSet",
83 "VkFramebuffer",
84 "VkCommandPool",
85 "VkSamplerYcbcrConversion",
86 "VkDescriptorUpdateTemplate",
87 "VkSurfaceKHR",
88 "VkSwapchainKHR",
89 "VkDisplayKHR",
90 "VkDisplayModeKHR",
91 "VkDebugReportCallbackEXT",
92 "VkDebugUtilsMessengerEXT",
93 "VkValidationCacheEXT",
94 ] {
95 builder = builder.blacklist_type(t).blacklist_type(format!("{}_T", t));
96 }
97 builder = builder
98 .whitelist_type("PFN_.*")
99 .blacklist_type("^xcb_.*")
100 .derive_debug(false)
101 .ignore_functions()
102 .constified_enum(".*");
103 let mut code = builder
104 .generate()
105 .map_err(|_| io::Error::new(io::ErrorKind::Other, "generate() failed"))?
106 .to_string();
107 code = match_calling_convention_regex
108 .replace_all(&code, |captures: &regex::Captures| {
109 if captures[1] == vulkan_calling_convention {
110 r#"extern "system""#
111 } else {
112 let _ = fs::write(
113 PathBuf::from(env::var("OUT_DIR").unwrap()).join("vulkan-types.rs"),
114 &code,
115 );
116 eprintln!("vulkan_calling_convention: {:?}", vulkan_calling_convention);
117 panic!("unhandled non-vulkan calling convention");
118 }
119 }).into_owned();
120 fs::write(
121 PathBuf::from(env::var("OUT_DIR").unwrap()).join("vulkan-types.rs"),
122 code,
123 )?;
124 Ok(())
125 }