Skip to content

Commit

Permalink
Find winmd files without reading PATH nor copying to target/
Browse files Browse the repository at this point in the history
Non-Windows platforms - which are supported for cross-compiling - do not
set the output directory in `PATH` nor use semicolons to separate this
variable, resulting in errors.
Replace it with the old `include_bytes!` logic that does not require
paths at runtime (of the macro) at all.
Copying of DLL targets to the `target/<profile>` dir for easy
consumption and running of crates is still performed.
  • Loading branch information
MarijnS95 committed Aug 13, 2021
1 parent 1dd9a40 commit 81e8abb
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 99 deletions.
36 changes: 0 additions & 36 deletions crates/gen/build.rs

This file was deleted.

39 changes: 20 additions & 19 deletions crates/gen/src/workspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ fn get_crate_winmds() -> Vec<File> {
if let Ok(file_type) = file.file_type() {
if file_type.is_file() {
let path = file.path();
if let Some("winmd") =
path.extension().and_then(|extension| extension.to_str())
if path.extension().and_then(|extension| extension.to_str())
== Some("winmd")
{
result.push(File::new(path));
}
Expand All @@ -93,26 +93,27 @@ fn get_crate_winmds() -> Vec<File> {

let mut result = vec![];

// Manifest directory of the crate calling `build!`
if let Ok(dir) = std::env::var("CARGO_MANIFEST_DIR") {
let mut dir: std::path::PathBuf = dir.into();
dir.push(".windows");
dir.push("winmd");
push_dir(&mut result, &dir);
push_dir(
&mut result,
&std::path::Path::new(&dir).join(".windows/winmd"),
);
}

let dir = std::env::var("PATH").expect("No `PATH` env variable set");
let end = dir.find(';').expect("Path not ending in `;`");
let mut dir: std::path::PathBuf = dir[..end].into();
dir.pop();
dir.pop();
dir.push(".windows");
dir.push("winmd");
push_dir(&mut result, &dir);

let mut dir: std::path::PathBuf = target_dir().into();
dir.push(".windows");
dir.push("winmd");
push_dir(&mut result, &dir);
// Default manifests provided by windows_gen
// TODO: include_bytes is very slow - it takes an extra 60ms compared with memory mapped files.
// https://github.com/rust-lang/rust/issues/65818
if !result.iter().any(|file| file.name.starts_with("Windows.")) {
result.push(File::from_bytes(
"Windows.Win32.winmd".to_string(),
include_bytes!("../.windows/winmd/Windows.Win32.winmd").to_vec(),
));
result.push(File::from_bytes(
"Windows.WinRT.winmd".to_string(),
include_bytes!("../.windows/winmd/Windows.WinRT.winmd").to_vec(),
));
}

result
}
60 changes: 16 additions & 44 deletions crates/macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,6 @@ impl ToTokens for RawString {
pub fn build(stream: proc_macro::TokenStream) -> proc_macro::TokenStream {
let build = parse_macro_input!(stream as BuildMacro);
let tokens = RawString(build.to_tokens_string());
let target_dir = std::env::var("PATH").expect("No `PATH` env variable set");
let end = target_dir.find(';').expect("Path not ending in `;`");
let target_dir = RawString(target_dir[..end].to_string());

let tokens = quote! {
{
Expand All @@ -59,6 +56,8 @@ pub fn build(stream: proc_macro::TokenStream) -> proc_macro::TokenStream {
);

path.push("windows.rs");
println!("cargo:rerun-if-changed={}", path.to_str().expect("`OUT_DIR` not a UTF-8 string"));

::std::fs::write(&path, #tokens).expect("Could not write generated code to windows.rs");

let mut cmd = ::std::process::Command::new("rustfmt");
Expand All @@ -68,49 +67,27 @@ pub fn build(stream: proc_macro::TokenStream) -> proc_macro::TokenStream {
fn copy(source: &::std::path::Path, destination: &mut ::std::path::PathBuf) {
if let ::std::result::Result::Ok(entries) = ::std::fs::read_dir(source) {
for entry in entries.filter_map(|entry| entry.ok()) {
if let ::std::result::Result::Ok(entry_type) = entry.file_type() {
let path = entry.path();
if let ::std::option::Option::Some(last_path_component) = path.file_name() {
let _ = ::std::fs::create_dir_all(&destination);
destination.push(last_path_component);
if entry_type.is_file() {
let _ = ::std::fs::copy(path, &destination);
} else if entry_type.is_dir() {
let _ = ::std::fs::create_dir(&destination);
copy(&path, destination);
}
destination.pop();
}
}
}
}
}

fn copy_to_profile(source: &::std::path::Path, destination: &::std::path::Path, profile: &str) {
if let ::std::result::Result::Ok(files) = ::std::fs::read_dir(destination) {
for file in files.filter_map(|file| file.ok()) {
if let ::std::result::Result::Ok(file_type) = file.file_type() {
if file_type.is_dir() {
let mut path = file.path();
if let ::std::option::Option::Some(filename) = path.file_name() {
if filename == profile {
copy(source, &mut path);
} else {
copy_to_profile(source, &path, profile);
}
}
let path = entry.path();
if let ::std::option::Option::Some(last_path_component) = path.file_name() {
let _ = ::std::fs::create_dir_all(&destination);
destination.push(last_path_component);
if path.is_file() {
let _ = ::std::fs::copy(path, &destination);
} else if path.is_dir() {
let _ = ::std::fs::create_dir(&destination);
copy(&path, destination);
}
destination.pop();
}
}
}
}

let mut source : ::std::path::PathBuf = ::std::env::var("CARGO_MANIFEST_DIR").expect("No `CARGO_MANIFEST_DIR` env variable set").into();
source.push(".windows");
println!("cargo:rerun-if-changed={}", source.to_str().expect("`CARGO_MANIFEST_DIR` not a UTF-8 string"));

if source.exists() {
println!("cargo:rerun-if-changed={}", source.to_str().expect("`CARGO_MANIFEST_DIR` not a valid path"));

// The `target_arch` cfg is not set for build scripts so we need to sniff it out from the environment variable.
source.push(match ::std::env::var("CARGO_CFG_TARGET_ARCH").expect("No `CARGO_CFG_TARGET_ARCH` env variable set").as_str() {
"x86_64" => "x64",
Expand All @@ -124,17 +101,12 @@ pub fn build(stream: proc_macro::TokenStream) -> proc_macro::TokenStream {
println!("cargo:rustc-link-search=native={}", source.to_str().expect("`CARGO_MANIFEST_DIR` not a valid path"));
}

let mut destination : ::std::path::PathBuf = #target_dir.into();
let mut destination: ::std::path::PathBuf = ::std::env::var("OUT_DIR").expect("No `OUT_DIR` env variable set").into();
// Of `target/<profile>/build/<crate_name>/out`, pop the last 3 folders
destination.pop();
destination.pop();
destination.pop();

let profile = ::std::env::var("PROFILE").expect("No `PROFILE` env variable set");
copy_to_profile(&source, &destination, &profile);

destination.push(".windows");
destination.push("winmd");
source.pop();
source.push("winmd");
copy(&source, &mut destination);
}
}
Expand Down

0 comments on commit 81e8abb

Please sign in to comment.