1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
// Copyright (c) Microsoft Corporation
// License: MIT OR Apache-2.0
use bindgen::Builder;
use crate::{CPUArchitecture, Config, ConfigError, DriverConfig};
/// An extension trait that provides a way to create a [`bindgen::Builder`]
/// configured for generating bindings to the wdk
pub trait BuilderExt {
/// Returns a `bindgen::Builder` with the default configuration for
/// generation of bindings to the WDK
///
/// # Errors
///
/// Implementation may return `wdk_build::ConfigError` if it fails to create
/// a builder
fn wdk_default(c_header_files: Vec<&str>, config: Config) -> Result<Builder, ConfigError>;
}
impl BuilderExt for Builder {
/// Returns a `bindgen::Builder` with the default configuration for
/// generation of bindings to the WDK
///
/// # Errors
///
/// Will return `wdk_build::ConfigError` if any of the resolved include or
/// library paths do not exist
fn wdk_default(c_header_files: Vec<&str>, config: Config) -> Result<Self, ConfigError> {
let mut builder = Self::default();
for c_header in c_header_files {
builder = builder.header(c_header);
}
builder = builder
.use_core() // Can't use std for kernel code
.derive_default(true) // allows for default initializing structs
// CStr types are safer and easier to work with when interacting with string constants
// from C
.generate_cstr(true)
// Building in eWDK can pollute system search path when clang-sys tries to detect
// c_search_paths
.detect_include_paths(false)
.clang_args(config.get_include_paths()?.iter().map(|include_path| {
format!(
"--include-directory={}",
include_path
.to_str()
.expect("Non Unicode paths are not supported")
)
}))
.clang_args(
match config.cpu_architecture {
// Definitions sourced from `Program Files\Windows
// Kits\10\build\10.0.22621.0\WindowsDriver.x64.props`
CPUArchitecture::AMD64 => {
vec!["_WIN64", "_AMD64_", "AMD64"]
}
// Definitions sourced from `Program Files\Windows
// Kits\10\build\10.0.22621.0\WindowsDriver.arm64.props`
CPUArchitecture::ARM64 => {
vec!["_ARM64_", "ARM64", "_USE_DECLSPECS_FOR_SAL=1", "STD_CALL"]
}
}
.iter()
.map(|preprocessor_definition| format!("--define-macro={preprocessor_definition}")),
)
.clang_args(
match config.driver_config {
// FIXME: Add support for KMDF_MINIMUM_VERSION_REQUIRED and
// UMDF_MINIMUM_VERSION_REQUIRED
DriverConfig::WDM() => {
vec![]
}
DriverConfig::KMDF(kmdf_config) => {
vec![
format!("KMDF_VERSION_MAJOR={}", kmdf_config.kmdf_version_major),
format!("KMDF_VERSION_MINOR={}", kmdf_config.kmdf_version_minor),
]
}
DriverConfig::UMDF(umdf_config) => {
let mut umdf_definitions = vec![
format!("UMDF_VERSION_MAJOR={}", umdf_config.umdf_version_major),
format!("UMDF_VERSION_MINOR={}", umdf_config.umdf_version_minor),
];
if umdf_config.umdf_version_major >= 2 {
umdf_definitions.push("UMDF_USING_NTSTATUS".to_string());
umdf_definitions.push("_UNICODE".to_string());
umdf_definitions.push("UNICODE".to_string());
}
umdf_definitions
}
}
.iter()
.map(|preprocessor_definition| format!("--define-macro={preprocessor_definition}")),
)
// Windows SDK & DDK have non-portable paths (ex. #include "DriverSpecs.h" but the file
// is actually driverspecs.h)
.clang_arg("--warn-=no-nonportable-include-path")
// Windows SDK & DDK use pshpack and poppack headers to change packing
.clang_arg("--warn-=no-pragma-pack")
.clang_arg("--warn-=no-ignored-attributes")
.clang_arg("--warn-=no-ignored-pragma-intrinsic")
.clang_arg("--warn-=no-visibility")
.clang_arg("--warn-=no-microsoft-anon-tag")
.clang_arg("--warn-=no-microsoft-enum-forward-reference")
// Don't warn for deprecated declarations. deprecated items are already blocklisted
// below and if there are any non-blocklisted function definitions, it will throw a
// -WDeprecated warning
.clang_arg("--warn-=no-deprecated-declarations")
// Windows SDK & DDK contain unnecessary token pasting (ex. &##_variable: `&` and
// `_variable` are seperate tokens already, and don't need `##` to concatenate them)
.clang_arg("--warn-=no-invalid-token-paste")
.clang_arg("-fms-extensions")
.blocklist_item("ExAllocatePoolWithTag") // Deprecated
.blocklist_item("ExAllocatePoolWithQuotaTag") // Deprecated
.blocklist_item("ExAllocatePoolWithTagPriority") // Deprecated
// FIXME: Types containing 32-bit pointers (via __ptr32) are not generated properly and cause bindgen layout tests to fail: https://github.com/rust-lang/rust-bindgen/issues/2636
.blocklist_item(".*EXTENDED_CREATE_INFORMATION_32")
// FIXME: bitfield generated with non-1byte alignment in _MCG_CAP
.blocklist_item(".*MCG_CAP(?:__bindgen.*)?")
.blocklist_item(".*WHEA_XPF_MCA_SECTION")
.blocklist_item(".*WHEA_ARM_BUS_ERROR(?:__bindgen.*)?")
.blocklist_item(".*WHEA_ARM_PROCESSOR_ERROR")
.blocklist_item(".*WHEA_ARM_CACHE_ERROR")
.must_use_type("NTSTATUS")
.must_use_type("HRESULT")
// Defaults enums to generate as a set of constants contained in a module (default value
// is EnumVariation::Consts which generates enums as global constants)
.default_enum_style(bindgen::EnumVariation::ModuleConsts)
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
.formatter(bindgen::Formatter::Prettyplease);
Ok(builder)
}
}