Add lib32 companion build pipeline
This commit is contained in:
@@ -40,7 +40,10 @@ pub fn build(
|
||||
}
|
||||
|
||||
use crate::builder::state::{BuildStep, StateTracker};
|
||||
let mut state = StateTracker::new(&actual_src)?;
|
||||
let mut state = StateTracker::new_with_namespace(
|
||||
&actual_src,
|
||||
spec.build.flags.lib32_variant.then_some("lib32"),
|
||||
)?;
|
||||
|
||||
// Run configure
|
||||
let build_dir = if let Some(dir) = &flags.build_dir {
|
||||
@@ -78,7 +81,14 @@ pub fn build(
|
||||
Some(flags.chost.clone())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
}
|
||||
.map(|host| {
|
||||
if flags.lib32_variant {
|
||||
lib32_host_triple(&host)
|
||||
} else {
|
||||
host
|
||||
}
|
||||
});
|
||||
|
||||
let requested_build = if cross.is_some() {
|
||||
CrossConfig::build_triple().ok()
|
||||
@@ -104,6 +114,15 @@ pub fn build(
|
||||
}
|
||||
}
|
||||
|
||||
if flags.lib32_variant {
|
||||
if !has_configure_option_prefix(&flags.configure, "--libdir") {
|
||||
configure_cmd.arg("--libdir=/usr/lib32");
|
||||
}
|
||||
if !has_configure_option_prefix(&flags.configure, "--libexecdir") {
|
||||
configure_cmd.arg("--libexecdir=/usr/lib32");
|
||||
}
|
||||
}
|
||||
|
||||
for arg in &flags.configure {
|
||||
let expanded = expand_configure_arg(spec, arg, &env_vars);
|
||||
configure_cmd.arg(expanded);
|
||||
@@ -412,6 +431,18 @@ fn configure_supports_option(help_text: Option<&str>, option: &str, configure_fi
|
||||
.unwrap_or(configure_file.trim().is_empty())
|
||||
}
|
||||
|
||||
fn has_configure_option_prefix(args: &[String], option: &str) -> bool {
|
||||
let with_eq = format!("{option}=");
|
||||
args.iter().any(|arg| {
|
||||
let trimmed = arg.trim();
|
||||
trimmed == option || trimmed.starts_with(&with_eq)
|
||||
})
|
||||
}
|
||||
|
||||
fn lib32_host_triple(host: &str) -> String {
|
||||
host.replace("x86_64", "i686")
|
||||
}
|
||||
|
||||
fn find_autotools_test_target(build_dir: &Path) -> Result<Option<&'static str>> {
|
||||
for target in ["check", "test"] {
|
||||
if makefile_has_target(build_dir, target)? {
|
||||
|
||||
@@ -46,7 +46,10 @@ pub fn build(
|
||||
};
|
||||
|
||||
use crate::builder::state::{BuildStep, StateTracker};
|
||||
let mut state = StateTracker::new(&actual_src)?;
|
||||
let mut state = StateTracker::new_with_namespace(
|
||||
&actual_src,
|
||||
spec.build.flags.lib32_variant.then_some("lib32"),
|
||||
)?;
|
||||
|
||||
// Run cmake configure
|
||||
if !state.is_done(BuildStep::Configured) {
|
||||
|
||||
@@ -59,7 +59,10 @@ pub fn build(
|
||||
}
|
||||
|
||||
use crate::builder::state::{BuildStep, StateTracker};
|
||||
let mut state = StateTracker::new(src_dir)?;
|
||||
let mut state = StateTracker::new_with_namespace(
|
||||
src_dir,
|
||||
spec.build.flags.lib32_variant.then_some("lib32"),
|
||||
)?;
|
||||
|
||||
if !state.is_done(BuildStep::Configured) {
|
||||
hooks::run_post_configure_commands(spec, src_dir, destdir)?;
|
||||
|
||||
@@ -12,7 +12,10 @@ pub fn build(
|
||||
cross: Option<&CrossConfig>,
|
||||
export_compiler_flags: bool,
|
||||
) -> Result<()> {
|
||||
let mut state = StateTracker::new(src_dir)?;
|
||||
let mut state = StateTracker::new_with_namespace(
|
||||
src_dir,
|
||||
spec.build.flags.lib32_variant.then_some("lib32"),
|
||||
)?;
|
||||
let flags = &spec.build.flags;
|
||||
|
||||
let mut env_vars = crate::builder::standard_build_env(spec, cross, true, export_compiler_flags);
|
||||
|
||||
@@ -37,7 +37,10 @@ pub fn build(
|
||||
};
|
||||
|
||||
use crate::builder::state::{BuildStep, StateTracker};
|
||||
let mut state = StateTracker::new(&actual_src)?;
|
||||
let mut state = StateTracker::new_with_namespace(
|
||||
&actual_src,
|
||||
spec.build.flags.lib32_variant.then_some("lib32"),
|
||||
)?;
|
||||
|
||||
// Run meson setup
|
||||
if !state.is_done(BuildStep::Configured) {
|
||||
|
||||
@@ -43,7 +43,10 @@ pub fn build(
|
||||
crate::builder::set_env_var(&mut env_vars, "PYTHONDONTWRITEBYTECODE", "1");
|
||||
crate::builder::set_env_var(&mut env_vars, "SETUPTOOLS_USE_DISTUTILS", "local");
|
||||
|
||||
let mut state = StateTracker::new(&actual_src)?;
|
||||
let mut state = StateTracker::new_with_namespace(
|
||||
&actual_src,
|
||||
spec.build.flags.lib32_variant.then_some("lib32"),
|
||||
)?;
|
||||
if !state.is_done(BuildStep::Configured) {
|
||||
hooks::run_post_configure_commands(spec, &actual_src, destdir)?;
|
||||
state.mark_done(BuildStep::Configured)?;
|
||||
|
||||
+28
-1
@@ -27,7 +27,15 @@ pub struct StateTracker {
|
||||
|
||||
impl StateTracker {
|
||||
pub fn new(source_dir: &Path) -> Result<Self> {
|
||||
let state_file = source_dir.join(".depot_state");
|
||||
Self::new_with_namespace(source_dir, None)
|
||||
}
|
||||
|
||||
pub fn new_with_namespace(source_dir: &Path, namespace: Option<&str>) -> Result<Self> {
|
||||
let state_file = if let Some(ns) = namespace.and_then(normalize_state_namespace) {
|
||||
source_dir.join(format!(".depot_state_{}", ns))
|
||||
} else {
|
||||
source_dir.join(".depot_state")
|
||||
};
|
||||
let state = if state_file.exists() {
|
||||
let content = fs::read_to_string(&state_file)?;
|
||||
toml::from_str(&content).unwrap_or_default()
|
||||
@@ -54,6 +62,25 @@ impl StateTracker {
|
||||
}
|
||||
}
|
||||
|
||||
fn normalize_state_namespace(namespace: &str) -> Option<String> {
|
||||
let normalized: String = namespace
|
||||
.chars()
|
||||
.map(|ch| {
|
||||
if ch.is_ascii_alphanumeric() || ch == '-' || ch == '_' {
|
||||
ch
|
||||
} else {
|
||||
'_'
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
let trimmed = normalized.trim_matches('_');
|
||||
if trimmed.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(trimmed.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
+3
-2
@@ -86,10 +86,11 @@ impl CrossConfig {
|
||||
|
||||
/// Get the build machine triple (native compiler)
|
||||
pub fn build_triple() -> Result<String> {
|
||||
let output = Command::new("gcc")
|
||||
let output = Command::new("cc")
|
||||
.arg("-dumpmachine")
|
||||
.output()
|
||||
.or_else(|_| Command::new("cc").arg("-dumpmachine").output())
|
||||
.or_else(|_| Command::new("clang").arg("-dumpmachine").output())
|
||||
.or_else(|_| Command::new("gcc").arg("-dumpmachine").output())
|
||||
.context("Failed to determine build machine triple")?;
|
||||
|
||||
Ok(String::from_utf8_lossy(&output.stdout).trim().to_string())
|
||||
|
||||
+225
-6
@@ -69,6 +69,173 @@ fn output_destdir_for(base_destdir: &Path, primary_pkg: &str, output_pkg: &str)
|
||||
}
|
||||
}
|
||||
|
||||
fn lib32_package_name(name: &str) -> String {
|
||||
format!("lib32-{name}")
|
||||
}
|
||||
|
||||
fn lib32_arch_name(arch: &str) -> String {
|
||||
arch.replace("x86_64", "i686")
|
||||
}
|
||||
|
||||
fn make_lib32_build_spec(base: &package::PackageSpec) -> package::PackageSpec {
|
||||
let mut spec = base.clone();
|
||||
let flags = &mut spec.build.flags;
|
||||
flags.lib32_variant = true;
|
||||
|
||||
if !flags.cflags_lib32.is_empty() {
|
||||
flags.cflags.extend(flags.cflags_lib32.clone());
|
||||
}
|
||||
if !flags.cxxflags_lib32.is_empty() {
|
||||
flags.cxxflags.extend(flags.cxxflags_lib32.clone());
|
||||
}
|
||||
if !flags.configure_lib32.is_empty() {
|
||||
flags.configure = flags.configure_lib32.clone();
|
||||
}
|
||||
if !flags.post_install_lib32.is_empty() {
|
||||
flags.post_install = flags.post_install_lib32.clone();
|
||||
}
|
||||
|
||||
flags.cc = format!("{} -m32", flags.cc.trim());
|
||||
flags.cxx = format!("{} -m32", flags.cxx.trim());
|
||||
|
||||
spec
|
||||
}
|
||||
|
||||
fn make_lib32_package_spec(base: &package::PackageSpec) -> package::PackageSpec {
|
||||
let mut spec = base.clone();
|
||||
spec.package.name = lib32_package_name(&base.package.name);
|
||||
// The lib32 pass currently emits a single companion package from /usr/lib32.
|
||||
spec.packages.clear();
|
||||
spec
|
||||
}
|
||||
|
||||
fn copy_tree_preserving_links(src: &Path, dst: &Path) -> Result<()> {
|
||||
use walkdir::WalkDir;
|
||||
|
||||
fs::create_dir_all(dst)
|
||||
.with_context(|| format!("Failed to create destination dir: {}", dst.display()))?;
|
||||
|
||||
for entry in WalkDir::new(src) {
|
||||
let entry = entry?;
|
||||
let rel = entry
|
||||
.path()
|
||||
.strip_prefix(src)
|
||||
.with_context(|| format!("Failed to strip prefix: {}", src.display()))?;
|
||||
let target = dst.join(rel);
|
||||
|
||||
if entry.file_type().is_dir() {
|
||||
fs::create_dir_all(&target)
|
||||
.with_context(|| format!("Failed to create dir: {}", target.display()))?;
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some(parent) = target.parent() {
|
||||
fs::create_dir_all(parent)
|
||||
.with_context(|| format!("Failed to create dir: {}", parent.display()))?;
|
||||
}
|
||||
|
||||
if entry.file_type().is_symlink() {
|
||||
let link_target = fs::read_link(entry.path())
|
||||
.with_context(|| format!("Failed to read symlink: {}", entry.path().display()))?;
|
||||
#[cfg(unix)]
|
||||
{
|
||||
use std::os::unix::fs as unix_fs;
|
||||
unix_fs::symlink(&link_target, &target).with_context(|| {
|
||||
format!(
|
||||
"Failed to create symlink {} -> {}",
|
||||
target.display(),
|
||||
link_target.display()
|
||||
)
|
||||
})?;
|
||||
}
|
||||
#[cfg(not(unix))]
|
||||
{
|
||||
anyhow::bail!(
|
||||
"Symlink-preserving lib32 staging copy is only supported on unix hosts"
|
||||
);
|
||||
}
|
||||
} else {
|
||||
fs::copy(entry.path(), &target).with_context(|| {
|
||||
format!(
|
||||
"Failed to copy {} to {}",
|
||||
entry.path().display(),
|
||||
target.display()
|
||||
)
|
||||
})?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn build_lib32_companion_package(
|
||||
pkg_spec: &package::PackageSpec,
|
||||
src_dir: &Path,
|
||||
config: &config::Config,
|
||||
cross_config: Option<&cross::CrossConfig>,
|
||||
export_compiler_flags: bool,
|
||||
) -> Result<Option<(package::PackageSpec, PathBuf)>> {
|
||||
if !pkg_spec.build.flags.build_32 {
|
||||
return Ok(None);
|
||||
}
|
||||
if pkg_spec.is_metapackage() {
|
||||
crate::log_warn!(
|
||||
"Ignoring build.flags.build-32 for metapackage {}",
|
||||
pkg_spec.package.name
|
||||
);
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
crate::log_info!("Running separate lib32 build pass...");
|
||||
let lib32_build_spec = make_lib32_build_spec(pkg_spec);
|
||||
let lib32_install_destdir = config
|
||||
.build_dir
|
||||
.join("destdir")
|
||||
.join(".lib32-build")
|
||||
.join(&pkg_spec.package.name)
|
||||
.join("lib32-dest");
|
||||
|
||||
builder::build(
|
||||
&lib32_build_spec,
|
||||
src_dir,
|
||||
&lib32_install_destdir,
|
||||
cross_config,
|
||||
export_compiler_flags,
|
||||
)?;
|
||||
|
||||
let lib32_src = lib32_install_destdir.join("usr/lib32");
|
||||
if !lib32_src.exists() {
|
||||
anyhow::bail!(
|
||||
"lib32 build completed but did not install usr/lib32 into {}",
|
||||
lib32_install_destdir.display()
|
||||
);
|
||||
}
|
||||
|
||||
let lib32_pkg_spec = make_lib32_package_spec(pkg_spec);
|
||||
let lib32_destdir = config
|
||||
.build_dir
|
||||
.join("destdir")
|
||||
.join(&lib32_pkg_spec.package.name);
|
||||
if lib32_destdir.exists() {
|
||||
fs::remove_dir_all(&lib32_destdir).with_context(|| {
|
||||
format!("Failed to clean lib32 destdir: {}", lib32_destdir.display())
|
||||
})?;
|
||||
}
|
||||
fs::create_dir_all(&lib32_destdir).with_context(|| {
|
||||
format!(
|
||||
"Failed to create lib32 destdir: {}",
|
||||
lib32_destdir.display()
|
||||
)
|
||||
})?;
|
||||
|
||||
copy_tree_preserving_links(&lib32_src, &lib32_destdir.join("usr/lib32"))?;
|
||||
staging::add_licenses(src_dir, &lib32_destdir, &lib32_pkg_spec.package.name)?;
|
||||
install::scripts::stage_scripts_from_spec_dir(&lib32_pkg_spec, &lib32_destdir)?;
|
||||
staging::process(&lib32_destdir, &lib32_pkg_spec)?;
|
||||
|
||||
Ok(Some((lib32_pkg_spec, lib32_destdir)))
|
||||
}
|
||||
|
||||
fn install_staged_to_rootfs(
|
||||
pkg_spec: &package::PackageSpec,
|
||||
destdir: &Path,
|
||||
@@ -1166,11 +1333,19 @@ fn main() -> Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
let cross_config = cli
|
||||
.cross_prefix
|
||||
.as_ref()
|
||||
.map(|p| cross::CrossConfig::from_prefix(p))
|
||||
.transpose()?;
|
||||
let mut built_src_dir: Option<PathBuf> = None;
|
||||
|
||||
let destdir = if let Some(dir) = &staging_dir {
|
||||
dir.path().to_path_buf()
|
||||
} else {
|
||||
// 1-2. Fetch + extract sources (supports archives and git URL#rev)
|
||||
let src_dir = source::prepare(&pkg_spec, &config.cache_dir, &config.build_dir)?;
|
||||
built_src_dir = Some(src_dir.clone());
|
||||
|
||||
// 3. Build
|
||||
let destdir = config
|
||||
@@ -1178,12 +1353,6 @@ fn main() -> Result<()> {
|
||||
.join("destdir")
|
||||
.join(&pkg_spec.package.name);
|
||||
|
||||
// Build with optional cross-compilation
|
||||
let cross_config = cli
|
||||
.cross_prefix
|
||||
.as_ref()
|
||||
.map(|p| cross::CrossConfig::from_prefix(p))
|
||||
.transpose()?;
|
||||
builder::build(
|
||||
&pkg_spec,
|
||||
&src_dir,
|
||||
@@ -1220,6 +1389,22 @@ fn main() -> Result<()> {
|
||||
// TODO(snapper): create post-install snapshot after install commit succeeds.
|
||||
}
|
||||
|
||||
if let Some(src_dir) = built_src_dir.as_deref()
|
||||
&& let Some((lib32_spec, lib32_destdir)) = build_lib32_companion_package(
|
||||
&pkg_spec,
|
||||
src_dir,
|
||||
&config,
|
||||
cross_config.as_ref(),
|
||||
!cli.no_flags,
|
||||
)?
|
||||
{
|
||||
install_staged_to_rootfs(&lib32_spec, &lib32_destdir, &cli.rootfs, &config)?;
|
||||
ui::success(format!(
|
||||
"Successfully installed {} v{}",
|
||||
lib32_spec.package.name, lib32_spec.package.version
|
||||
));
|
||||
}
|
||||
|
||||
if cli.clean {
|
||||
clean_build_workspace(&config)?;
|
||||
}
|
||||
@@ -1408,6 +1593,33 @@ fn main() -> Result<()> {
|
||||
created_files.push(pkg_file);
|
||||
}
|
||||
|
||||
let mut lib32_install_bundle: Option<(package::PackageSpec, PathBuf)> = None;
|
||||
if let Some((lib32_spec, lib32_destdir)) = build_lib32_companion_package(
|
||||
&pkg_spec,
|
||||
&src_dir,
|
||||
&config,
|
||||
cross_config.as_ref(),
|
||||
!cli.no_flags,
|
||||
)? {
|
||||
let lib32_arch = lib32_arch_name(arch);
|
||||
let packager = package::Packager::new(
|
||||
lib32_spec.clone(),
|
||||
lib32_destdir.clone(),
|
||||
config.clone(),
|
||||
);
|
||||
let pkg_file = packager.create_package(Path::new("."), &lib32_arch)?;
|
||||
if let Some(sig_path) =
|
||||
signing::auto_sign_zst_file_detached(&cli.rootfs, &pkg_file)?
|
||||
{
|
||||
ui::success(format!(
|
||||
"Created detached signature: {}",
|
||||
sig_path.display()
|
||||
));
|
||||
}
|
||||
created_files.push(pkg_file);
|
||||
lib32_install_bundle = Some((lib32_spec, lib32_destdir));
|
||||
}
|
||||
|
||||
for f in &created_files {
|
||||
ui::success(format!("Build complete. Package created: {}", f.display()));
|
||||
}
|
||||
@@ -1432,6 +1644,13 @@ fn main() -> Result<()> {
|
||||
));
|
||||
// TODO(snapper): create post-install snapshot after --install commit succeeds.
|
||||
}
|
||||
if let Some((lib32_spec, lib32_destdir)) = &lib32_install_bundle {
|
||||
install_staged_to_rootfs(lib32_spec, lib32_destdir, &cli.rootfs, &config)?;
|
||||
ui::success(format!(
|
||||
"Successfully installed {} v{}",
|
||||
lib32_spec.package.name, lib32_spec.package.version
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
if cli.clean {
|
||||
|
||||
+230
-1
@@ -240,6 +240,17 @@ impl PackageSpec {
|
||||
self.build.flags.cflags = vec![s.to_string()];
|
||||
}
|
||||
}
|
||||
"cflags-lib32" | "cflags_lib32" => {
|
||||
if let Some(arr) = v.as_array() {
|
||||
self.build.flags.cflags_lib32 = arr
|
||||
.iter()
|
||||
.filter_map(|x| x.as_str())
|
||||
.map(String::from)
|
||||
.collect();
|
||||
} else if let Some(s) = v.as_str() {
|
||||
self.build.flags.cflags_lib32 = vec![s.to_string()];
|
||||
}
|
||||
}
|
||||
"cxxflags" => {
|
||||
if let Some(arr) = v.as_array() {
|
||||
self.build.flags.cxxflags = arr
|
||||
@@ -251,6 +262,17 @@ impl PackageSpec {
|
||||
self.build.flags.cxxflags = vec![s.to_string()];
|
||||
}
|
||||
}
|
||||
"cxxflags-lib32" | "cxxflags_lib32" => {
|
||||
if let Some(arr) = v.as_array() {
|
||||
self.build.flags.cxxflags_lib32 = arr
|
||||
.iter()
|
||||
.filter_map(|x| x.as_str())
|
||||
.map(String::from)
|
||||
.collect();
|
||||
} else if let Some(s) = v.as_str() {
|
||||
self.build.flags.cxxflags_lib32 = vec![s.to_string()];
|
||||
}
|
||||
}
|
||||
"ldflags" => {
|
||||
if let Some(arr) = v.as_array() {
|
||||
self.build.flags.ldflags = arr
|
||||
@@ -472,6 +494,22 @@ impl PackageSpec {
|
||||
self.build.flags.skip_tests = b;
|
||||
}
|
||||
}
|
||||
"build_32" | "build-32" => {
|
||||
if let Some(b) = toml_value_as_boolish(v) {
|
||||
self.build.flags.build_32 = b;
|
||||
}
|
||||
}
|
||||
"configure_lib32" | "configure-lib32" => {
|
||||
if let Some(arr) = v.as_array() {
|
||||
self.build.flags.configure_lib32 = arr
|
||||
.iter()
|
||||
.filter_map(|x| x.as_str())
|
||||
.map(String::from)
|
||||
.collect();
|
||||
} else if let Some(s) = v.as_str() {
|
||||
self.build.flags.configure_lib32 = vec![s.to_string()];
|
||||
}
|
||||
}
|
||||
"configure_file" | "configure-file" => {
|
||||
if let Some(s) = v.as_str() {
|
||||
self.build.flags.configure_file = s.to_string();
|
||||
@@ -510,6 +548,17 @@ impl PackageSpec {
|
||||
self.build.flags.post_install = vec![s.to_string()];
|
||||
}
|
||||
}
|
||||
"post_install_lib32" | "post_install-lib32" | "post-install-lib32" => {
|
||||
if let Some(arr) = v.as_array() {
|
||||
self.build.flags.post_install_lib32 = arr
|
||||
.iter()
|
||||
.filter_map(|x| x.as_str())
|
||||
.map(String::from)
|
||||
.collect();
|
||||
} else if let Some(s) = v.as_str() {
|
||||
self.build.flags.post_install_lib32 = vec![s.to_string()];
|
||||
}
|
||||
}
|
||||
// Add more fields as needed
|
||||
_ => {}
|
||||
}
|
||||
@@ -530,6 +579,18 @@ impl PackageSpec {
|
||||
}
|
||||
}
|
||||
}
|
||||
"cflags-lib32" | "cflags_lib32" => {
|
||||
for v in values {
|
||||
if let Some(arr) = v.as_array() {
|
||||
self.build
|
||||
.flags
|
||||
.cflags_lib32
|
||||
.extend(arr.iter().filter_map(|x| x.as_str()).map(String::from));
|
||||
} else if let Some(s) = v.as_str() {
|
||||
self.build.flags.cflags_lib32.push(s.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
"cxxflags" => {
|
||||
for v in values {
|
||||
if let Some(arr) = v.as_array() {
|
||||
@@ -542,6 +603,18 @@ impl PackageSpec {
|
||||
}
|
||||
}
|
||||
}
|
||||
"cxxflags-lib32" | "cxxflags_lib32" => {
|
||||
for v in values {
|
||||
if let Some(arr) = v.as_array() {
|
||||
self.build
|
||||
.flags
|
||||
.cxxflags_lib32
|
||||
.extend(arr.iter().filter_map(|x| x.as_str()).map(String::from));
|
||||
} else if let Some(s) = v.as_str() {
|
||||
self.build.flags.cxxflags_lib32.push(s.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
"ldflags" => {
|
||||
for v in values {
|
||||
if let Some(arr) = v.as_array() {
|
||||
@@ -578,6 +651,18 @@ impl PackageSpec {
|
||||
}
|
||||
}
|
||||
}
|
||||
"configure_lib32" | "configure-lib32" => {
|
||||
for v in values {
|
||||
if let Some(arr) = v.as_array() {
|
||||
self.build
|
||||
.flags
|
||||
.configure_lib32
|
||||
.extend(arr.iter().filter_map(|x| x.as_str()).map(String::from));
|
||||
} else if let Some(s) = v.as_str() {
|
||||
self.build.flags.configure_lib32.push(s.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
"configure_file" | "configure-file" => {
|
||||
if let Some(s) = values.last().and_then(|v| v.as_str()) {
|
||||
self.build.flags.configure_file = s.to_string();
|
||||
@@ -619,6 +704,18 @@ impl PackageSpec {
|
||||
}
|
||||
}
|
||||
}
|
||||
"post_install_lib32" | "post_install-lib32" | "post-install-lib32" => {
|
||||
for v in values {
|
||||
if let Some(arr) = v.as_array() {
|
||||
self.build
|
||||
.flags
|
||||
.post_install_lib32
|
||||
.extend(arr.iter().filter_map(|x| x.as_str()).map(String::from));
|
||||
} else if let Some(s) = v.as_str() {
|
||||
self.build.flags.post_install_lib32.push(s.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
"cargs" => {
|
||||
for v in values {
|
||||
if let Some(arr) = v.as_array() {
|
||||
@@ -863,10 +960,15 @@ impl PackageSpec {
|
||||
}
|
||||
}
|
||||
"skip_tests" | "skip-tests" => {
|
||||
if let Some(b) = values.last().and_then(|v| v.as_bool()) {
|
||||
if let Some(b) = values.last().and_then(toml_value_as_boolish) {
|
||||
self.build.flags.skip_tests = b;
|
||||
}
|
||||
}
|
||||
"build_32" | "build-32" => {
|
||||
if let Some(b) = values.last().and_then(toml_value_as_boolish) {
|
||||
self.build.flags.build_32 = b;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@@ -1753,6 +1855,47 @@ configure_file = "build-aux/configure"
|
||||
assert_eq!(spec.build.flags.configure_file, "build-aux/configure");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_lib32_build_flags_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 = "autotools"
|
||||
|
||||
[build.flags]
|
||||
"build-32" = "true"
|
||||
"CFLAGS-lib32" = ["-mstackrealign"]
|
||||
"CXXFLAGS-lib32" = ["-fno-rtti"]
|
||||
"configure-lib32" = ["--disable-static"]
|
||||
"post_install-lib32" = ["echo lib32"]
|
||||
"#,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let spec = PackageSpec::from_file(&path).unwrap();
|
||||
assert!(spec.build.flags.build_32);
|
||||
assert_eq!(spec.build.flags.cflags_lib32, vec!["-mstackrealign"]);
|
||||
assert_eq!(spec.build.flags.cxxflags_lib32, vec!["-fno-rtti"]);
|
||||
assert_eq!(spec.build.flags.configure_lib32, vec!["--disable-static"]);
|
||||
assert_eq!(spec.build.flags.post_install_lib32, vec!["echo lib32"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_post_configure_from_spec() {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
@@ -2343,9 +2486,29 @@ pub enum BuildType {
|
||||
pub struct BuildFlags {
|
||||
#[serde(default, deserialize_with = "deserialize_string_or_array")]
|
||||
pub cflags: Vec<String>,
|
||||
/// Extra flags exported to `CFLAGS` only for the lib32 build variant.
|
||||
#[serde(
|
||||
default,
|
||||
alias = "cflags-lib32",
|
||||
alias = "cflags_lib32",
|
||||
alias = "CFLAGS-lib32",
|
||||
alias = "CFLAGS_lib32",
|
||||
deserialize_with = "deserialize_string_or_array"
|
||||
)]
|
||||
pub cflags_lib32: Vec<String>,
|
||||
/// Extra flags exported to `CXXFLAGS`.
|
||||
#[serde(default, deserialize_with = "deserialize_string_or_array")]
|
||||
pub cxxflags: Vec<String>,
|
||||
/// Extra flags exported to `CXXFLAGS` only for the lib32 build variant.
|
||||
#[serde(
|
||||
default,
|
||||
alias = "cxxflags-lib32",
|
||||
alias = "cxxflags_lib32",
|
||||
alias = "CXXFLAGS-lib32",
|
||||
alias = "CXXFLAGS_lib32",
|
||||
deserialize_with = "deserialize_string_or_array"
|
||||
)]
|
||||
pub cxxflags_lib32: Vec<String>,
|
||||
#[serde(default, deserialize_with = "deserialize_string_or_array")]
|
||||
pub ldflags: Vec<String>,
|
||||
/// Keep existing files and install package-provided replacement as `<path>.depotnew`.
|
||||
@@ -2368,8 +2531,19 @@ pub struct BuildFlags {
|
||||
/// Skip automatic build-system test execution (e.g. Autotools `make check`/`make test`).
|
||||
#[serde(default, alias = "skip-tests")]
|
||||
pub skip_tests: bool,
|
||||
/// Run an additional lib32 build pass and emit a `lib32-*` package.
|
||||
#[serde(
|
||||
default,
|
||||
alias = "build-32",
|
||||
alias = "build_32",
|
||||
deserialize_with = "deserialize_boolish"
|
||||
)]
|
||||
pub build_32: bool,
|
||||
#[serde(default)]
|
||||
pub configure: Vec<String>,
|
||||
/// Configure arguments used only for the lib32 build variant (replaces `configure` when set).
|
||||
#[serde(default, alias = "configure-lib32", alias = "configure_lib32")]
|
||||
pub configure_lib32: Vec<String>,
|
||||
/// Autotools configure script path, relative to source root or absolute.
|
||||
#[serde(default, alias = "configure-file")]
|
||||
pub configure_file: String,
|
||||
@@ -2398,6 +2572,14 @@ pub struct BuildFlags {
|
||||
/// Commands to run after install (after make install)
|
||||
#[serde(default, alias = "post-install")]
|
||||
pub post_install: Vec<String>,
|
||||
/// Commands to run after the lib32 install step (replaces `post_install` when set).
|
||||
#[serde(
|
||||
default,
|
||||
alias = "post-install-lib32",
|
||||
alias = "post_install-lib32",
|
||||
alias = "post_install_lib32"
|
||||
)]
|
||||
pub post_install_lib32: Vec<String>,
|
||||
|
||||
/// Specific commands for 'makefile' build type
|
||||
#[serde(default)]
|
||||
@@ -2544,20 +2726,27 @@ pub struct BuildFlags {
|
||||
/// Binary package type when using BuildType::Bin (e.g. "deb")
|
||||
#[serde(default)]
|
||||
pub binary_type: String,
|
||||
/// Internal runtime marker used to adjust builder behavior for the lib32 variant.
|
||||
#[serde(skip)]
|
||||
pub lib32_variant: bool,
|
||||
}
|
||||
|
||||
impl Default for BuildFlags {
|
||||
fn default() -> Self {
|
||||
BuildFlags {
|
||||
cflags: Vec::new(),
|
||||
cflags_lib32: Vec::new(),
|
||||
cxxflags: Vec::new(),
|
||||
cxxflags_lib32: Vec::new(),
|
||||
ldflags: Vec::new(),
|
||||
keep: Vec::new(),
|
||||
no_flags: false,
|
||||
no_strip: false,
|
||||
no_compress_man: false,
|
||||
skip_tests: false,
|
||||
build_32: false,
|
||||
configure: Vec::new(),
|
||||
configure_lib32: Vec::new(),
|
||||
configure_file: String::new(),
|
||||
cc: default_cc(),
|
||||
cxx: default_cxx(),
|
||||
@@ -2567,6 +2756,7 @@ impl Default for BuildFlags {
|
||||
post_configure: Vec::new(),
|
||||
post_compile: Vec::new(),
|
||||
post_install: Vec::new(),
|
||||
post_install_lib32: Vec::new(),
|
||||
makefile_commands: Vec::new(),
|
||||
makefile_install_commands: Vec::new(),
|
||||
prefix: default_prefix(),
|
||||
@@ -2595,6 +2785,7 @@ impl Default for BuildFlags {
|
||||
source_subdir: String::new(),
|
||||
build_dir: None,
|
||||
binary_type: String::new(),
|
||||
lib32_variant: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2619,6 +2810,44 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_boolish<'de, D>(deserializer: D) -> std::result::Result<bool, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
#[derive(Deserialize)]
|
||||
#[serde(untagged)]
|
||||
enum Boolish {
|
||||
Bool(bool),
|
||||
String(String),
|
||||
}
|
||||
|
||||
match Option::<Boolish>::deserialize(deserializer)? {
|
||||
Some(Boolish::Bool(v)) => Ok(v),
|
||||
Some(Boolish::String(s)) => match s.trim().to_ascii_lowercase().as_str() {
|
||||
"true" | "1" | "yes" | "on" => Ok(true),
|
||||
"false" | "0" | "no" | "off" => Ok(false),
|
||||
other => Err(serde::de::Error::custom(format!(
|
||||
"expected boolean string for lib32 flag, got '{}'",
|
||||
other
|
||||
))),
|
||||
},
|
||||
None => Ok(false),
|
||||
}
|
||||
}
|
||||
|
||||
fn toml_value_as_boolish(value: &toml::Value) -> Option<bool> {
|
||||
if let Some(b) = value.as_bool() {
|
||||
return Some(b);
|
||||
}
|
||||
value
|
||||
.as_str()
|
||||
.and_then(|s| match s.trim().to_ascii_lowercase().as_str() {
|
||||
"true" | "1" | "yes" | "on" => Some(true),
|
||||
"false" | "0" | "no" | "off" => Some(false),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
||||
fn default_cc() -> String {
|
||||
// Prefer clang if available (supports -print-resource-dir and other useful flags)
|
||||
if std::process::Command::new("which")
|
||||
|
||||
Reference in New Issue
Block a user