feat: add support for customizable installation directories in build flags

This commit is contained in:
2026-03-08 21:11:50 -05:00
parent be0288440a
commit a10c7227be
9 changed files with 648 additions and 26 deletions
+5
View File
@@ -7,6 +7,11 @@ cc = "gcc"
cflags = ["-O2"]
cflags += ["-pipe"]
# Optional install directory overrides for supported builders
#bindir = "/usr/bin"
#libdir = "/usr/lib"
#sysconfdir = "/etc"
# Default LDFLAGS
ldflags = ["-Wl,-O1"]
+14
View File
@@ -13,6 +13,20 @@ cflags = ["-O2"]
# Append additional flags (demonstrates += append support)
cflags += ["-g"]
# Optional install directory overrides for supported builders
#bindir = "/usr/bin"
#sbindir = "/usr/bin"
#libdir = "/usr/lib"
#libexecdir = "/usr/lib"
#sysconfdir = "/etc"
#localstatedir = "/var"
#sharedstatedir = "/var/lib"
#includedir = "/usr/include"
#datarootdir = "/usr/share"
#datadir = "/usr/share"
#mandir = "/usr/share/man"
#infodir = "/usr/share/info"
# Linker flags
ldflags = ["-Wl,-O1"]
+5
View File
@@ -8,3 +8,8 @@ cc = "clang"
cflags = ["-O2"]
cflags += ["-g"]
carch = "x86_64"
# Optional install directory overrides for supported builders
#bindir = "/usr/local/bin"
#sbindir = "/usr/local/sbin"
#libdir = "/usr/local/lib"
+13 -18
View File
@@ -442,25 +442,20 @@ fn default_configure_install_dirs(
flags: &crate::package::BuildFlags,
help_text: Option<&str>,
) -> Vec<String> {
let libdir = if flags.lib32_variant {
"/usr/lib32"
} else {
"/usr/lib"
};
let bindir = nonempty_trimmed(&flags.bindir).unwrap_or("/usr/bin");
let dirs = crate::builder::install_dirs(flags);
let defaults = [
("--bindir", bindir),
("--sbindir", "/usr/bin"),
("--libdir", libdir),
("--libexecdir", libdir),
("--sysconfdir", "/etc"),
("--localstatedir", "/var"),
("--sharedstatedir", "/var/lib"),
("--includedir", "/usr/include"),
("--datarootdir", "/usr/share"),
("--datadir", "/usr/share"),
("--mandir", "/usr/share/man"),
("--infodir", "/usr/share/info"),
("--bindir", dirs.bindir),
("--sbindir", dirs.sbindir),
("--libdir", dirs.libdir),
("--libexecdir", dirs.libexecdir),
("--sysconfdir", dirs.sysconfdir),
("--localstatedir", dirs.localstatedir),
("--sharedstatedir", dirs.sharedstatedir),
("--includedir", dirs.includedir),
("--datarootdir", dirs.datarootdir),
("--datadir", dirs.datadir),
("--mandir", dirs.mandir),
("--infodir", dirs.infodir),
];
defaults
+134 -8
View File
@@ -35,12 +35,8 @@ pub fn build(
let env_vars = crate::builder::standard_build_env(spec, cross, true, export_compiler_flags);
// Extract prefix from configure flags (cmake-style -DCMAKE_INSTALL_PREFIX=)
let prefix = flags
.configure
.iter()
.find(|s| s.contains("CMAKE_INSTALL_PREFIX="))
.and_then(|s| s.split('=').nth(1))
.unwrap_or(&flags.prefix);
let prefix = cmake_cache_entry_value(&flags.configure, "CMAKE_INSTALL_PREFIX")
.unwrap_or(flags.prefix.as_str());
// Generate toolchain file if cross-compiling
let toolchain_file = if let Some(cc_cfg) = cross {
@@ -64,6 +60,9 @@ pub fn build(
cmake_cmd.arg("-B").arg(&build_dir);
cmake_cmd.arg(format!("-DCMAKE_INSTALL_PREFIX={}", prefix));
cmake_cmd.arg("-DCMAKE_BUILD_TYPE=Release");
for arg in cmake_install_dir_args(flags) {
cmake_cmd.arg(arg);
}
// Add toolchain file for cross-compilation
if let Some(ref tf) = toolchain_file {
@@ -283,12 +282,47 @@ fn cmake_configure_flags_specify_generator(flags: &[String]) -> bool {
}
fn cmake_configure_flags_set_make_program(flags: &[String]) -> bool {
flags.iter().any(|flag| {
cmake_cache_entry_value(flags, "CMAKE_MAKE_PROGRAM").is_some()
}
fn cmake_cache_entry_value<'a>(flags: &'a [String], variable: &str) -> Option<&'a str> {
let plain_prefix = format!("-D{variable}=");
let typed_prefix = format!("-D{variable}:");
flags.iter().find_map(|flag| {
let trimmed = flag.trim();
trimmed.starts_with("-DCMAKE_MAKE_PROGRAM=")
if let Some(value) = trimmed.strip_prefix(&plain_prefix) {
return Some(value);
}
trimmed
.strip_prefix(&typed_prefix)
.and_then(|rest| rest.split_once('=').map(|(_, value)| value))
})
}
fn cmake_install_dir_args(flags: &crate::package::BuildFlags) -> Vec<String> {
let dirs = crate::builder::install_dirs(flags);
let defaults = [
("CMAKE_INSTALL_BINDIR", dirs.bindir),
("CMAKE_INSTALL_SBINDIR", dirs.sbindir),
("CMAKE_INSTALL_LIBDIR", dirs.libdir),
("CMAKE_INSTALL_LIBEXECDIR", dirs.libexecdir),
("CMAKE_INSTALL_SYSCONFDIR", dirs.sysconfdir),
("CMAKE_INSTALL_LOCALSTATEDIR", dirs.localstatedir),
("CMAKE_INSTALL_SHAREDSTATEDIR", dirs.sharedstatedir),
("CMAKE_INSTALL_INCLUDEDIR", dirs.includedir),
("CMAKE_INSTALL_DATAROOTDIR", dirs.datarootdir),
("CMAKE_INSTALL_DATADIR", dirs.datadir),
("CMAKE_INSTALL_MANDIR", dirs.mandir),
("CMAKE_INSTALL_INFODIR", dirs.infodir),
];
defaults
.into_iter()
.filter(|(variable, _)| cmake_cache_entry_value(&flags.configure, variable).is_none())
.map(|(variable, value)| format!("-D{variable}={value}"))
.collect()
}
fn num_cpus() -> usize {
std::thread::available_parallelism()
.map(|n| n.get())
@@ -429,6 +463,98 @@ mod tests {
]));
}
#[test]
fn test_cmake_cache_entry_value_supports_plain_and_typed_entries() {
let flags = vec![
"-DCMAKE_INSTALL_PREFIX=/usr".to_string(),
"-DCMAKE_INSTALL_LIBDIR:PATH=/usr/lib64".to_string(),
];
assert_eq!(
cmake_cache_entry_value(&flags, "CMAKE_INSTALL_PREFIX"),
Some("/usr")
);
assert_eq!(
cmake_cache_entry_value(&flags, "CMAKE_INSTALL_LIBDIR"),
Some("/usr/lib64")
);
assert_eq!(
cmake_cache_entry_value(&flags, "CMAKE_INSTALL_BINDIR"),
None
);
}
#[test]
fn test_cmake_install_dir_args_include_defaults() {
let args = cmake_install_dir_args(&BuildFlags::default());
assert!(args.iter().any(|a| a == "-DCMAKE_INSTALL_BINDIR=/usr/bin"));
assert!(args.iter().any(|a| a == "-DCMAKE_INSTALL_SBINDIR=/usr/bin"));
assert!(args.iter().any(|a| a == "-DCMAKE_INSTALL_LIBDIR=/usr/lib"));
assert!(
args.iter()
.any(|a| a == "-DCMAKE_INSTALL_LIBEXECDIR=/usr/lib")
);
assert!(args.iter().any(|a| a == "-DCMAKE_INSTALL_SYSCONFDIR=/etc"));
assert!(
args.iter()
.any(|a| a == "-DCMAKE_INSTALL_LOCALSTATEDIR=/var")
);
assert!(
args.iter()
.any(|a| a == "-DCMAKE_INSTALL_SHAREDSTATEDIR=/var/lib")
);
assert!(
args.iter()
.any(|a| a == "-DCMAKE_INSTALL_INCLUDEDIR=/usr/include")
);
assert!(
args.iter()
.any(|a| a == "-DCMAKE_INSTALL_DATAROOTDIR=/usr/share")
);
assert!(
args.iter()
.any(|a| a == "-DCMAKE_INSTALL_DATADIR=/usr/share")
);
assert!(
args.iter()
.any(|a| a == "-DCMAKE_INSTALL_MANDIR=/usr/share/man")
);
assert!(
args.iter()
.any(|a| a == "-DCMAKE_INSTALL_INFODIR=/usr/share/info")
);
}
#[test]
fn test_cmake_install_dir_args_respect_explicit_user_overrides() {
let flags = BuildFlags {
configure: vec![
"-DCMAKE_INSTALL_SBINDIR=/sbin".to_string(),
"-DCMAKE_INSTALL_LIBDIR:PATH=/custom/lib".to_string(),
"-DCMAKE_INSTALL_DATADIR=/custom/share".to_string(),
],
..BuildFlags::default()
};
let args = cmake_install_dir_args(&flags);
assert!(
!args
.iter()
.any(|a| a.starts_with("-DCMAKE_INSTALL_SBINDIR="))
);
assert!(
!args
.iter()
.any(|a| a.starts_with("-DCMAKE_INSTALL_LIBDIR="))
);
assert!(
!args
.iter()
.any(|a| a.starts_with("-DCMAKE_INSTALL_DATADIR="))
);
assert!(args.iter().any(|a| a == "-DCMAKE_INSTALL_BINDIR=/usr/bin"));
}
#[test]
fn resolve_actual_src_prefers_srcdir_then_specdir_and_handles_absolute() {
let tmp = tempdir().unwrap();
+54
View File
@@ -162,10 +162,29 @@ fn meson_setup_args(
env_vars: &[(String, String)],
) -> Vec<String> {
let mut args = Vec::new();
let dirs = crate::builder::install_dirs(flags);
if !has_option(&flags.configure, "--prefix") {
args.push(format!("--prefix={}", flags.prefix));
}
for (option, value) in [
("--bindir", dirs.bindir),
("--sbindir", dirs.sbindir),
("--libdir", dirs.libdir),
("--libexecdir", dirs.libexecdir),
("--sysconfdir", dirs.sysconfdir),
("--localstatedir", dirs.localstatedir),
("--sharedstatedir", dirs.sharedstatedir),
("--includedir", dirs.includedir),
("--datarootdir", dirs.datarootdir),
("--datadir", dirs.datadir),
("--mandir", dirs.mandir),
("--infodir", dirs.infodir),
] {
if !has_option(&flags.configure, option) {
args.push(format!("{option}={value}"));
}
}
if !has_option(&flags.configure, "--buildtype") {
args.push("--buildtype=release".to_string());
}
@@ -275,6 +294,23 @@ mod tests {
assert!(args.iter().any(|a| a == "--buildtype=release"));
}
#[test]
fn test_meson_setup_args_include_install_dirs() {
let args = meson_setup_args(&BuildFlags::default(), None, &[]);
assert!(args.iter().any(|a| a == "--bindir=/usr/bin"));
assert!(args.iter().any(|a| a == "--sbindir=/usr/bin"));
assert!(args.iter().any(|a| a == "--libdir=/usr/lib"));
assert!(args.iter().any(|a| a == "--libexecdir=/usr/lib"));
assert!(args.iter().any(|a| a == "--sysconfdir=/etc"));
assert!(args.iter().any(|a| a == "--localstatedir=/var"));
assert!(args.iter().any(|a| a == "--sharedstatedir=/var/lib"));
assert!(args.iter().any(|a| a == "--includedir=/usr/include"));
assert!(args.iter().any(|a| a == "--datarootdir=/usr/share"));
assert!(args.iter().any(|a| a == "--datadir=/usr/share"));
assert!(args.iter().any(|a| a == "--mandir=/usr/share/man"));
assert!(args.iter().any(|a| a == "--infodir=/usr/share/info"));
}
#[test]
fn test_meson_setup_args_honor_explicit_prefix() {
let flags = BuildFlags {
@@ -288,6 +324,24 @@ mod tests {
assert!(args.iter().any(|a| a == "--prefix=/opt"));
}
#[test]
fn test_meson_setup_args_honor_explicit_install_dirs() {
let flags = BuildFlags {
configure: vec![
"--sbindir=/sbin".to_string(),
"--libdir=/custom/lib".to_string(),
"--datadir=/custom/share".to_string(),
],
..BuildFlags::default()
};
let args = meson_setup_args(&flags, None, &[]);
assert!(!args.iter().any(|a| a == "--sbindir=/usr/bin"));
assert!(!args.iter().any(|a| a == "--libdir=/usr/lib"));
assert!(!args.iter().any(|a| a == "--datadir=/usr/share"));
assert!(args.iter().any(|a| a == "--bindir=/usr/bin"));
}
#[test]
fn test_resolve_build_dir_uses_flag() {
let flags = BuildFlags {
+90
View File
@@ -20,6 +20,22 @@ use std::process::{Command, Stdio};
pub type EnvVars = Vec<(String, String)>;
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct InstallDirs {
pub bindir: String,
pub sbindir: String,
pub libdir: String,
pub libexecdir: String,
pub sysconfdir: String,
pub localstatedir: String,
pub sharedstatedir: String,
pub includedir: String,
pub datarootdir: String,
pub datadir: String,
pub mandir: String,
pub infodir: String,
}
pub fn set_env_var(env_vars: &mut EnvVars, key: &str, value: impl Into<String>) {
let value = value.into();
if let Some((_, existing)) = env_vars.iter_mut().find(|(k, _)| k == key) {
@@ -29,6 +45,46 @@ pub fn set_env_var(env_vars: &mut EnvVars, key: &str, value: impl Into<String>)
}
}
fn default_libdir_for_variant(lib32_variant: bool) -> &'static str {
if lib32_variant {
"/usr/lib32"
} else {
"/usr/lib"
}
}
fn configured_install_dir(value: &str, default: &str) -> String {
let trimmed = value.trim();
if trimmed.is_empty() {
default.to_string()
} else {
trimmed.to_string()
}
}
pub(crate) fn install_dirs(flags: &crate::package::BuildFlags) -> InstallDirs {
let libdir = configured_install_dir(
&flags.libdir,
default_libdir_for_variant(flags.lib32_variant),
);
let datarootdir = configured_install_dir(&flags.datarootdir, "/usr/share");
InstallDirs {
bindir: configured_install_dir(&flags.bindir, "/usr/bin"),
sbindir: configured_install_dir(&flags.sbindir, "/usr/bin"),
libdir: libdir.clone(),
libexecdir: configured_install_dir(&flags.libexecdir, &libdir),
sysconfdir: configured_install_dir(&flags.sysconfdir, "/etc"),
localstatedir: configured_install_dir(&flags.localstatedir, "/var"),
sharedstatedir: configured_install_dir(&flags.sharedstatedir, "/var/lib"),
includedir: configured_install_dir(&flags.includedir, "/usr/include"),
datarootdir: datarootdir.clone(),
datadir: configured_install_dir(&flags.datadir, &datarootdir),
mandir: configured_install_dir(&flags.mandir, "/usr/share/man"),
infodir: configured_install_dir(&flags.infodir, "/usr/share/info"),
}
}
fn compiler_flag_sets(
flags: &crate::package::BuildFlags,
) -> (Vec<String>, Vec<String>, Vec<String>, Vec<String>) {
@@ -551,4 +607,38 @@ mod tests {
"expected default CC to take precedence over passthrough CC"
);
}
#[test]
fn test_install_dirs_use_defaults_and_lib32_fallbacks() {
let default_dirs = install_dirs(&BuildFlags::default());
assert_eq!(default_dirs.bindir, "/usr/bin");
assert_eq!(default_dirs.sbindir, "/usr/bin");
assert_eq!(default_dirs.libdir, "/usr/lib");
assert_eq!(default_dirs.libexecdir, "/usr/lib");
assert_eq!(default_dirs.datarootdir, "/usr/share");
assert_eq!(default_dirs.datadir, "/usr/share");
let lib32_dirs = install_dirs(&BuildFlags {
lib32_variant: true,
..BuildFlags::default()
});
assert_eq!(lib32_dirs.libdir, "/usr/lib32");
assert_eq!(lib32_dirs.libexecdir, "/usr/lib32");
}
#[test]
fn test_install_dirs_respect_explicit_overrides_and_derived_defaults() {
let dirs = install_dirs(&BuildFlags {
bindir: "/opt/bin".into(),
libdir: "/opt/lib64".into(),
datarootdir: "/opt/share-root".into(),
..BuildFlags::default()
});
assert_eq!(dirs.bindir, "/opt/bin");
assert_eq!(dirs.libdir, "/opt/lib64");
assert_eq!(dirs.libexecdir, "/opt/lib64");
assert_eq!(dirs.datarootdir, "/opt/share-root");
assert_eq!(dirs.datadir, "/opt/share-root");
}
}
+88
View File
@@ -1274,6 +1274,72 @@ pub fn spec_to_minimal_toml(spec: &PackageSpec) -> anyhow::Result<String> {
Value::String(spec.build.flags.bindir.clone()),
);
}
if !spec.build.flags.sbindir.is_empty() {
flags_tbl.insert(
"sbindir".into(),
Value::String(spec.build.flags.sbindir.clone()),
);
}
if !spec.build.flags.libdir.is_empty() {
flags_tbl.insert(
"libdir".into(),
Value::String(spec.build.flags.libdir.clone()),
);
}
if !spec.build.flags.libexecdir.is_empty() {
flags_tbl.insert(
"libexecdir".into(),
Value::String(spec.build.flags.libexecdir.clone()),
);
}
if !spec.build.flags.sysconfdir.is_empty() {
flags_tbl.insert(
"sysconfdir".into(),
Value::String(spec.build.flags.sysconfdir.clone()),
);
}
if !spec.build.flags.localstatedir.is_empty() {
flags_tbl.insert(
"localstatedir".into(),
Value::String(spec.build.flags.localstatedir.clone()),
);
}
if !spec.build.flags.sharedstatedir.is_empty() {
flags_tbl.insert(
"sharedstatedir".into(),
Value::String(spec.build.flags.sharedstatedir.clone()),
);
}
if !spec.build.flags.includedir.is_empty() {
flags_tbl.insert(
"includedir".into(),
Value::String(spec.build.flags.includedir.clone()),
);
}
if !spec.build.flags.datarootdir.is_empty() {
flags_tbl.insert(
"datarootdir".into(),
Value::String(spec.build.flags.datarootdir.clone()),
);
}
if !spec.build.flags.datadir.is_empty() {
flags_tbl.insert(
"datadir".into(),
Value::String(spec.build.flags.datadir.clone()),
);
}
if !spec.build.flags.mandir.is_empty() {
flags_tbl.insert(
"mandir".into(),
Value::String(spec.build.flags.mandir.clone()),
);
}
if !spec.build.flags.infodir.is_empty() {
flags_tbl.insert(
"infodir".into(),
Value::String(spec.build.flags.infodir.clone()),
);
}
if !spec.build.flags.binary_type.is_empty() {
flags_tbl.insert(
"binary_type".into(),
@@ -1497,6 +1563,17 @@ mod tests {
ltoflags: vec!["-flto=auto".into()],
target: "x86_64-unknown-linux-gnu".into(),
keep: vec!["etc/locale.gen".into()],
sbindir: "/usr/sbin".into(),
libdir: "/usr/lib64".into(),
libexecdir: "/usr/libexec".into(),
sysconfdir: "/etc/custom".into(),
localstatedir: "/var/custom".into(),
sharedstatedir: "/var/lib/custom".into(),
includedir: "/usr/include/custom".into(),
datarootdir: "/usr/share/root".into(),
datadir: "/usr/share/custom".into(),
mandir: "/usr/share/custom/man".into(),
infodir: "/usr/share/custom/info".into(),
use_lto: false,
no_flags: true,
no_strip: true,
@@ -1560,6 +1637,17 @@ mod tests {
assert!(toml.contains("target = \"x86_64-unknown-linux-gnu\""));
assert!(toml.contains("keep = ["));
assert!(toml.contains("\"etc/locale.gen\""));
assert!(toml.contains("sbindir = \"/usr/sbin\""));
assert!(toml.contains("libdir = \"/usr/lib64\""));
assert!(toml.contains("libexecdir = \"/usr/libexec\""));
assert!(toml.contains("sysconfdir = \"/etc/custom\""));
assert!(toml.contains("localstatedir = \"/var/custom\""));
assert!(toml.contains("sharedstatedir = \"/var/lib/custom\""));
assert!(toml.contains("includedir = \"/usr/include/custom\""));
assert!(toml.contains("datarootdir = \"/usr/share/root\""));
assert!(toml.contains("datadir = \"/usr/share/custom\""));
assert!(toml.contains("mandir = \"/usr/share/custom/man\""));
assert!(toml.contains("infodir = \"/usr/share/custom/info\""));
assert!(toml.contains("use_lto = false"));
assert!(toml.contains("no_flags = true"));
assert!(toml.contains("no_strip = true"));
+245
View File
@@ -342,6 +342,66 @@ impl PackageSpec {
self.build.flags.prefix = s.to_string();
}
}
"bindir" => {
if let Some(s) = v.as_str() {
self.build.flags.bindir = s.to_string();
}
}
"sbindir" => {
if let Some(s) = v.as_str() {
self.build.flags.sbindir = s.to_string();
}
}
"libdir" => {
if let Some(s) = v.as_str() {
self.build.flags.libdir = s.to_string();
}
}
"libexecdir" => {
if let Some(s) = v.as_str() {
self.build.flags.libexecdir = s.to_string();
}
}
"sysconfdir" => {
if let Some(s) = v.as_str() {
self.build.flags.sysconfdir = s.to_string();
}
}
"localstatedir" => {
if let Some(s) = v.as_str() {
self.build.flags.localstatedir = s.to_string();
}
}
"sharedstatedir" => {
if let Some(s) = v.as_str() {
self.build.flags.sharedstatedir = s.to_string();
}
}
"includedir" => {
if let Some(s) = v.as_str() {
self.build.flags.includedir = s.to_string();
}
}
"datarootdir" => {
if let Some(s) = v.as_str() {
self.build.flags.datarootdir = s.to_string();
}
}
"datadir" => {
if let Some(s) = v.as_str() {
self.build.flags.datadir = s.to_string();
}
}
"mandir" => {
if let Some(s) = v.as_str() {
self.build.flags.mandir = s.to_string();
}
}
"infodir" => {
if let Some(s) = v.as_str() {
self.build.flags.infodir = s.to_string();
}
}
"chost" => {
if let Some(s) = v.as_str() {
self.build.flags.chost = s.to_string();
@@ -886,6 +946,66 @@ impl PackageSpec {
self.build.flags.prefix = s.to_string();
}
}
"bindir" => {
if let Some(s) = values.last().and_then(|v| v.as_str()) {
self.build.flags.bindir = s.to_string();
}
}
"sbindir" => {
if let Some(s) = values.last().and_then(|v| v.as_str()) {
self.build.flags.sbindir = s.to_string();
}
}
"libdir" => {
if let Some(s) = values.last().and_then(|v| v.as_str()) {
self.build.flags.libdir = s.to_string();
}
}
"libexecdir" => {
if let Some(s) = values.last().and_then(|v| v.as_str()) {
self.build.flags.libexecdir = s.to_string();
}
}
"sysconfdir" => {
if let Some(s) = values.last().and_then(|v| v.as_str()) {
self.build.flags.sysconfdir = s.to_string();
}
}
"localstatedir" => {
if let Some(s) = values.last().and_then(|v| v.as_str()) {
self.build.flags.localstatedir = s.to_string();
}
}
"sharedstatedir" => {
if let Some(s) = values.last().and_then(|v| v.as_str()) {
self.build.flags.sharedstatedir = s.to_string();
}
}
"includedir" => {
if let Some(s) = values.last().and_then(|v| v.as_str()) {
self.build.flags.includedir = s.to_string();
}
}
"datarootdir" => {
if let Some(s) = values.last().and_then(|v| v.as_str()) {
self.build.flags.datarootdir = s.to_string();
}
}
"datadir" => {
if let Some(s) = values.last().and_then(|v| v.as_str()) {
self.build.flags.datadir = s.to_string();
}
}
"mandir" => {
if let Some(s) = values.last().and_then(|v| v.as_str()) {
self.build.flags.mandir = s.to_string();
}
}
"infodir" => {
if let Some(s) = values.last().and_then(|v| v.as_str()) {
self.build.flags.infodir = s.to_string();
}
}
"chost" => {
if let Some(s) = values.last().and_then(|v| v.as_str()) {
self.build.flags.chost = s.to_string();
@@ -1773,6 +1893,11 @@ cc = "my-cc"
cflags = ["-O2"]
cxxflags = ["-O2", "-pipe"]
passthrough_env = ["RUSTFLAGS"]
bindir = "/opt/bin"
sbindir = "/opt/sbin"
libdir = "/opt/lib64"
sysconfdir = "/opt/etc"
datarootdir = "/opt/share-root"
makeflags = "-j8"
make_vars = ["V=1"]
make_dirs = ["lib"]
@@ -1867,6 +1992,14 @@ post_configure = ["echo configured"]
"build.flags.configure_file".to_string(),
vec![toml::Value::String("build-aux/configure".to_string())],
);
config.appends.insert(
"build.flags.libexecdir".to_string(),
vec![toml::Value::String("/opt/libexec".to_string())],
);
config.appends.insert(
"build.flags.datadir".to_string(),
vec![toml::Value::String("/opt/share-data".to_string())],
);
config.appends.insert(
"build.flags.config-setting".to_string(),
vec![toml::Value::String(
@@ -1933,6 +2066,13 @@ post_configure = ["echo configured"]
.passthrough_env
.contains(&"CARGO_HOME".to_string())
);
assert_eq!(spec.build.flags.bindir, "/opt/bin");
assert_eq!(spec.build.flags.sbindir, "/opt/sbin");
assert_eq!(spec.build.flags.libdir, "/opt/lib64");
assert_eq!(spec.build.flags.libexecdir, "/opt/libexec");
assert_eq!(spec.build.flags.sysconfdir, "/opt/etc");
assert_eq!(spec.build.flags.datarootdir, "/opt/share-root");
assert_eq!(spec.build.flags.datadir, "/opt/share-data");
assert_eq!(spec.build.flags.makeflags, "-j8 --output-sync=target");
assert!(spec.build.flags.make_vars.contains(&"V=1".to_string()));
assert!(spec.build.flags.make_dirs.contains(&"lib".to_string()));
@@ -2276,6 +2416,61 @@ configure_file = "build-aux/configure"
assert_eq!(spec.build.flags.configure_file, "build-aux/configure");
}
#[test]
fn parse_install_dirs_from_spec() {
let tmp = tempfile::tempdir().unwrap();
let path = tmp.path().join("pkg.toml");
std::fs::write(
&path,
r#"
[package]
name = "foo"
version = "1.0"
description = "d"
homepage = "h"
license = "MIT"
[source]
url = "https://example.com/foo.tar.gz"
sha256 = "skip"
extract_dir = "foo"
[build]
type = "cmake"
[build.flags]
bindir = "/custom/bin"
sbindir = "/custom/sbin"
libdir = "/custom/lib64"
libexecdir = "/custom/libexec"
sysconfdir = "/custom/etc"
localstatedir = "/custom/var"
sharedstatedir = "/custom/var/lib"
includedir = "/custom/include"
datarootdir = "/custom/share-root"
datadir = "/custom/share"
mandir = "/custom/share/man"
infodir = "/custom/share/info"
"#,
)
.unwrap();
let spec = PackageSpec::from_file(&path).unwrap();
assert_eq!(spec.build.flags.bindir, "/custom/bin");
assert_eq!(spec.build.flags.sbindir, "/custom/sbin");
assert_eq!(spec.build.flags.libdir, "/custom/lib64");
assert_eq!(spec.build.flags.libexecdir, "/custom/libexec");
assert_eq!(spec.build.flags.sysconfdir, "/custom/etc");
assert_eq!(spec.build.flags.localstatedir, "/custom/var");
assert_eq!(spec.build.flags.sharedstatedir, "/custom/var/lib");
assert_eq!(spec.build.flags.includedir, "/custom/include");
assert_eq!(spec.build.flags.datarootdir, "/custom/share-root");
assert_eq!(spec.build.flags.datadir, "/custom/share");
assert_eq!(spec.build.flags.mandir, "/custom/share/man");
assert_eq!(spec.build.flags.infodir, "/custom/share/info");
}
#[test]
fn parse_lib32_build_flags_from_spec() {
let tmp = tempfile::tempdir().unwrap();
@@ -3262,6 +3457,45 @@ pub struct BuildFlags {
/// Binary installation directory relative to DESTDIR (default: /usr/bin)
#[serde(default = "default_bindir")]
pub bindir: String,
/// System binary installation directory for supported builders (default: /usr/bin).
#[serde(default)]
pub sbindir: String,
/// Library installation directory for supported builders.
///
/// Defaults to `/usr/lib`, or `/usr/lib32` for the lib32 build variant.
#[serde(default)]
pub libdir: String,
/// Library helper executable installation directory for supported builders.
///
/// Defaults to the effective `libdir`.
#[serde(default)]
pub libexecdir: String,
/// System configuration directory for supported builders (default: /etc).
#[serde(default)]
pub sysconfdir: String,
/// Variable state directory for supported builders (default: /var).
#[serde(default)]
pub localstatedir: String,
/// Shared variable state directory for supported builders (default: /var/lib).
#[serde(default)]
pub sharedstatedir: String,
/// Header installation directory for supported builders (default: /usr/include).
#[serde(default)]
pub includedir: String,
/// Data root installation directory for supported builders (default: /usr/share).
#[serde(default)]
pub datarootdir: String,
/// Architecture-independent data installation directory for supported builders.
///
/// Defaults to the effective `datarootdir`.
#[serde(default)]
pub datadir: String,
/// Manual page installation directory for supported builders (default: /usr/share/man).
#[serde(default)]
pub mandir: String,
/// Info page installation directory for supported builders (default: /usr/share/info).
#[serde(default)]
pub infodir: String,
/// Subdirectory within extracted source to use as the actual source root.
/// Useful for monorepos like llvm-project where you want to build just one component.
@@ -3336,6 +3570,17 @@ impl Default for BuildFlags {
rustflags: Vec::new(),
cargs: Vec::new(),
bindir: default_bindir(),
sbindir: String::new(),
libdir: String::new(),
libexecdir: String::new(),
sysconfdir: String::new(),
localstatedir: String::new(),
sharedstatedir: String::new(),
includedir: String::new(),
datarootdir: String::new(),
datadir: String::new(),
mandir: String::new(),
infodir: String::new(),
source_subdir: String::new(),
build_dir: None,
binary_type: String::new(),