From 25a77c465195ba555eb5e7ba51def485f774eeb9 Mon Sep 17 00:00:00 2001 From: roblabla Date: Fri, 5 Jan 2024 11:16:50 +0100 Subject: [PATCH] Pass /no-preprocess flag to llvm-rc 16+ Since LLVM 16, llvm-rc supports doing the preprocessing itself. However, doing so requires having `clang` in the PATH, which some more complex toolchain may not necessarily have (for instance, for windows, you may have `clang-cl` but no `clang` in PATH, or you may have a target-prefixed clang like `x86_64-pc-windows-msvc-clang`). If llvm-rc fails to find clang, it will error out with a message saying it failed to find the program in PATH. To avoid these issues, we continue doing the preprocessing manually, and pass the /no-preprocess flag to llvm-rc. --- Cargo.toml | 1 + src/lib.rs | 4 +++- src/non_windows.rs | 27 ++++++++++++++++++++++----- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 20c62db..d11e0d6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,6 +42,7 @@ rustc_version = "0.4" toml = "0.8" [target.'cfg(not(target_os = "windows"))'.dependencies] +memchr = "2.7" cc = "1.0" [target.'cfg(all(target_os = "windows", target_env = "msvc"))'.dependencies] diff --git a/src/lib.rs b/src/lib.rs index 921cf04..fb6da89 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -112,12 +112,14 @@ #[cfg(any(not(target_os = "windows"), all(target_os = "windows", target_env = "msvc")))] extern crate cc; -extern crate toml; +#[cfg(not(target_os = "windows"))] +extern crate memchr; #[cfg(all(target_os = "windows", target_env = "msvc"))] extern crate vswhom; #[cfg(all(target_os = "windows", target_env = "msvc"))] extern crate winreg; extern crate rustc_version; +extern crate toml; #[cfg(not(target_os = "windows"))] mod non_windows; diff --git a/src/non_windows.rs b/src/non_windows.rs index 56e03c8..a5ed19c 100644 --- a/src/non_windows.rs +++ b/src/non_windows.rs @@ -3,6 +3,7 @@ use std::path::{PathBuf, Path}; use self::super::apply_macros; use std::borrow::Cow; use std::ffi::OsStr; +use memchr::memmem; use std::{env, fs}; @@ -32,7 +33,7 @@ enum CompilerType { /// LLVM-RC /// /// Requires a separate C preprocessor step on the source RC file - LlvmRc, + LlvmRc { has_no_preprocess: bool, }, /// MinGW windres WindRes, } @@ -65,7 +66,14 @@ impl Compiler { } else if target.ends_with("-pc-windows-msvc") { if is_runnable("llvm-rc") { return Some(Compiler { - tp: CompilerType::LlvmRc, + tp: CompilerType::LlvmRc { + has_no_preprocess: Command::new("llvm-rc") + .arg("/?") + .output() + .ok() + .map(|out| memmem::find(&out.stdout, b"no-preprocess").is_some()) + .unwrap_or(false), + }, executable: "llvm-rc".into(), }); } @@ -77,7 +85,7 @@ impl Compiler { pub fn compile, Mi: IntoIterator>(&self, out_dir: &str, prefix: &str, resource: &str, macros: Mi) -> String { let out_file = format!("{}/{}.lib", out_dir, prefix); match self.tp { - CompilerType::LlvmRc => { + CompilerType::LlvmRc { has_no_preprocess } => { let preprocessed_path = format!("{}/{}-preprocessed.rc", out_dir, prefix); fs::write(&preprocessed_path, apply_macros_cc(cc::Build::new().define("RC_INVOKED", None), macros) @@ -89,7 +97,16 @@ impl Compiler { .unwrap(); try_command(Command::new(&self.executable[..]) - .args(&["/fo", &out_file, "--", &preprocessed_path]) + .args(&["/fo", &out_file]) + .args(if has_no_preprocess { + // We already preprocessed using CC. llvm-rc preprocessing + // requires having clang in PATH, which more exotic toolchains + // may not necessarily have. + &["/no-preprocess"][..] + } else { + &[][..] + }) + .args(&["--", &preprocessed_path]) .stdin(Stdio::piped()) .current_dir(or_curdir(Path::new(resource).parent().expect("Resource parent nonexistent?"))), Path::new(&self.executable[..]), @@ -150,7 +167,7 @@ fn guess_compiler_variant(s: &str) -> Compiler { } else if out.stdout.starts_with(b"OVERVIEW: Resource Converter") || out.stdout.starts_with(b"OVERVIEW: LLVM Resource Converter") { Compiler { executable: s.to_string().into(), - tp: CompilerType::LlvmRc, + tp: CompilerType::LlvmRc { has_no_preprocess: memmem::find(&out.stdout, b"no-preprocess").is_some() }, } } else { panic!("Unknown RC compiler variant: {}", s)