diff --git a/src/build.rs b/src/build.rs index 3dedfb3e..27bc89c2 100644 --- a/src/build.rs +++ b/src/build.rs @@ -928,7 +928,7 @@ fn compile_with_exec( let pkg = &unit.pkg; let capi_config = load_manifest_capi_config(pkg, rustc_target)?; let name = &capi_config.library.name; - let install_paths = InstallPaths::new(name, args, &capi_config); + let install_paths = InstallPaths::new(name, args, rustc_target, &capi_config); let pkg_rustflags = &capi_config.library.rustflags; let mut leaf_args: Vec = rustc_target @@ -1018,7 +1018,7 @@ impl CPackage { let name = &capi_config.library.name; - let install_paths = InstallPaths::new(name, args, &capi_config); + let install_paths = InstallPaths::new(name, args, rustc_target, &capi_config); let build_targets = BuildTargets::new(name, rustc_target, root_output, libkinds, &capi_config)?; diff --git a/src/cli.rs b/src/cli.rs index c46276e1..ed5713a8 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -20,13 +20,13 @@ struct Common { /// `bindir`, `datarootdir`, `includedir`, `libdir` /// /// If they are absolute the prefix is ignored. - #[clap(long = "prefix", default_value = "/usr/local")] + #[clap(long = "prefix")] prefix: PathBuf, /// Path to directory for installing generated library files - #[clap(long = "libdir", default_value = "lib")] + #[clap(long = "libdir")] libdir: PathBuf, /// Path to directory for installing generated headers files - #[clap(long = "includedir", default_value = "include")] + #[clap(long = "includedir")] includedir: PathBuf, /// Path to directory for installing generated executable files #[clap(long = "bindir", default_value = "bin")] @@ -37,7 +37,7 @@ struct Common { #[clap(long = "pkgconfigdir")] pkgconfigdir: Option, /// Path to directory for installing read-only data - #[clap(long = "datarootdir", default_value = "share")] + #[clap(long = "datarootdir")] datarootdir: PathBuf, /// Path to directory for installing read-only application-specific data /// diff --git a/src/install.rs b/src/install.rs index b5933b4c..af33bb4e 100644 --- a/src/install.rs +++ b/src/install.rs @@ -1,4 +1,5 @@ use clap::ArgMatches; +use std::env::consts; use std::path::{Component, Path, PathBuf}; use cargo::core::Workspace; @@ -6,6 +7,7 @@ use cargo_util::paths::{copy, create_dir_all}; use crate::build::*; use crate::build_targets::BuildTargets; +use crate::target::Target; fn append_to_destdir(destdir: Option<&Path>, path: &Path) -> PathBuf { if let Some(destdir) = destdir { @@ -306,15 +308,102 @@ pub struct InstallPaths { } impl InstallPaths { - pub fn new(_name: &str, args: &ArgMatches, capi_config: &CApiConfig) -> Self { + fn is_debianlike(target: &Target) -> bool { + consts::ARCH.eq_ignore_ascii_case(&target.arch) + && consts::OS.eq_ignore_ascii_case(&target.os) + && PathBuf::from("/etc/debian_version").exists() + } + + fn is_freebsd(target: &Target) -> bool { + target.os.eq_ignore_ascii_case("freebsd") + } + + fn is_haiku(target: &Target) -> bool { + target.os.eq_ignore_ascii_case("haiku") + } + + fn is_windows(target: &Target) -> bool { + target.os.eq_ignore_ascii_case("windows") + } + + fn default_libdir(target: &Target) -> PathBuf { + if Self::is_debianlike(target) { + let pc = std::process::Command::new("dpkg-architecture") + .arg("-qDEB_HOST_MULTIARCH") + .output(); + match pc { + Ok(v) => { + if v.status.success() { + let archpath = String::from_utf8_lossy(&v.stdout); + return format!("lib/{archpath}").into(); + } + } + Err(_) => {} + } + } + + if Self::is_freebsd(target) { + return "lib".into(); + } + if consts::ARCH.eq_ignore_ascii_case(&target.arch) + && consts::OS.eq_ignore_ascii_case(&target.os) + { + let usr_lib64 = PathBuf::from("/usr/lib64"); + if usr_lib64.exists() && !usr_lib64.is_symlink() { + return "lib64".into(); + } + } + "lib".into() + } + + fn default_prefix(target: &Target) -> PathBuf { + if Self::is_windows(target) { + "c:/".into() + } else if Self::is_haiku(target) { + "/boot/system/non-packaged".into() + } else { + "/usr/local".into() + } + } + + fn default_datadir(target: &Target) -> PathBuf { + if Self::is_haiku(target) { + return "data".into(); + } + "share".into() + } + + fn default_includedir(target: &Target) -> PathBuf { + if Self::is_haiku(target) { + return "develop/headers".into(); + } + "include".into() + } + + pub fn new(_name: &str, args: &ArgMatches, target: &Target, capi_config: &CApiConfig) -> Self { let destdir = args.get_one::("destdir").map(PathBuf::from); let prefix = args .get_one::("prefix") .map(PathBuf::from) - .unwrap_or_else(|| "/usr/local".into()); - let libdir = prefix.join(args.get_one::("libdir").unwrap()); - let includedir = prefix.join(args.get_one::("includedir").unwrap()); - let datarootdir = prefix.join(args.get_one::("datarootdir").unwrap()); + .unwrap_or(Self::default_prefix(target)); + let libdir = { + let default_dir = Self::default_libdir(target); + prefix.join(args.get_one::("libdir").unwrap_or(&default_dir)) + }; + let includedir = { + let default_dir = Self::default_includedir(target); + prefix.join( + args.get_one::("includedir") + .unwrap_or(&default_dir), + ) + }; + let datarootdir: PathBuf = { + let default_dir = Self::default_datadir(target); + prefix.join( + args.get_one::("datarootdir") + .unwrap_or(&default_dir), + ) + }; let datadir = args .get_one::("datadir") .map(|d| prefix.join(d))