Add lib32 companion build pipeline
This commit is contained in:
@@ -40,7 +40,10 @@ pub fn build(
|
|||||||
}
|
}
|
||||||
|
|
||||||
use crate::builder::state::{BuildStep, StateTracker};
|
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
|
// Run configure
|
||||||
let build_dir = if let Some(dir) = &flags.build_dir {
|
let build_dir = if let Some(dir) = &flags.build_dir {
|
||||||
@@ -78,7 +81,14 @@ pub fn build(
|
|||||||
Some(flags.chost.clone())
|
Some(flags.chost.clone())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
}
|
||||||
|
.map(|host| {
|
||||||
|
if flags.lib32_variant {
|
||||||
|
lib32_host_triple(&host)
|
||||||
|
} else {
|
||||||
|
host
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
let requested_build = if cross.is_some() {
|
let requested_build = if cross.is_some() {
|
||||||
CrossConfig::build_triple().ok()
|
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 {
|
for arg in &flags.configure {
|
||||||
let expanded = expand_configure_arg(spec, arg, &env_vars);
|
let expanded = expand_configure_arg(spec, arg, &env_vars);
|
||||||
configure_cmd.arg(expanded);
|
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())
|
.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>> {
|
fn find_autotools_test_target(build_dir: &Path) -> Result<Option<&'static str>> {
|
||||||
for target in ["check", "test"] {
|
for target in ["check", "test"] {
|
||||||
if makefile_has_target(build_dir, target)? {
|
if makefile_has_target(build_dir, target)? {
|
||||||
|
|||||||
@@ -46,7 +46,10 @@ pub fn build(
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::builder::state::{BuildStep, StateTracker};
|
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
|
// Run cmake configure
|
||||||
if !state.is_done(BuildStep::Configured) {
|
if !state.is_done(BuildStep::Configured) {
|
||||||
|
|||||||
@@ -59,7 +59,10 @@ pub fn build(
|
|||||||
}
|
}
|
||||||
|
|
||||||
use crate::builder::state::{BuildStep, StateTracker};
|
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) {
|
if !state.is_done(BuildStep::Configured) {
|
||||||
hooks::run_post_configure_commands(spec, src_dir, destdir)?;
|
hooks::run_post_configure_commands(spec, src_dir, destdir)?;
|
||||||
|
|||||||
@@ -12,7 +12,10 @@ pub fn build(
|
|||||||
cross: Option<&CrossConfig>,
|
cross: Option<&CrossConfig>,
|
||||||
export_compiler_flags: bool,
|
export_compiler_flags: bool,
|
||||||
) -> Result<()> {
|
) -> 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 flags = &spec.build.flags;
|
||||||
|
|
||||||
let mut env_vars = crate::builder::standard_build_env(spec, cross, true, export_compiler_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};
|
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
|
// Run meson setup
|
||||||
if !state.is_done(BuildStep::Configured) {
|
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, "PYTHONDONTWRITEBYTECODE", "1");
|
||||||
crate::builder::set_env_var(&mut env_vars, "SETUPTOOLS_USE_DISTUTILS", "local");
|
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) {
|
if !state.is_done(BuildStep::Configured) {
|
||||||
hooks::run_post_configure_commands(spec, &actual_src, destdir)?;
|
hooks::run_post_configure_commands(spec, &actual_src, destdir)?;
|
||||||
state.mark_done(BuildStep::Configured)?;
|
state.mark_done(BuildStep::Configured)?;
|
||||||
|
|||||||
+28
-1
@@ -27,7 +27,15 @@ pub struct StateTracker {
|
|||||||
|
|
||||||
impl StateTracker {
|
impl StateTracker {
|
||||||
pub fn new(source_dir: &Path) -> Result<Self> {
|
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 state = if state_file.exists() {
|
||||||
let content = fs::read_to_string(&state_file)?;
|
let content = fs::read_to_string(&state_file)?;
|
||||||
toml::from_str(&content).unwrap_or_default()
|
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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|||||||
+3
-2
@@ -86,10 +86,11 @@ impl CrossConfig {
|
|||||||
|
|
||||||
/// Get the build machine triple (native compiler)
|
/// Get the build machine triple (native compiler)
|
||||||
pub fn build_triple() -> Result<String> {
|
pub fn build_triple() -> Result<String> {
|
||||||
let output = Command::new("gcc")
|
let output = Command::new("cc")
|
||||||
.arg("-dumpmachine")
|
.arg("-dumpmachine")
|
||||||
.output()
|
.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")?;
|
.context("Failed to determine build machine triple")?;
|
||||||
|
|
||||||
Ok(String::from_utf8_lossy(&output.stdout).trim().to_string())
|
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(
|
fn install_staged_to_rootfs(
|
||||||
pkg_spec: &package::PackageSpec,
|
pkg_spec: &package::PackageSpec,
|
||||||
destdir: &Path,
|
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 {
|
let destdir = if let Some(dir) = &staging_dir {
|
||||||
dir.path().to_path_buf()
|
dir.path().to_path_buf()
|
||||||
} else {
|
} else {
|
||||||
// 1-2. Fetch + extract sources (supports archives and git URL#rev)
|
// 1-2. Fetch + extract sources (supports archives and git URL#rev)
|
||||||
let src_dir = source::prepare(&pkg_spec, &config.cache_dir, &config.build_dir)?;
|
let src_dir = source::prepare(&pkg_spec, &config.cache_dir, &config.build_dir)?;
|
||||||
|
built_src_dir = Some(src_dir.clone());
|
||||||
|
|
||||||
// 3. Build
|
// 3. Build
|
||||||
let destdir = config
|
let destdir = config
|
||||||
@@ -1178,12 +1353,6 @@ fn main() -> Result<()> {
|
|||||||
.join("destdir")
|
.join("destdir")
|
||||||
.join(&pkg_spec.package.name);
|
.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(
|
builder::build(
|
||||||
&pkg_spec,
|
&pkg_spec,
|
||||||
&src_dir,
|
&src_dir,
|
||||||
@@ -1220,6 +1389,22 @@ fn main() -> Result<()> {
|
|||||||
// TODO(snapper): create post-install snapshot after install commit succeeds.
|
// 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 {
|
if cli.clean {
|
||||||
clean_build_workspace(&config)?;
|
clean_build_workspace(&config)?;
|
||||||
}
|
}
|
||||||
@@ -1408,6 +1593,33 @@ fn main() -> Result<()> {
|
|||||||
created_files.push(pkg_file);
|
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 {
|
for f in &created_files {
|
||||||
ui::success(format!("Build complete. Package created: {}", f.display()));
|
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.
|
// 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 {
|
if cli.clean {
|
||||||
|
|||||||
+230
-1
@@ -240,6 +240,17 @@ impl PackageSpec {
|
|||||||
self.build.flags.cflags = vec![s.to_string()];
|
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" => {
|
"cxxflags" => {
|
||||||
if let Some(arr) = v.as_array() {
|
if let Some(arr) = v.as_array() {
|
||||||
self.build.flags.cxxflags = arr
|
self.build.flags.cxxflags = arr
|
||||||
@@ -251,6 +262,17 @@ impl PackageSpec {
|
|||||||
self.build.flags.cxxflags = vec![s.to_string()];
|
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" => {
|
"ldflags" => {
|
||||||
if let Some(arr) = v.as_array() {
|
if let Some(arr) = v.as_array() {
|
||||||
self.build.flags.ldflags = arr
|
self.build.flags.ldflags = arr
|
||||||
@@ -472,6 +494,22 @@ impl PackageSpec {
|
|||||||
self.build.flags.skip_tests = b;
|
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" => {
|
"configure_file" | "configure-file" => {
|
||||||
if let Some(s) = v.as_str() {
|
if let Some(s) = v.as_str() {
|
||||||
self.build.flags.configure_file = s.to_string();
|
self.build.flags.configure_file = s.to_string();
|
||||||
@@ -510,6 +548,17 @@ impl PackageSpec {
|
|||||||
self.build.flags.post_install = vec![s.to_string()];
|
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
|
// 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" => {
|
"cxxflags" => {
|
||||||
for v in values {
|
for v in values {
|
||||||
if let Some(arr) = v.as_array() {
|
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" => {
|
"ldflags" => {
|
||||||
for v in values {
|
for v in values {
|
||||||
if let Some(arr) = v.as_array() {
|
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" => {
|
"configure_file" | "configure-file" => {
|
||||||
if let Some(s) = values.last().and_then(|v| v.as_str()) {
|
if let Some(s) = values.last().and_then(|v| v.as_str()) {
|
||||||
self.build.flags.configure_file = s.to_string();
|
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" => {
|
"cargs" => {
|
||||||
for v in values {
|
for v in values {
|
||||||
if let Some(arr) = v.as_array() {
|
if let Some(arr) = v.as_array() {
|
||||||
@@ -863,10 +960,15 @@ impl PackageSpec {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
"skip_tests" | "skip-tests" => {
|
"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;
|
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");
|
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]
|
#[test]
|
||||||
fn parse_post_configure_from_spec() {
|
fn parse_post_configure_from_spec() {
|
||||||
let tmp = tempfile::tempdir().unwrap();
|
let tmp = tempfile::tempdir().unwrap();
|
||||||
@@ -2343,9 +2486,29 @@ pub enum BuildType {
|
|||||||
pub struct BuildFlags {
|
pub struct BuildFlags {
|
||||||
#[serde(default, deserialize_with = "deserialize_string_or_array")]
|
#[serde(default, deserialize_with = "deserialize_string_or_array")]
|
||||||
pub cflags: Vec<String>,
|
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`.
|
/// Extra flags exported to `CXXFLAGS`.
|
||||||
#[serde(default, deserialize_with = "deserialize_string_or_array")]
|
#[serde(default, deserialize_with = "deserialize_string_or_array")]
|
||||||
pub cxxflags: Vec<String>,
|
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")]
|
#[serde(default, deserialize_with = "deserialize_string_or_array")]
|
||||||
pub ldflags: Vec<String>,
|
pub ldflags: Vec<String>,
|
||||||
/// Keep existing files and install package-provided replacement as `<path>.depotnew`.
|
/// 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`).
|
/// Skip automatic build-system test execution (e.g. Autotools `make check`/`make test`).
|
||||||
#[serde(default, alias = "skip-tests")]
|
#[serde(default, alias = "skip-tests")]
|
||||||
pub skip_tests: bool,
|
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)]
|
#[serde(default)]
|
||||||
pub configure: Vec<String>,
|
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.
|
/// Autotools configure script path, relative to source root or absolute.
|
||||||
#[serde(default, alias = "configure-file")]
|
#[serde(default, alias = "configure-file")]
|
||||||
pub configure_file: String,
|
pub configure_file: String,
|
||||||
@@ -2398,6 +2572,14 @@ pub struct BuildFlags {
|
|||||||
/// Commands to run after install (after make install)
|
/// Commands to run after install (after make install)
|
||||||
#[serde(default, alias = "post-install")]
|
#[serde(default, alias = "post-install")]
|
||||||
pub post_install: Vec<String>,
|
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
|
/// Specific commands for 'makefile' build type
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
@@ -2544,20 +2726,27 @@ pub struct BuildFlags {
|
|||||||
/// Binary package type when using BuildType::Bin (e.g. "deb")
|
/// Binary package type when using BuildType::Bin (e.g. "deb")
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub binary_type: String,
|
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 {
|
impl Default for BuildFlags {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
BuildFlags {
|
BuildFlags {
|
||||||
cflags: Vec::new(),
|
cflags: Vec::new(),
|
||||||
|
cflags_lib32: Vec::new(),
|
||||||
cxxflags: Vec::new(),
|
cxxflags: Vec::new(),
|
||||||
|
cxxflags_lib32: Vec::new(),
|
||||||
ldflags: Vec::new(),
|
ldflags: Vec::new(),
|
||||||
keep: Vec::new(),
|
keep: Vec::new(),
|
||||||
no_flags: false,
|
no_flags: false,
|
||||||
no_strip: false,
|
no_strip: false,
|
||||||
no_compress_man: false,
|
no_compress_man: false,
|
||||||
skip_tests: false,
|
skip_tests: false,
|
||||||
|
build_32: false,
|
||||||
configure: Vec::new(),
|
configure: Vec::new(),
|
||||||
|
configure_lib32: Vec::new(),
|
||||||
configure_file: String::new(),
|
configure_file: String::new(),
|
||||||
cc: default_cc(),
|
cc: default_cc(),
|
||||||
cxx: default_cxx(),
|
cxx: default_cxx(),
|
||||||
@@ -2567,6 +2756,7 @@ impl Default for BuildFlags {
|
|||||||
post_configure: Vec::new(),
|
post_configure: Vec::new(),
|
||||||
post_compile: Vec::new(),
|
post_compile: Vec::new(),
|
||||||
post_install: Vec::new(),
|
post_install: Vec::new(),
|
||||||
|
post_install_lib32: Vec::new(),
|
||||||
makefile_commands: Vec::new(),
|
makefile_commands: Vec::new(),
|
||||||
makefile_install_commands: Vec::new(),
|
makefile_install_commands: Vec::new(),
|
||||||
prefix: default_prefix(),
|
prefix: default_prefix(),
|
||||||
@@ -2595,6 +2785,7 @@ impl Default for BuildFlags {
|
|||||||
source_subdir: String::new(),
|
source_subdir: String::new(),
|
||||||
build_dir: None,
|
build_dir: None,
|
||||||
binary_type: String::new(),
|
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 {
|
fn default_cc() -> String {
|
||||||
// Prefer clang if available (supports -print-resource-dir and other useful flags)
|
// Prefer clang if available (supports -print-resource-dir and other useful flags)
|
||||||
if std::process::Command::new("which")
|
if std::process::Command::new("which")
|
||||||
|
|||||||
Reference in New Issue
Block a user