Skip to content

Commit

Permalink
Pass /no-preprocess flag to llvm-rc 16+
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
roblabla authored and nabijaczleweli committed Jan 5, 2024
1 parent dfc4b39 commit 25a77c4
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 6 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
4 changes: 3 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
27 changes: 22 additions & 5 deletions src/non_windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};


Expand Down Expand Up @@ -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,
}
Expand Down Expand Up @@ -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(),
});
}
Expand All @@ -77,7 +85,7 @@ impl Compiler {
pub fn compile<Ms: AsRef<OsStr>, Mi: IntoIterator<Item = Ms>>(&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)
Expand All @@ -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[..]),
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit 25a77c4

Please sign in to comment.