extern crate pkg_config;
#[cfg(feature = "use-bindgen")]
extern crate bindgen;
fn main() {
match pkg_config::Config::new().statik(false).probe("alsa") {
Err(pkg_config::Error::Failure { command, output }) => panic!(
"Pkg-config failed - usually this is because alsa development headers are not installed.\n\n\
For Fedora users:\n# dnf install alsa-lib-devel\n\n\
For Debian/Ubuntu users:\n# apt-get install libasound2-dev\n\n\
For Archlinux users:\n# pacman -S alsa-lib\n\n
pkg_config details:\n{}\n", pkg_config::Error::Failure { command, output }),
Err(e) => panic!("{}", e),
Ok(alsa_library) => {
probe_time64(&alsa_library);
#[cfg(feature = "use-bindgen")]
generate_bindings(&alsa_library);
}
};
}
fn probe_time64(alsa_library: &pkg_config::Library) {
println!("cargo:rustc-check-cfg=cfg(alsa_sys_time64)");
let target_os = std::env::var("CARGO_CFG_TARGET_OS");
let target_env = std::env::var("CARGO_CFG_TARGET_ENV");
let target_pointer_width = std::env::var("CARGO_CFG_TARGET_POINTER_WIDTH");
if target_os.is_ok_and(|v| v != "linux")
|| target_env.is_ok_and(|v| v != "gnu")
|| target_pointer_width.is_ok_and(|v| v != "32")
{
return;
}
let out_dir = std::path::PathBuf::from(std::env::var("OUT_DIR").unwrap());
let include_paths = &alsa_library.include_paths;
if let Err(e) = try_compile(
&out_dir,
include_paths,
"time64_control.c",
"#include <alsa/asoundlib.h>\n\
_Static_assert(sizeof(snd_htimestamp_t) == 8\n\
|| sizeof(snd_htimestamp_t) == 16, \"unexpected snd_htimestamp_t\");\n",
) {
panic!(
"alsa-sys could not compile a probe measuring sizeof(snd_htimestamp_t) \
against the ALSA headers.\n
Check that the C compiler and the ALSA headers are installed.
If you still have a problem, please post an issue here:\n
https://github.com/diwic/alsa-sys\n\n
{}",
e
);
}
if try_compile(
&out_dir,
include_paths,
"time64_probe.c",
"#include <alsa/asoundlib.h>\n\
_Static_assert(sizeof(snd_htimestamp_t) == 16, \"64-bit time_t\");\n",
)
.is_ok()
{
println!("cargo:rustc-cfg=alsa_sys_time64");
}
}
fn try_compile(
out_dir: &std::path::Path,
include_paths: &[std::path::PathBuf],
name: &str,
source: &str,
) -> Result<(), String> {
let path = out_dir.join(name);
std::fs::write(&path, source).map_err(|e| e.to_string())?;
cc::Build::new()
.file(&path)
.includes(include_paths)
.cargo_metadata(false)
.cargo_warnings(false)
.warnings(false)
.try_compile(name.trim_end_matches(".c"))
.map_err(|e| e.to_string())
}
#[cfg(feature = "use-bindgen")]
fn generate_bindings(alsa_library: &pkg_config::Library) {
use std::env;
use std::path::PathBuf;
let clang_include_args = alsa_library.include_paths.iter().map(|include_path| {
format!(
"-I{}",
include_path.to_str().expect("include path was not UTF-8")
)
});
let mut codegen_config = bindgen::CodegenConfig::empty();
codegen_config.insert(bindgen::CodegenConfig::FUNCTIONS);
codegen_config.insert(bindgen::CodegenConfig::TYPES);
codegen_config.insert(bindgen::CodegenConfig::VARS);
let builder = bindgen::Builder::default()
.use_core()
.size_t_is_usize(true)
.allowlist_recursively(false)
.prepend_enum_name(false)
.layout_tests(false)
.allowlist_function("snd_.*")
.allowlist_type("_?snd_.*")
.allowlist_type(".*va_list.*")
.allowlist_var("SND_.*")
.fit_macro_constants(false)
.with_codegen_config(codegen_config)
.clang_args(clang_include_args)
.header("wrapper.h")
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()));
let bindings = builder.generate().expect("Unable to generate bindings");
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
bindings
.write_to_file(out_path.join("generated.rs"))
.expect("Couldn't write bindings");
}