Skip to content

Commit cfd54fe

Browse files
committed
Never pick up Strawberry Perl's pkg-config as a valid implementation
Strawberry Perl places a `pkg-config.bat` into PATH that is written in Perl and is not intended to be used by third parties as a MinGW distribution. This wouldn't matter, except that Strawberry Perl is also included in Github CI images out of the box, in `PATH`, and it breaks everyone's CI jobs. This is already done by Meson and CMake: mesonbuild/meson#9384 https://gitlab.kitware.com/cmake/cmake/-/merge_requests/9375 Fixes #164
1 parent 246ece2 commit cfd54fe

File tree

1 file changed

+72
-1
lines changed

1 file changed

+72
-1
lines changed

src/lib.rs

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -652,14 +652,85 @@ impl Config {
652652
self.statik.unwrap_or_else(|| self.infer_static(name))
653653
}
654654

655+
#[cfg(windows)]
656+
fn find_pkg_config_in(&self, mut path: PathBuf, pathexts: &[OsString]) -> Option<OsString> {
657+
path.push("pkg-config");
658+
for pathext in pathexts {
659+
path.set_extension(pathext);
660+
if !path.is_file() {
661+
return None;
662+
}
663+
// Strawberry Perl's pkg-config is pkg-config.bat
664+
if pathext.eq_ignore_ascii_case("bat") {
665+
let mut cmd = Command::new(path.as_os_str());
666+
let out = match cmd.arg("--help").output() {
667+
Ok(o) => o,
668+
Err(e) => {
669+
eprintln!("Ignoring unusable pkg-config ({:?}): {:?}", path, e);
670+
return None;
671+
}
672+
};
673+
if let Ok(out) = str::from_utf8(&out.stdout) {
674+
if out.contains("Pure-Perl") {
675+
eprintln!("Ignoring Strawberry Perl pkg-config: {:?}", path);
676+
return None;
677+
}
678+
}
679+
}
680+
}
681+
Some(path.into_os_string())
682+
}
683+
684+
fn pkg_config_from_path(&self) -> OsString {
685+
#[cfg(windows)]
686+
{
687+
// Resolve pkg-config in PATH to find the absolute path to pkg-config that we should
688+
// use, so that we can skip Strawberry Perl's pure-perl implementation of pkg-config.
689+
// Despite its presence in PATH, the implementation is for internal use and not meant
690+
// to be used as a MinGW distribution.
691+
use std::os::windows::prelude::*;
692+
let pathexts = env::var_os("PATHEXT").map_or_else(
693+
|| {
694+
["COM", "EXE", "BAT"]
695+
.iter()
696+
.map(|v| OsStr::new(v).to_owned())
697+
.collect::<Vec<_>>()
698+
},
699+
|v| {
700+
env::split_paths(&v)
701+
// PATHEXT is a list of .EXT but we want EXT
702+
.map(|v| {
703+
OsString::from_wide(
704+
&v.as_os_str().encode_wide().skip(1).collect::<Vec<u16>>(),
705+
)
706+
})
707+
.collect::<Vec<_>>()
708+
},
709+
);
710+
// Windows first searches for the specified command in the current directory,
711+
// regardless of the value of PATH.
712+
if let Some(ret) = self.find_pkg_config_in(".".into(), &pathexts) {
713+
return ret;
714+
}
715+
if let Some(paths) = env::var_os("PATH") {
716+
for path in env::split_paths(&paths) {
717+
if let Some(ret) = self.find_pkg_config_in(path, &pathexts) {
718+
return ret;
719+
}
720+
}
721+
}
722+
}
723+
OsString::from("pkg-config")
724+
}
725+
655726
fn run(&self, name: &str, args: &[&str]) -> Result<Vec<u8>, Error> {
656727
let pkg_config_exe = self.targeted_env_var("PKG_CONFIG");
657728
let fallback_exe = if pkg_config_exe.is_none() {
658729
Some(OsString::from("pkgconf"))
659730
} else {
660731
None
661732
};
662-
let exe = pkg_config_exe.unwrap_or_else(|| OsString::from("pkg-config"));
733+
let exe = pkg_config_exe.unwrap_or_else(|| self.pkg_config_from_path());
663734

664735
let mut cmd = self.command(exe, name, args);
665736

0 commit comments

Comments
 (0)