pub fn target_triple_to_asset_name(target: &str) -> Option<&'static str> {
match target {
"x86_64-unknown-linux-gnu" => Some("graphviz-native-linux-x86_64.tar.gz"),
"aarch64-unknown-linux-gnu" => Some("graphviz-native-linux-aarch64.tar.gz"),
"x86_64-apple-darwin"
| "aarch64-apple-darwin"
| "universal-apple-darwin" => Some("graphviz-native-macos-universal.tar.gz"),
"aarch64-linux-android" => Some("graphviz-native-android-arm64-v8a.tar.gz"),
"armv7-linux-androideabi" => Some("graphviz-native-android-armeabi-v7a.tar.gz"),
"x86_64-linux-android" => Some("graphviz-native-android-x86_64.tar.gz"),
"i686-linux-android" => Some("graphviz-native-android-x86.tar.gz"),
"aarch64-apple-ios" => Some("graphviz-native-ios-device-arm64.tar.gz"),
"aarch64-apple-ios-sim" => Some("graphviz-native-ios-sim-arm64.tar.gz"),
"x86_64-apple-ios" => Some("graphviz-native-ios-sim-x86_64.tar.gz"),
"x86_64-pc-windows-msvc" => Some("graphviz-native-windows-x86_64.tar.gz"),
"aarch64-pc-windows-msvc" => Some("graphviz-native-windows-arm64.tar.gz"),
_ => None,
}
}
pub fn target_triple_to_prebuilt_subdir(target: &str) -> Option<(&'static str, &'static str)> {
match target {
"x86_64-unknown-linux-gnu" => {
Some(("x86_64-unknown-linux-gnu", "libgraphviz_api.a"))
}
"aarch64-unknown-linux-gnu" => {
Some(("aarch64-unknown-linux-gnu", "libgraphviz_api.a"))
}
"x86_64-apple-darwin" => Some(("x86_64-apple-darwin", "libgraphviz_api.a")),
"aarch64-apple-darwin" => Some(("aarch64-apple-darwin", "libgraphviz_api.a")),
"aarch64-apple-ios" => Some(("aarch64-apple-ios", "libgraphviz_api.a")),
"aarch64-apple-ios-sim" => Some(("aarch64-apple-ios-sim", "libgraphviz_api.a")),
"x86_64-apple-ios" => Some(("x86_64-apple-ios", "libgraphviz_api.a")),
"x86_64-pc-windows-msvc" => {
Some(("x86_64-pc-windows-msvc", "graphviz_api.lib"))
}
"aarch64-pc-windows-msvc" => Some(("aarch64-pc-windows-msvc", "graphviz_api.lib")),
_ => None,
}
}
pub fn target_triple_to_output_dirs(target: &str) -> &'static [&'static str] {
match target {
"x86_64-unknown-linux-gnu" => &["output/linux-x86_64/lib", "output/linux/lib"],
"aarch64-unknown-linux-gnu" => &["output/linux-aarch64/lib", "output/linux/lib"],
"x86_64-apple-darwin"
| "aarch64-apple-darwin"
| "universal-apple-darwin" => &["output/macos-universal/lib"],
"aarch64-linux-android" => &["output/android/arm64-v8a/lib"],
"armv7-linux-androideabi" => &["output/android/armeabi-v7a/lib"],
"x86_64-linux-android" => &["output/android/x86_64/lib"],
"i686-linux-android" => &["output/android/x86/lib"],
"aarch64-apple-ios" => &["output/ios/iphoneos-arm64/lib"],
"aarch64-apple-ios-sim" => &["output/ios/iphonesimulator-arm64/lib"],
"x86_64-apple-ios" => &["output/ios/iphonesimulator-x86_64/lib"],
"x86_64-pc-windows-msvc" => &[
"output/windows-x86_64/lib",
"output/windows-x86_64/bin",
],
"aarch64-pc-windows-msvc" => &[
"output/windows-arm64/lib",
"output/windows-arm64/bin",
],
_ => &[],
}
}
pub fn is_ios_target(target: &str) -> bool {
matches!(
target,
"aarch64-apple-ios" | "aarch64-apple-ios-sim" | "x86_64-apple-ios"
)
}
pub fn legacy_prebuilt_is_compatible(host: &str, target: &str) -> bool {
!host.is_empty() && host == target
}
pub fn asset_is_static(target: &str) -> bool {
is_ios_target(target)
|| target.contains("windows-msvc")
|| target.contains("unknown-linux-gnu")
|| target.contains("apple-darwin")
}
pub fn asset_lib_filename(target: &str) -> &'static str {
match target {
"x86_64-apple-darwin"
| "aarch64-apple-darwin"
| "universal-apple-darwin" => "libgraphviz_api.a",
t if is_ios_target(t) => "libgraphviz_api.a",
t if t.contains("windows-msvc") => "graphviz_api.lib",
t if t.contains("unknown-linux-gnu") => "libgraphviz_api.a",
_ => "libgraphviz_api.so",
}
}
pub fn find_static_override(
lib_dirs: &[std::path::PathBuf],
target_os: &str,
) -> Option<(std::path::PathBuf, &'static str)> {
if target_os != "windows" {
return lib_dirs
.iter()
.map(|dir| dir.join("libgraphviz_api.a"))
.find(|path| path.is_file())
.map(|path| (path, "graphviz_api"));
}
if let Some(path) = lib_dirs
.iter()
.map(|dir| dir.join("graphviz_api_static.lib"))
.find(|path| path.is_file())
{
return Some((path, "graphviz_api_static"));
}
let has_dll = lib_dirs.iter().any(|lib_dir| {
lib_dir.join("graphviz_api.dll").is_file()
|| lib_dir
.parent()
.map_or(false, |parent| parent.join("bin/graphviz_api.dll").is_file())
});
if has_dll {
return None;
}
lib_dirs
.iter()
.map(|dir| dir.join("graphviz_api.lib"))
.find(|path| path.is_file())
.map(|path| (path, "graphviz_api"))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn linux_x86_64_asset() {
assert_eq!(
target_triple_to_asset_name("x86_64-unknown-linux-gnu"),
Some("graphviz-native-linux-x86_64.tar.gz")
);
}
#[test]
fn linux_aarch64_asset() {
assert_eq!(
target_triple_to_asset_name("aarch64-unknown-linux-gnu"),
Some("graphviz-native-linux-aarch64.tar.gz")
);
}
#[test]
fn macos_asset_universal() {
assert_eq!(
target_triple_to_asset_name("x86_64-apple-darwin"),
Some("graphviz-native-macos-universal.tar.gz")
);
assert_eq!(
target_triple_to_asset_name("aarch64-apple-darwin"),
Some("graphviz-native-macos-universal.tar.gz")
);
}
#[test]
fn android_assets() {
assert_eq!(
target_triple_to_asset_name("aarch64-linux-android"),
Some("graphviz-native-android-arm64-v8a.tar.gz")
);
assert_eq!(
target_triple_to_asset_name("armv7-linux-androideabi"),
Some("graphviz-native-android-armeabi-v7a.tar.gz")
);
assert_eq!(
target_triple_to_asset_name("x86_64-linux-android"),
Some("graphviz-native-android-x86_64.tar.gz")
);
assert_eq!(
target_triple_to_asset_name("i686-linux-android"),
Some("graphviz-native-android-x86.tar.gz")
);
}
#[test]
fn ios_device_asset() {
assert_eq!(
target_triple_to_asset_name("aarch64-apple-ios"),
Some("graphviz-native-ios-device-arm64.tar.gz")
);
}
#[test]
fn ios_simulator_assets() {
assert_eq!(
target_triple_to_asset_name("aarch64-apple-ios-sim"),
Some("graphviz-native-ios-sim-arm64.tar.gz")
);
assert_eq!(
target_triple_to_asset_name("x86_64-apple-ios"),
Some("graphviz-native-ios-sim-x86_64.tar.gz")
);
}
#[test]
fn windows_arm64_asset() {
assert_eq!(
target_triple_to_asset_name("aarch64-pc-windows-msvc"),
Some("graphviz-native-windows-arm64.tar.gz")
);
}
#[test]
fn windows_x86_64_asset() {
assert_eq!(
target_triple_to_asset_name("x86_64-pc-windows-msvc"),
Some("graphviz-native-windows-x86_64.tar.gz")
);
}
#[test]
fn unknown_target_returns_none() {
assert_eq!(target_triple_to_asset_name("wasm32-unknown-unknown"), None);
assert_eq!(target_triple_to_asset_name("riscv64gc-unknown-linux-gnu"), None);
}
#[test]
fn prebuilt_subdir_ios_device() {
let (subdir, lib) = target_triple_to_prebuilt_subdir("aarch64-apple-ios").unwrap();
assert_eq!(subdir, "aarch64-apple-ios");
assert_eq!(lib, "libgraphviz_api.a");
}
#[test]
fn prebuilt_subdir_ios_sim_arm64() {
let (subdir, lib) = target_triple_to_prebuilt_subdir("aarch64-apple-ios-sim").unwrap();
assert_eq!(subdir, "aarch64-apple-ios-sim");
assert_eq!(lib, "libgraphviz_api.a");
}
#[test]
fn prebuilt_subdir_linux_aarch64() {
let (subdir, lib) = target_triple_to_prebuilt_subdir("aarch64-unknown-linux-gnu").unwrap();
assert_eq!(subdir, "aarch64-unknown-linux-gnu");
assert_eq!(lib, "libgraphviz_api.a");
}
#[test]
fn prebuilt_subdir_android_x86() {
assert_eq!(target_triple_to_prebuilt_subdir("i686-linux-android"), None);
}
#[test]
fn prebuilt_subdir_windows_arm64() {
let (subdir, lib) = target_triple_to_prebuilt_subdir("aarch64-pc-windows-msvc").unwrap();
assert_eq!(subdir, "aarch64-pc-windows-msvc");
assert_eq!(lib, "graphviz_api.lib");
}
#[test]
fn output_dirs_ios_device() {
let dirs = target_triple_to_output_dirs("aarch64-apple-ios");
assert_eq!(dirs, &["output/ios/iphoneos-arm64/lib"]);
}
#[test]
fn output_dirs_ios_sim_arm64() {
let dirs = target_triple_to_output_dirs("aarch64-apple-ios-sim");
assert_eq!(dirs, &["output/ios/iphonesimulator-arm64/lib"]);
}
#[test]
fn output_dirs_ios_sim_x86_64() {
let dirs = target_triple_to_output_dirs("x86_64-apple-ios");
assert_eq!(dirs, &["output/ios/iphonesimulator-x86_64/lib"]);
}
#[test]
fn output_dirs_linux_aarch64() {
let dirs = target_triple_to_output_dirs("aarch64-unknown-linux-gnu");
assert!(dirs.contains(&"output/linux-aarch64/lib"));
}
#[test]
fn output_dirs_android_x86() {
let dirs = target_triple_to_output_dirs("i686-linux-android");
assert_eq!(dirs, &["output/android/x86/lib"]);
}
#[test]
fn asset_lib_filename_ios_is_static() {
assert_eq!(asset_lib_filename("aarch64-apple-ios"), "libgraphviz_api.a");
assert_eq!(asset_lib_filename("aarch64-apple-ios-sim"), "libgraphviz_api.a");
assert_eq!(asset_lib_filename("x86_64-apple-ios"), "libgraphviz_api.a");
}
#[test]
fn asset_lib_filename_macos_is_static() {
assert_eq!(asset_lib_filename("aarch64-apple-darwin"), "libgraphviz_api.a");
}
#[test]
fn asset_lib_filename_linux_is_static() {
assert_eq!(asset_lib_filename("x86_64-unknown-linux-gnu"), "libgraphviz_api.a");
}
#[test]
fn asset_lib_filename_windows_is_static_import_name() {
assert_eq!(asset_lib_filename("x86_64-pc-windows-msvc"), "graphviz_api.lib");
}
#[test]
fn is_ios_target_recognition() {
assert!(is_ios_target("aarch64-apple-ios"));
assert!(is_ios_target("aarch64-apple-ios-sim"));
assert!(is_ios_target("x86_64-apple-ios"));
assert!(!is_ios_target("aarch64-apple-darwin"));
assert!(!is_ios_target("aarch64-linux-android"));
}
#[test]
fn legacy_prebuilt_is_native_only() {
assert!(legacy_prebuilt_is_compatible(
"aarch64-apple-darwin",
"aarch64-apple-darwin"
));
assert!(!legacy_prebuilt_is_compatible(
"aarch64-apple-darwin",
"x86_64-apple-darwin"
));
assert!(!legacy_prebuilt_is_compatible(
"x86_64-unknown-linux-gnu",
"aarch64-unknown-linux-gnu"
));
assert!(!legacy_prebuilt_is_compatible(
"",
"x86_64-pc-windows-msvc"
));
}
#[test]
fn asset_is_static_for_desktop_and_ios() {
assert!(asset_is_static("aarch64-apple-ios"));
assert!(asset_is_static("aarch64-apple-ios-sim"));
assert!(asset_is_static("x86_64-apple-ios"));
assert!(asset_is_static("x86_64-pc-windows-msvc"));
assert!(asset_is_static("x86_64-unknown-linux-gnu"));
assert!(asset_is_static("aarch64-unknown-linux-gnu"));
assert!(asset_is_static("aarch64-apple-darwin"));
assert!(asset_is_static("x86_64-apple-darwin"));
assert!(!asset_is_static("aarch64-linux-android"));
}
#[test]
fn incompatible_abi_assets_are_not_auto_selected() {
assert_eq!(target_triple_to_asset_name("x86_64-unknown-linux-musl"), None);
assert_eq!(target_triple_to_asset_name("aarch64-unknown-linux-musl"), None);
assert_eq!(target_triple_to_asset_name("x86_64-pc-windows-gnu"), None);
assert_eq!(target_triple_to_prebuilt_subdir("x86_64-unknown-linux-musl"), None);
assert_eq!(target_triple_to_prebuilt_subdir("x86_64-pc-windows-gnu"), None);
assert!(target_triple_to_output_dirs("aarch64-unknown-linux-musl").is_empty());
assert!(target_triple_to_output_dirs("x86_64-pc-windows-gnu").is_empty());
}
#[test]
fn windows_override_prefers_merged_static_archive() {
let root = std::env::temp_dir().join(format!(
"graphviz-anywhere-static-override-{}",
std::process::id()
));
let lib = root.join("lib");
let bin = root.join("bin");
std::fs::create_dir_all(&lib).unwrap();
std::fs::create_dir_all(&bin).unwrap();
std::fs::write(lib.join("graphviz_api.lib"), b"import").unwrap();
std::fs::write(lib.join("graphviz_api_static.lib"), b"static").unwrap();
std::fs::write(bin.join("graphviz_api.dll"), b"dll").unwrap();
let resolved = find_static_override(std::slice::from_ref(&lib), "windows").unwrap();
assert_eq!(resolved.0, lib.join("graphviz_api_static.lib"));
assert_eq!(resolved.1, "graphviz_api_static");
std::fs::remove_dir_all(root).unwrap();
}
#[test]
fn windows_override_rejects_import_library_as_static() {
let root = std::env::temp_dir().join(format!(
"graphviz-anywhere-import-override-{}",
std::process::id()
));
let lib = root.join("lib");
let bin = root.join("bin");
std::fs::create_dir_all(&lib).unwrap();
std::fs::create_dir_all(&bin).unwrap();
std::fs::write(lib.join("graphviz_api.lib"), b"import").unwrap();
std::fs::write(bin.join("graphviz_api.dll"), b"dll").unwrap();
assert!(find_static_override(&[lib], "windows").is_none());
std::fs::remove_dir_all(root).unwrap();
}
#[test]
fn windows_release_canonical_library_is_static_without_dll() {
let root = std::env::temp_dir().join(format!(
"graphviz-anywhere-release-override-{}",
std::process::id()
));
let lib = root.join("lib");
std::fs::create_dir_all(&lib).unwrap();
std::fs::write(lib.join("graphviz_api.lib"), b"static").unwrap();
let resolved = find_static_override(std::slice::from_ref(&lib), "windows").unwrap();
assert_eq!(resolved.0, lib.join("graphviz_api.lib"));
assert_eq!(resolved.1, "graphviz_api");
std::fs::remove_dir_all(root).unwrap();
}
#[test]
fn asset_is_static_agrees_with_lib_filename() {
for target in [
"aarch64-apple-ios",
"x86_64-unknown-linux-gnu",
"aarch64-apple-darwin",
"aarch64-linux-android",
"x86_64-pc-windows-msvc",
] {
let lib_name = asset_lib_filename(target);
let ships_archive = lib_name.ends_with(".a") || lib_name.ends_with(".lib");
assert_eq!(
asset_is_static(target),
ships_archive,
"asset_is_static and asset_lib_filename disagree for {target}"
);
}
}
}