Skip to content

Commit 7bbf651

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 rust-lang#164
1 parent 246ece2 commit 7bbf651

File tree

1 file changed

+69
-2
lines changed

1 file changed

+69
-2
lines changed

src/lib.rs

Lines changed: 69 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ use std::fmt;
9292
use std::fmt::Display;
9393
use std::io;
9494
use std::ops::{Bound, RangeBounds};
95-
use std::path::PathBuf;
95+
use std::path::{Path, PathBuf};
9696
use std::process::{Command, Output};
9797
use std::str;
9898

@@ -652,14 +652,81 @@ 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| OsString::from_wide(v.as_os_str().encode_wide()[1..]))
703+
.collect::<Vec<_>>()
704+
},
705+
);
706+
// Windows first searches for the specified command in the current directory,
707+
// regardless of the value of PATH.
708+
if let Some(ret) = self.find_pkg_config_in(".".into(), &pathexts) {
709+
return ret;
710+
}
711+
if let Some(paths) = env::var_os("PATH") {
712+
for mut path in env::split_paths(&paths) {
713+
if let Some(ret) = self.find_pkg_config_in(path, &pathexts) {
714+
return ret;
715+
}
716+
}
717+
}
718+
}
719+
OsString::from("pkg-config")
720+
}
721+
655722
fn run(&self, name: &str, args: &[&str]) -> Result<Vec<u8>, Error> {
656723
let pkg_config_exe = self.targeted_env_var("PKG_CONFIG");
657724
let fallback_exe = if pkg_config_exe.is_none() {
658725
Some(OsString::from("pkgconf"))
659726
} else {
660727
None
661728
};
662-
let exe = pkg_config_exe.unwrap_or_else(|| OsString::from("pkg-config"));
729+
let exe = pkg_config_exe.unwrap_or_else(|| self.pkg_config_from_path());
663730

664731
let mut cmd = self.command(exe, name, args);
665732

0 commit comments

Comments
 (0)