Skip to content

Commit

Permalink
build: update cargo-make tasks with arch-specific tools
Browse files Browse the repository at this point in the history
  • Loading branch information
wmmc88 committed Nov 16, 2023
1 parent eeffeb5 commit b45c10d
Show file tree
Hide file tree
Showing 5 changed files with 361 additions and 52 deletions.
2 changes: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
target/
DriverCertificate.cer
.cargo-make-loadscripts/
110 changes: 108 additions & 2 deletions crates/wdk-build/src/cargo_make.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@
use clap::{Args, Parser};

use crate::{
utils::{detect_wdk_content_root, get_latest_windows_sdk_version, PathExt},
CPUArchitecture,
ConfigError,
};

const PATH_ENV_VAR: &str = "Path";

/// The name of the environment variable that cargo-make uses during `cargo
/// build` and `cargo test` commands
const CARGO_MAKE_CARGO_BUILD_TEST_FLAGS_ENV_VAR: &str = "CARGO_MAKE_CARGO_BUILD_TEST_FLAGS";
Expand Down Expand Up @@ -363,7 +371,7 @@ pub fn validate_and_forward_args() {
.to_string_lossy()
.strip_prefix('+')
.expect("Toolchain arg should have a + prefix")
.to_owned(),
.to_string(),
)
} else {
None
Expand All @@ -389,7 +397,91 @@ pub fn validate_and_forward_args() {
forward_env_var_to_cargo_make(CARGO_MAKE_CARGO_BUILD_TEST_FLAGS_ENV_VAR);
}

fn append_to_space_delimited_env_var<S: AsRef<str>>(env_var_name: S, string_to_append: S) {
/// Prepends the path variable with the necessary paths to access WDK tools
///
/// # Errors
///
/// This function returns a [`ConfigError::WDKContentRootDetectionError`] if the
/// WDK content root directory could not be found.
/// Sets up the path for the WDK build environment.
///
/// # Panics
///
/// This function will panic if the CPU architecture cannot be determined from
/// `std::env::consts::ARCH` or if the PATH variable contains non-UTF8
/// characters.
pub fn setup_path() -> Result<(), ConfigError> {
let Some(wdk_content_root) = detect_wdk_content_root() else {
return Err(ConfigError::WDKContentRootDetectionError);
};
let version = get_latest_windows_sdk_version(&wdk_content_root.join("Lib"))?;
let host_arch = CPUArchitecture::try_from_cargo_str(std::env::consts::ARCH)
.expect("The rust standard library should always set std::env::consts::ARCH");

let wdk_bin_root = wdk_content_root
.join(format!("bin/{version}"))
.canonicalize()?
.strip_extended_length_path_prefix()?;
let windows_sdk_ver_bin_path = match host_arch {
CPUArchitecture::AMD64 => {
let x64_path = wdk_bin_root
.join(host_arch.as_windows_str())
.canonicalize()?
.strip_extended_length_path_prefix()?;

// Some tools (ex. inf2cat) are only available in the x86 folder
let x86_path = wdk_bin_root
.join("x86")
.canonicalize()?
.strip_extended_length_path_prefix()?;

// By putting x64_path first, 64-bit versions of tools are prioritized over
// 32-bit versions
format!(
"{};{}",
x64_path
.to_str()
.expect("AMD64 windows_sdk_ver_bin_path should only contain valid UTF8"),
x86_path
.to_str()
.expect("x86 windows_sdk_ver_bin_path should only contain valid UTF8")
)
}
CPUArchitecture::ARM64 => wdk_bin_root
.join(host_arch.as_windows_str())
.canonicalize()?
.strip_extended_length_path_prefix()?
.to_str()
.expect("ARM64 windows_sdk_ver_bin_path should only contain valid UTF8")
.to_string(),
};

let wdk_tool_root = wdk_content_root
.join(format!("Tools/{version}"))
.canonicalize()?
.strip_extended_length_path_prefix()?;
let arch_specific_wdk_tool_root = wdk_tool_root
.join(host_arch.as_windows_str())
.canonicalize()?
.strip_extended_length_path_prefix()?;

prepend_to_semicolon_delimited_env_var(PATH_ENV_VAR, windows_sdk_ver_bin_path);
prepend_to_semicolon_delimited_env_var(
PATH_ENV_VAR,
arch_specific_wdk_tool_root
.to_str()
.expect("arch_specific_wdk_tool_root should only contain valid UTF8"),
);

forward_env_var_to_cargo_make(PATH_ENV_VAR);
Ok(())
}

fn append_to_space_delimited_env_var<S, T>(env_var_name: S, string_to_append: T)
where
S: AsRef<str>,
T: AsRef<str>,
{
let env_var_name = env_var_name.as_ref();
let string_to_append = string_to_append.as_ref();

Expand All @@ -399,6 +491,20 @@ fn append_to_space_delimited_env_var<S: AsRef<str>>(env_var_name: S, string_to_a
std::env::set_var(env_var_name, env_var_value.trim());
}

fn prepend_to_semicolon_delimited_env_var<S, T>(env_var_name: S, string_to_prepend: T)
where
S: AsRef<str>,
T: AsRef<str>,
{
let env_var_name = env_var_name.as_ref();
let string_to_prepend = string_to_prepend.as_ref();

let mut env_var_value = string_to_prepend.to_string();
env_var_value.push(';');
env_var_value.push_str(std::env::var(env_var_name).unwrap_or_default().as_str());
std::env::set_var(env_var_name, env_var_value);
}

fn forward_env_var_to_cargo_make<S: AsRef<str>>(env_var_name: S) {
let env_var_name = env_var_name.as_ref();

Expand Down
57 changes: 52 additions & 5 deletions crates/wdk-build/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,13 @@ pub enum ConfigError {
/// Error returned when a [`Config`] fails to be exported to the environment
#[error(transparent)]
ExportError(#[from] ExportError),

/// Error returned when a [`Config`] fails to be serialized
#[error(
"WDKContentRoot should be able to be detected. Ensure that the WDK is installed, or that \
the environment setup scripts in the eWDK have been run."
)]
WDKContentRootDetectionError,
}

/// Errors that could result from parsing a configuration from a [`wdk-build`]
Expand Down Expand Up @@ -398,10 +405,10 @@ impl Config {
.join(sdk_version)
.join(match self.driver_config {
DriverConfig::WDM() | DriverConfig::KMDF(_) => {
format!("km/{}", self.cpu_architecture.to_windows_str(),)
format!("km/{}", self.cpu_architecture.as_windows_str(),)
}
DriverConfig::UMDF(_) => {
format!("um/{}", self.cpu_architecture.to_windows_str(),)
format!("um/{}", self.cpu_architecture.as_windows_str(),)
}
});
if !windows_sdk_library_path.is_dir() {
Expand All @@ -421,7 +428,7 @@ impl Config {
DriverConfig::KMDF(kmdf_config) => {
let kmdf_library_path = library_directory.join(format!(
"wdf/kmdf/{}/{}.{}",
self.cpu_architecture.to_windows_str(),
self.cpu_architecture.as_windows_str(),
kmdf_config.kmdf_version_major,
kmdf_config.kmdf_version_minor
));
Expand All @@ -439,7 +446,7 @@ impl Config {
DriverConfig::UMDF(umdf_config) => {
let umdf_library_path = library_directory.join(format!(
"wdf/umdf/{}/{}.{}",
self.cpu_architecture.to_windows_str(),
self.cpu_architecture.as_windows_str(),
umdf_config.umdf_version_major,
umdf_config.umdf_version_minor
));
Expand Down Expand Up @@ -651,12 +658,39 @@ impl CPUArchitecture {
/// Converts [`CPUArchitecture`] to the string corresponding to what the
/// architecture is typically referred to in Windows
#[must_use]
pub const fn to_windows_str(&self) -> &str {
pub const fn as_windows_str(&self) -> &str {
match self {
Self::AMD64 => "x64",
Self::ARM64 => "ARM64",
}
}

/// Converts [`CPUArchitecture`] to the string corresponding to what the
/// architecture is typically referred to in Windows
#[deprecated(
since = "0.2.0",
note = "CPUArchitecture.to_windows_str() was mis-named when originally created, since the \
conversion from CPUArchitecture to str is free. Use \
CPUArchitecture.as_windows_str instead."
)]
#[must_use]
pub const fn to_windows_str(&self) -> &str {
self.as_windows_str()
}

/// Converts from a cargo-provided [`std::str`] to a [`CPUArchitecture`].
///
/// #
#[must_use]
pub fn try_from_cargo_str<S: AsRef<str>>(cargo_str: S) -> Option<Self> {
// Specifically not using the [`std::convert::TryFrom`] trait to be more
// explicit in function name, since only arch strings from cargo are handled.
match cargo_str.as_ref() {
"x86_64" => Some(Self::AMD64),
"aarch64" => Some(Self::ARM64),
_ => None,
}
}
}

#[cfg(test)]
Expand Down Expand Up @@ -819,4 +853,17 @@ mod tests {
);
assert_eq!(config.cpu_architecture, CPUArchitecture::ARM64);
}

#[test]
fn test_try_from_cargo_str() {
assert_eq!(
CPUArchitecture::try_from_cargo_str("x86_64"),
Some(CPUArchitecture::AMD64)
);
assert_eq!(
CPUArchitecture::try_from_cargo_str("aarch64"),
Some(CPUArchitecture::ARM64)
);
assert_eq!(CPUArchitecture::try_from_cargo_str("arm"), None);
}
}
10 changes: 3 additions & 7 deletions crates/wdk-build/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -249,13 +249,9 @@ pub fn detect_cpu_architecture_in_build_script() -> CPUArchitecture {
build.rs",
);

if target_arch == "x86_64" {
return CPUArchitecture::AMD64;
} else if target_arch == "aarch64" {
return CPUArchitecture::ARM64;
}

panic!("The target architecture, {target_arch}, is currently not supported.");
CPUArchitecture::try_from_cargo_str(&target_arch).unwrap_or_else(|| {
panic!("The target architecture, {target_arch}, is currently not supported.")
})
}

#[cfg(test)]
Expand Down
Loading

0 comments on commit b45c10d

Please sign in to comment.