use anyhow::{bail, Context, Result};
pub const RELEASE_REPO: &str = "ConradIrwin/corgi";
pub fn platform(host: &str) -> Result<&'static str> {
let platform = match host {
"aarch64-apple-darwin" => "macos-arm64",
"x86_64-unknown-linux-gnu" => "linux-x64",
"aarch64-unknown-linux-gnu" => "linux-arm64",
_ => bail!(
"Corgi has no pinned llvm-tools artifact for host `{host}` \
(published for aarch64-apple-darwin and x86_64/aarch64 Linux)"
),
};
Ok(platform)
}
pub fn is_supported(host: &str) -> bool {
platform(host).is_ok()
}
pub fn required_files(host: &str) -> &'static [&'static str] {
if host.ends_with("-apple-darwin") {
&[DYLIB_RELATIVE, DSYMUTIL_RELATIVE]
} else {
&[SHARED_OBJECT_RELATIVE, "lib/libstdc++.so.6"]
}
}
pub fn tag(host: &str) -> Result<String> {
Ok(match platform(host)? {
"macos-arm64" => format!("llvm-tools-{}", crate::zig::VERSION),
platform => format!("llvm-tools-{}-{platform}", crate::zig::VERSION),
})
}
pub fn asset_name(host: &str) -> Result<String> {
Ok(format!("llvm-tools-{}.tar.zst", platform(host)?))
}
pub fn url(host: &str) -> Result<String> {
Ok(format!(
"https://github.com/{RELEASE_REPO}/releases/download/{}/{}",
tag(host)?,
asset_name(host)?
))
}
#[cfg(not(debug_assertions))]
pub fn expected_sha256(host: &str) -> Option<&'static str> {
match platform(host).ok()? {
"macos-arm64" => option_env!("CORGI_LLVM_TOOLS_SHA256"),
"linux-x64" => option_env!("CORGI_LLVM_TOOLS_SHA256_LINUX_X64"),
"linux-arm64" => option_env!("CORGI_LLVM_TOOLS_SHA256_LINUX_ARM64"),
_ => None,
}
}
#[cfg(debug_assertions)]
pub fn expected_sha256(_host: &str) -> Option<&'static str> {
None
}
pub const DYLIB_RELATIVE: &str = "lib/libclang.dylib";
pub const SHARED_OBJECT_RELATIVE: &str = "lib/libclang.so";
pub const DSYMUTIL_RELATIVE: &str = "bin/dsymutil";
pub const CLANG_RESOURCE_PARENT: &str = "lib/clang";
pub fn compiler_rt_dir(root: &std::path::Path) -> Result<std::path::PathBuf> {
Ok(resource_dir(root)?.join("lib/darwin"))
}
pub fn resource_dir(root: &std::path::Path) -> Result<std::path::PathBuf> {
let parent = root.join(CLANG_RESOURCE_PARENT);
let mut versions = std::fs::read_dir(&parent)
.with_context(|| format!("reading {}", parent.display()))?
.filter_map(|entry| entry.ok().map(|entry| entry.path()))
.filter(|path| path.is_dir());
let version = versions
.next()
.with_context(|| format!("no Clang resource version under {}", parent.display()))?;
if versions.next().is_some() {
bail!(
"multiple Clang resource versions under {}; expected exactly one",
parent.display()
);
}
Ok(version)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn tag_follows_zig_version_and_platform() {
let version = crate::zig::VERSION;
assert_eq!(
tag("aarch64-apple-darwin").unwrap(),
format!("llvm-tools-{version}")
);
assert_eq!(
tag("aarch64-unknown-linux-gnu").unwrap(),
format!("llvm-tools-{version}-linux-arm64")
);
}
#[test]
fn arm_mac_is_supported_with_release_urls() {
let host = "aarch64-apple-darwin";
assert!(is_supported(host));
let url = url(host).unwrap();
assert_eq!(
url,
format!(
"https://github.com/ConradIrwin/corgi/releases/download/llvm-tools-{}/llvm-tools-macos-arm64.tar.zst",
crate::zig::VERSION
)
);
}
#[test]
fn artifact_names_the_llvm_tools_family_and_exposes_dsymutil() {
assert_eq!(DYLIB_RELATIVE, "lib/libclang.dylib");
assert_eq!(DSYMUTIL_RELATIVE, "bin/dsymutil");
assert!(url("aarch64-apple-darwin")
.unwrap()
.contains("llvm-tools-macos-arm64.tar.zst"));
}
#[test]
fn intel_mac_is_unsupported_for_now() {
assert!(!is_supported("x86_64-apple-darwin"));
assert!(platform("x86_64-apple-darwin").is_err());
assert!(url("x86_64-apple-darwin").is_err());
}
#[test]
fn linux_artifacts_bundle_libstdcxx_instead_of_dsymutil() {
let host = "x86_64-unknown-linux-gnu";
assert!(url(host).unwrap().ends_with(&format!(
"/llvm-tools-{}-linux-x64/llvm-tools-linux-x64.tar.zst",
crate::zig::VERSION
)));
assert_eq!(
required_files(host),
["lib/libclang.so", "lib/libstdc++.so.6"]
);
assert!(!is_supported("x86_64-unknown-linux-musl"));
}
}