Files
spotifast/build.rs
T
Carmine Paolino 8bd25261c9 Rename the app to Spotifast while preserving installation identities
Use Spotifast across the native app, commands, packages and documentation. Keep existing state, credential stores, protocol identities and package names; provide both command names and compatible updater payloads. Rename the guides with jekyll-redirect-from and prepare spotifast.rocks as the website domain. Keep product descriptions name-free.
2026-09-14 10:43:11 +02:00

138 lines
5.6 KiB
Rust

//! Compiles translations, embeds Windows resources and links GLEW for libprojectM.
#[path = "build_support/catalogs.rs"]
mod catalogs;
/// Known names for vcpkg's static GLEW library, in preferred order.
/// Names differ across vcpkg versions and triplets, so use the installed one.
#[cfg(windows)]
const GLEW_NAMES: &[&str] = &["glew32s", "libglew32", "glew32"];
/// Returns the vcpkg triplet matching the target architecture and CRT mode.
#[cfg(windows)]
fn vcpkg_triplet() -> Option<String> {
let arch = match std::env::var("CARGO_CFG_TARGET_ARCH").as_deref() {
Ok("x86_64") => "x64",
Ok("aarch64") => "arm64",
_ => return None,
};
let static_crt = std::env::var("CARGO_CFG_TARGET_FEATURE")
.unwrap_or_default()
.split(',')
.any(|feature| feature == "crt-static");
let suffix = if static_crt { "static" } else { "static-md" };
Some(format!("{arch}-windows-{suffix}"))
}
/// Returns the known GLEW library installed in `lib`.
#[cfg(windows)]
fn glew_library(lib: &std::path::Path) -> Option<&'static str> {
let present: Vec<String> = std::fs::read_dir(lib)
.ok()?
.flatten()
.filter_map(|entry| {
let path = entry.path();
if path.extension()?.eq_ignore_ascii_case("lib") {
Some(path.file_stem()?.to_str()?.to_ascii_lowercase())
} else {
None
}
})
.collect();
GLEW_NAMES
.iter()
.copied()
.find(|name| present.iter().any(|found| found == name))
}
fn main() {
println!("cargo:rerun-if-changed=build_support/catalogs.rs");
println!("cargo:rerun-if-changed=assets/i18n");
let output =
std::path::PathBuf::from(std::env::var_os("OUT_DIR").expect("Cargo output directory"));
let mut modules = Vec::new();
for entry in std::fs::read_dir("assets/i18n").expect("translation directory") {
let path = entry.expect("translation entry").path();
if path.extension().is_some_and(|ext| ext == "po") {
let filename = path.file_stem().expect("catalog filename");
let module = filename
.to_str()
.expect("catalog identifier")
.replace('-', "_")
.to_ascii_lowercase();
assert!(
module
.chars()
.all(|c| c.is_ascii_alphanumeric() || c == '_'),
"invalid catalog identifier"
);
let generated = output.join(filename).with_extension("rs");
catalogs::compile(&path, &generated)
.unwrap_or_else(|error| panic!("{}: {error}", path.display()));
modules.push(format!("#[path = {generated:?}]\nmod {module};\n"));
}
}
println!("cargo:rerun-if-changed=tests/fixtures/translation.po");
catalogs::compile(
std::path::Path::new("tests/fixtures/translation.po"),
&output.join("test_translation.rs"),
)
.expect("translation regression fixture");
// Generated files are modules so they retain their own module attributes.
// Sort directory entries for reproducible builds.
modules.sort();
std::fs::write(output.join("catalogs.rs"), modules.concat()).expect("catalog module index");
std::fs::write(
output.join("test_catalog.rs"),
format!(
"#[path = {:?}]\nmod fixture;\n",
output.join("test_translation.rs")
),
)
.expect("test catalog module index");
#[cfg(windows)]
if std::env::var("CARGO_CFG_TARGET_OS").as_deref() == Ok("windows") {
println!("cargo:rerun-if-changed=packaging/windows/fastpotify.ico");
let mut resource = winresource::WindowsResource::new();
resource
.set_icon("packaging/windows/fastpotify.ico")
.set("ProductName", "Spotifast")
.set("FileDescription", "A native Spotify client");
if let Err(error) = resource.compile() {
println!("cargo:warning=Windows resources not embedded: {error}");
}
// Static libprojectM requires the GLEW library installed by vcpkg.
if std::env::var_os("CARGO_FEATURE_MILKDROP").is_some() {
println!("cargo:rerun-if-env-changed=VCPKG_INSTALLATION_ROOT");
if let (Some(root), Some(triplet)) =
(std::env::var_os("VCPKG_INSTALLATION_ROOT"), vcpkg_triplet())
{
let lib = std::path::Path::new(&root)
.join("installed")
.join(triplet)
.join("lib");
println!("cargo:rustc-link-search=native={}", lib.display());
match glew_library(&lib) {
Some(name) => println!("cargo:rustc-link-lib=static={name}"),
None => {
// Include the directory listing in the error for diagnosis.
let listing = std::fs::read_dir(&lib)
.map(|entries| {
entries
.flatten()
.map(|entry| entry.file_name().to_string_lossy().into_owned())
.collect::<Vec<_>>()
.join(", ")
})
.unwrap_or_else(|error| format!("unreadable: {error}"));
println!(
"cargo:warning=no GLEW library in {}; it holds: {listing}",
lib.display()
);
}
}
}
}
}
}