Skip to content

Commit

Permalink
Implement heuristics for target-specific install paths
Browse files Browse the repository at this point in the history
  • Loading branch information
amyspark committed May 4, 2024
1 parent 6fc7e69 commit df5e11c
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 11 deletions.
4 changes: 2 additions & 2 deletions src/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<String> = rustc_target
Expand Down Expand Up @@ -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)?;

Expand Down
8 changes: 4 additions & 4 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
Expand All @@ -37,7 +37,7 @@ struct Common {
#[clap(long = "pkgconfigdir")]
pkgconfigdir: Option<PathBuf>,
/// 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
///
Expand Down
99 changes: 94 additions & 5 deletions src/install.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
use clap::ArgMatches;
use std::env::consts;
use std::path::{Component, Path, PathBuf};

use cargo::core::Workspace;
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 {
Expand Down Expand Up @@ -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::<PathBuf>("destdir").map(PathBuf::from);
let prefix = args
.get_one::<PathBuf>("prefix")
.map(PathBuf::from)
.unwrap_or_else(|| "/usr/local".into());
let libdir = prefix.join(args.get_one::<PathBuf>("libdir").unwrap());
let includedir = prefix.join(args.get_one::<PathBuf>("includedir").unwrap());
let datarootdir = prefix.join(args.get_one::<PathBuf>("datarootdir").unwrap());
.unwrap_or(Self::default_prefix(target));
let libdir = {
let default_dir = Self::default_libdir(target);
prefix.join(args.get_one::<PathBuf>("libdir").unwrap_or(&default_dir))
};
let includedir = {
let default_dir = Self::default_includedir(target);
prefix.join(
args.get_one::<PathBuf>("includedir")
.unwrap_or(&default_dir),
)
};
let datarootdir: PathBuf = {
let default_dir = Self::default_datadir(target);
prefix.join(
args.get_one::<PathBuf>("datarootdir")
.unwrap_or(&default_dir),
)
};
let datadir = args
.get_one::<PathBuf>("datadir")
.map(|d| prefix.join(d))
Expand Down

0 comments on commit df5e11c

Please sign in to comment.