#[cfg(feature = "vendored")]
use std::{
env,
path::{Path, PathBuf},
process::Command,
};
fn main() {
if std::env::var("DOCS_RS").is_err() {
setup_hwloc();
}
}
fn setup_hwloc() {
let required_version = if cfg!(feature = "hwloc-2_8_0") {
"2.8.0"
} else if cfg!(feature = "hwloc-2_5_0") {
"2.5.0"
} else if cfg!(feature = "hwloc-2_4_0") {
"2.4.0"
} else if cfg!(feature = "hwloc-2_3_0") {
"2.3.0"
} else if cfg!(feature = "hwloc-2_2_0") {
"2.2.0"
} else if cfg!(feature = "hwloc-2_1_0") {
"2.1.0"
} else if cfg!(feature = "hwloc-2_0_4") {
"2.0.4"
} else {
"2.0.0"
};
#[cfg(feature = "vendored")]
setup_vendored_hwloc(required_version);
#[cfg(not(feature = "vendored"))]
find_hwloc(Some(required_version));
}
#[cfg(not(all(feature = "vendored", windows)))]
fn find_hwloc(required_version: Option<&str>) -> pkg_config::Library {
let mut config = pkg_config::Config::new();
if let Some(required_version) = required_version {
let first_unsupported_version = match required_version
.split('.')
.next()
.expect("No major version in required_version")
{
"2" => "3.0.0",
other => panic!("Please add support for hwloc v{other}.x"),
};
config.range_version(required_version..first_unsupported_version);
}
let lib = config
.statik(cfg!(not(target_os = "macos")))
.probe("hwloc")
.expect("Could not find a suitable version of hwloc");
if cfg!(target_family = "unix") {
for link_path in &lib.link_paths {
println!(
"cargo:rustc-link-arg=-Wl,-rpath,{}",
link_path
.to_str()
.expect("Link path is not an UTF-8 string")
);
}
}
lib
}
#[cfg(feature = "vendored")]
fn setup_vendored_hwloc(required_version: &str) {
let source_version = match required_version
.split('.')
.next()
.expect("No major version in required_version")
{
"2" => "v2.x",
other => panic!("Please add support for bundling hwloc v{other}.x"),
};
let out_path = env::var("OUT_DIR").expect("No output directory given");
let source_path = fetch_hwloc(out_path, source_version);
#[cfg(target_os = "windows")]
install_hwloc_cmake(source_path);
#[cfg(not(target_os = "windows"))]
install_hwloc_autotools(source_path);
}
#[cfg(feature = "vendored")]
fn fetch_hwloc(parent_path: impl AsRef<Path>, version: &str) -> PathBuf {
let parent_path = parent_path.as_ref();
let repo_path = parent_path.join("hwloc");
let output = if !repo_path.join("Makefile.am").exists() {
Command::new("git")
.args([
"clone",
"https://github.com/open-mpi/hwloc",
"--depth",
"1",
"--branch",
version,
])
.current_dir(parent_path)
.output()
.expect("git clone for hwloc failed")
} else {
Command::new("git")
.args(["pull", "--ff-only", "origin", "v2.x"])
.current_dir(&repo_path)
.output()
.expect("git pull for hwloc failed")
};
let status = output.status;
assert!(
status.success(),
"git clone/pull for hwloc returned failure status {status}:\n{output:?}"
);
repo_path
}
#[cfg(all(feature = "vendored", windows))]
fn install_hwloc_cmake(source_path: impl AsRef<Path>) {
let cmake_path = source_path.as_ref().join("contrib").join("windows-cmake");
assert!(
cmake_path.join("CMakeLists.txt").exists(),
"Need hwloc's CMake support to build on Windows (with MSVC)"
);
let mut config = cmake::Config::new(cmake_path);
if let Ok(profile) = env::var("HWLOC_BUILD_PROFILE") {
config.profile(&profile);
}
if let Ok(toolchain) = env::var("HWLOC_TOOLCHAIN") {
config.define("CMAKE_TOOLCHAIN_FILE", &toolchain);
}
config.define("HWLOC_ENABLE_TESTING", "OFF");
config.define("HWLOC_SKIP_LSTOPO", "1");
config.define("HWLOC_SKIP_TOOLS", "1");
let install_path = config.always_configure(false).build();
println!("cargo:rustc-link-lib=static=hwloc");
println!(
"cargo:rustc-link-search={}",
install_path.join("lib").display()
);
}
#[cfg(all(feature = "vendored", not(windows)))]
fn install_hwloc_autotools(source_path: impl AsRef<Path>) {
let mut config = autotools::Config::new(source_path);
if cfg!(target_os = "macos") {
config.disable_static();
config.enable_shared();
} else {
config.enable_static();
config.disable_shared();
}
let install_path = config.fast_build(true).reconf("-ivf").build();
let new_path = |lib_dir: &str| install_path.join(lib_dir).join("pkgconfig");
let new_path = format!(
"{}:{}",
new_path("lib").display(),
new_path("lib64").display()
);
match env::var("PKG_CONFIG_PATH") {
Ok(old_path) if !old_path.is_empty() => {
env::set_var("PKG_CONFIG_PATH", format!("{new_path}:{old_path}"))
}
Ok(_) | Err(env::VarError::NotPresent) => env::set_var("PKG_CONFIG_PATH", new_path),
Err(other_err) => panic!("Failed to check PKG_CONFIG_PATH: {other_err}"),
}
find_hwloc(None);
}