feat: update depot version to 0.25.1 and enhance lib32 installation handling

This commit is contained in:
2026-03-15 22:55:17 -05:00
parent a7a8ac201e
commit 99ceacdb64
7 changed files with 302 additions and 102 deletions
Generated
+1 -1
View File
@@ -418,7 +418,7 @@ checksum = "807800ff3288b621186fe0a8f3392c4652068257302709c24efd918c3dffcdc2"
[[package]] [[package]]
name = "depot" name = "depot"
version = "0.25.0" version = "0.25.1"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"ar", "ar",
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "depot" name = "depot"
version = "0.25.0" version = "0.25.1"
edition = "2024" edition = "2024"
[lints.rust] [lints.rust]
+1 -1
View File
@@ -1,6 +1,6 @@
project( project(
'depot', 'depot',
version: '0.25.0', version: '0.25.1',
meson_version: '>=0.60.0', meson_version: '>=0.60.0',
default_options: ['buildtype=release'], default_options: ['buildtype=release'],
) )
+1 -63
View File
@@ -8,7 +8,6 @@ use anyhow::{Context, Result};
use std::fs; use std::fs;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::process::Command; use std::process::Command;
use walkdir::WalkDir;
pub fn build( pub fn build(
spec: &PackageSpec, spec: &PackageSpec,
@@ -373,11 +372,7 @@ pub fn build(
} }
if flags.lib32_variant { if flags.lib32_variant {
let staged_lib32 = install_destdir.join("usr/lib32"); crate::builder::stage_lib32_install_tree(&install_destdir, destdir)?;
if !staged_lib32.exists() {
anyhow::bail!("lib32 install did not populate {}", staged_lib32.display());
}
copy_tree_preserving_links(&staged_lib32, &destdir.join("usr/lib32"))?;
hooks::run_post_install_commands_in_dir(spec, &build_dir, destdir)?; hooks::run_post_install_commands_in_dir(spec, &build_dir, destdir)?;
} else { } else {
hooks::run_post_install_commands(spec, &actual_src, destdir)?; hooks::run_post_install_commands(spec, &actual_src, destdir)?;
@@ -510,63 +505,6 @@ fn install_destdir_path(build_dir: &Path, destdir: &Path, lib32_variant: bool) -
} }
} }
fn copy_tree_preserving_links(src: &Path, dst: &Path) -> Result<()> {
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 lib32_host_triple(host: &str) -> String { fn lib32_host_triple(host: &str) -> String {
host.replace("x86_64", "i686") host.replace("x86_64", "i686")
} }
+100 -14
View File
@@ -17,12 +17,37 @@ pub fn build(
export_compiler_flags: bool, export_compiler_flags: bool,
) -> Result<()> { ) -> Result<()> {
let flags = &spec.build.flags; let flags = &spec.build.flags;
let build_dir = if let Some(dir) = &flags.build_dir {
let bdir = src_dir.join(dir);
fs::create_dir_all(&bdir)?;
bdir
} else {
src_dir.to_path_buf()
};
let install_destdir =
crate::builder::install_destdir_path(&build_dir, destdir, flags.lib32_variant);
// Create destdir // Create destdir
fs::create_dir_all(destdir)?; fs::create_dir_all(destdir)?;
if flags.lib32_variant {
if install_destdir.exists() {
fs::remove_dir_all(&install_destdir).with_context(|| {
format!(
"Failed to clean temporary lib32 install dir: {}",
install_destdir.display()
)
})?;
}
fs::create_dir_all(&install_destdir).with_context(|| {
format!(
"Failed to create temporary lib32 install dir: {}",
install_destdir.display()
)
})?;
}
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);
let shell_helpers = crate::shell_helpers::ShellHelpers::new(destdir)?; let shell_helpers = crate::shell_helpers::ShellHelpers::new(&install_destdir)?;
shell_helpers.apply_to_env_vars(&mut env_vars); shell_helpers.apply_to_env_vars(&mut env_vars);
// For custom builds, look for a build.sh script in the source directory // For custom builds, look for a build.sh script in the source directory
@@ -81,25 +106,17 @@ pub fn build(
} }
); );
let build_dir = if let Some(dir) = &flags.build_dir {
let bdir = src_dir.join(dir);
fs::create_dir_all(&bdir)?;
bdir
} else {
src_dir.to_path_buf()
};
crate::builder::set_env_var( crate::builder::set_env_var(
&mut env_vars, &mut env_vars,
"DESTDIR", "DESTDIR",
destdir.to_string_lossy().into_owned(), install_destdir.to_string_lossy().into_owned(),
); );
crate::builder::set_env_var( crate::builder::set_env_var(
&mut env_vars, &mut env_vars,
"DEPOT_PRIMARY_DESTDIR", "DEPOT_PRIMARY_DESTDIR",
destdir.to_string_lossy().into_owned(), install_destdir.to_string_lossy().into_owned(),
); );
add_output_destdir_envs(spec, destdir, &mut env_vars); add_output_destdir_envs(spec, &install_destdir, &mut env_vars);
// Ensure build script path is absolute for when we are in a sub-build-dir // Ensure build script path is absolute for when we are in a sub-build-dir
let abs_build_script = if build_script.is_absolute() { let abs_build_script = if build_script.is_absolute() {
@@ -113,9 +130,9 @@ pub fn build(
crate::log_info!( crate::log_info!(
"Using custom build.sh function mode (per-output install functions enabled)" "Using custom build.sh function mode (per-output install functions enabled)"
); );
build_function_mode_command(spec, destdir, &abs_build_script)? build_function_mode_command(spec, &install_destdir, &abs_build_script)?
} else { } else {
let mut cmd = fakeroot::wrap_install_command("sh", destdir); let mut cmd = fakeroot::wrap_install_command("sh", &install_destdir);
let wrapper = crate::shell_helpers::wrap_shell_command(". \"$1\""); let wrapper = crate::shell_helpers::wrap_shell_command(". \"$1\"");
// Run custom scripts through `sh -c` so helper commands like `haul` // Run custom scripts through `sh -c` so helper commands like `haul`
// work even when the helper scripts live on a `noexec` mount. // work even when the helper scripts live on a `noexec` mount.
@@ -142,6 +159,9 @@ pub fn build(
if !status.success() { if !status.success() {
anyhow::bail!("Custom build script failed with status: {}", status); anyhow::bail!("Custom build script failed with status: {}", status);
} }
if flags.lib32_variant {
crate::builder::stage_lib32_install_tree(&install_destdir, destdir)?;
}
state.mark_done(BuildStep::PostInstallDone)?; state.mark_done(BuildStep::PostInstallDone)?;
} else { } else {
crate::log_info!("Skipping custom build script (already done)"); crate::log_info!("Skipping custom build script (already done)");
@@ -467,4 +487,70 @@ exit 0
assert!(err.to_string().contains("Custom build script failed")); assert!(err.to_string().contains("Custom build script failed"));
Ok(()) Ok(())
} }
#[test]
fn test_build_lib32_stages_usr_lib_and_keeps_non_library_paths() -> Result<()> {
let tmp_src = tempdir()?;
let tmp_dest = tempdir()?;
let tmp_tools = tempdir()?;
let build_sh = tmp_src.path().join("build.sh");
std::fs::write(
&build_sh,
r#"#!/bin/sh
mkdir -p "$DESTDIR/usr/lib" "$DESTDIR/usr/share/man/man1"
printf 'lib32' > "$DESTDIR/usr/lib/libfoo.so.1"
printf 'manpage' > "$DESTDIR/usr/share/man/man1/foo.1"
"#,
)?;
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
let mut perms = std::fs::metadata(&build_sh)?.permissions();
perms.set_mode(0o755);
std::fs::set_permissions(&build_sh, perms)?;
}
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
let fakeroot = tmp_tools.path().join("fakeroot");
std::fs::write(
&fakeroot,
r#"#!/bin/sh
if [ "$1" = "--" ]; then
shift
fi
exec "$@"
"#,
)?;
let mut perms = std::fs::metadata(&fakeroot)?.permissions();
perms.set_mode(0o755);
std::fs::set_permissions(&fakeroot, perms)?;
}
let mut env = crate::test_support::TestEnv::new();
let old_path = std::env::var("PATH").unwrap_or_default();
env.set_var(
"PATH",
format!("{}:{}", tmp_tools.path().display(), old_path),
);
let mut spec = mk_spec("custom-lib32", "1.0");
spec.build.flags.lib32_variant = true;
build(&spec, tmp_src.path(), tmp_dest.path(), None, true)?;
assert_eq!(
std::fs::read_to_string(tmp_dest.path().join("usr/lib32/libfoo.so.1"))?,
"lib32"
);
assert_eq!(
std::fs::read_to_string(tmp_dest.path().join("usr/share/man/man1/foo.1"))?,
"manpage"
);
assert!(!tmp_dest.path().join("usr/lib").exists());
Ok(())
}
} }
+73 -3
View File
@@ -2,6 +2,7 @@ use crate::builder::state::{BuildStep, StateTracker};
use crate::cross::CrossConfig; use crate::cross::CrossConfig;
use crate::package::PackageSpec; use crate::package::PackageSpec;
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use std::fs;
use std::path::Path; use std::path::Path;
use std::process::Command; use std::process::Command;
@@ -17,6 +18,8 @@ pub fn build(
spec.build.flags.lib32_variant.then_some("lib32"), spec.build.flags.lib32_variant.then_some("lib32"),
)?; )?;
let flags = &spec.build.flags; let flags = &spec.build.flags;
fs::create_dir_all(destdir)
.with_context(|| format!("Failed to create DESTDIR: {}", destdir.display()))?;
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);
@@ -72,19 +75,38 @@ pub fn build(
} }
); );
let install_destdir =
crate::builder::install_destdir_path(src_dir, destdir, flags.lib32_variant);
if flags.lib32_variant {
if install_destdir.exists() {
fs::remove_dir_all(&install_destdir).with_context(|| {
format!(
"Failed to clean temporary lib32 install dir: {}",
install_destdir.display()
)
})?;
}
fs::create_dir_all(&install_destdir).with_context(|| {
format!(
"Failed to create temporary lib32 install dir: {}",
install_destdir.display()
)
})?;
}
for cmd_str in &spec.build.flags.makefile_install_commands { for cmd_str in &spec.build.flags.makefile_install_commands {
let cmd_str = spec.expand_vars(cmd_str); let cmd_str = spec.expand_vars(cmd_str);
crate::log_info!(" Executing: {}", cmd_str); crate::log_info!(" Executing: {}", cmd_str);
// We need to run each command under fakeroot // We need to run each command under fakeroot
let mut cmd = crate::fakeroot::wrap_install_command("sh", destdir); let mut cmd = crate::fakeroot::wrap_install_command("sh", &install_destdir);
cmd.arg("-c").arg(&cmd_str); cmd.arg("-c").arg(&cmd_str);
cmd.current_dir(src_dir); cmd.current_dir(src_dir);
let mut install_env = env_vars.clone(); let mut install_env = env_vars.clone();
install_env.push(( install_env.push((
"DESTDIR".to_string(), "DESTDIR".to_string(),
destdir.to_string_lossy().into_owned(), install_destdir.to_string_lossy().into_owned(),
)); ));
crate::builder::prepare_tool_command(&mut cmd, &install_env); crate::builder::prepare_tool_command(&mut cmd, &install_env);
@@ -95,7 +117,12 @@ pub fn build(
} }
} }
crate::source::hooks::run_post_install_commands(spec, src_dir, destdir)?; if flags.lib32_variant {
crate::builder::stage_lib32_install_tree(&install_destdir, destdir)?;
crate::source::hooks::run_post_install_commands_in_dir(spec, src_dir, destdir)?;
} else {
crate::source::hooks::run_post_install_commands(spec, src_dir, destdir)?;
}
state.mark_done(BuildStep::PostInstallDone)?; state.mark_done(BuildStep::PostInstallDone)?;
} else { } else {
crate::log_info!("Skipping makefile install commands (already done)"); crate::log_info!("Skipping makefile install commands (already done)");
@@ -212,4 +239,47 @@ exec "$@"
Ok(()) Ok(())
} }
#[test]
fn test_makefile_lib32_install_relocates_usr_lib_and_keeps_other_paths() -> Result<()> {
let tmp_src = tempdir()?;
let tmp_dest = tempdir()?;
let tmp_tools = tempdir()?;
let src_path = tmp_src.path();
let dest_path = tmp_dest.path();
let tools_path = tmp_tools.path();
write_executable(
&tools_path.join("fakeroot"),
r#"#!/bin/sh
if [ "$1" = "--" ]; then
shift
fi
exec "$@"
"#,
)?;
let mut env = TestEnv::new();
let old_path = std::env::var("PATH").unwrap_or_default();
env.set_var("PATH", format!("{}:{}", tools_path.display(), old_path));
let mut spec = mk_spec("lib32-test-make", "1.0");
spec.build.flags.lib32_variant = true;
spec.build.flags.makefile_install_commands = vec![
"mkdir -p \"$DESTDIR/usr/lib\" \"$DESTDIR/usr/bin\"".into(),
"printf 'lib32' > \"$DESTDIR/usr/lib/libfoo.so.1\"".into(),
"printf 'bin' > \"$DESTDIR/usr/bin/foo\"".into(),
];
build(&spec, src_path, dest_path, None, true)?;
assert_eq!(
fs::read_to_string(dest_path.join("usr/lib32/libfoo.so.1"))?,
"lib32"
);
assert_eq!(fs::read_to_string(dest_path.join("usr/bin/foo"))?, "bin");
assert!(!dest_path.join("usr/lib").exists());
Ok(())
}
} }
+125 -19
View File
@@ -180,25 +180,9 @@ pub(crate) fn install_destdir_path(
} }
pub(crate) fn stage_lib32_install_tree(staging_destdir: &Path, destdir: &Path) -> Result<()> { pub(crate) fn stage_lib32_install_tree(staging_destdir: &Path, destdir: &Path) -> Result<()> {
let staged_lib32 = staging_destdir.join("usr/lib32"); let lib_rel = lib32_stage_source_rel(staging_destdir)?;
if staged_lib32.exists() { copy_install_tree_preserving_links(staging_destdir, destdir, Some(&lib_rel))?;
return copy_tree_preserving_links(&staged_lib32, &destdir.join("usr/lib32")); copy_tree_preserving_links(&staging_destdir.join(&lib_rel), &destdir.join("usr/lib32"))
}
let staged_lib = staging_destdir.join("usr/lib");
if staged_lib.exists() {
crate::log_warn!(
"lib32 install populated {} instead of usr/lib32; relocating staged libraries",
staged_lib.display()
);
return copy_tree_preserving_links(&staged_lib, &destdir.join("usr/lib32"));
}
anyhow::bail!(
"lib32 install did not populate {} or {}",
staged_lib32.display(),
staged_lib.display()
);
} }
fn copy_tree_preserving_links(src: &Path, dst: &Path) -> Result<()> { fn copy_tree_preserving_links(src: &Path, dst: &Path) -> Result<()> {
@@ -258,6 +242,105 @@ fn copy_tree_preserving_links(src: &Path, dst: &Path) -> Result<()> {
Ok(()) Ok(())
} }
fn copy_install_tree_preserving_links(
src: &Path,
dst: &Path,
relocated_lib_rel: Option<&Path>,
) -> Result<()> {
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()))?;
if should_skip_staged_install_entry(rel, relocated_lib_rel) {
continue;
}
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 should_skip_staged_install_entry(rel: &Path, relocated_lib_rel: Option<&Path>) -> bool {
if rel.as_os_str().is_empty() {
return false;
}
if rel.starts_with(Path::new(crate::shell_helpers::INTERNAL_DEPOT_DIR)) {
return true;
}
relocated_lib_rel.is_some_and(|lib_rel| rel.starts_with(lib_rel))
}
fn lib32_stage_source_rel(staging_destdir: &Path) -> Result<PathBuf> {
let staged_lib32 = PathBuf::from("usr/lib32");
if staging_destdir.join(&staged_lib32).exists() {
return Ok(staged_lib32);
}
let staged_lib = PathBuf::from("usr/lib");
if staging_destdir.join(&staged_lib).exists() {
crate::log_warn!(
"lib32 install populated {} instead of usr/lib32; relocating staged libraries",
staging_destdir.join(&staged_lib).display()
);
return Ok(staged_lib);
}
anyhow::bail!(
"lib32 install did not populate {} or {}",
staging_destdir.join("usr/lib32").display(),
staging_destdir.join("usr/lib").display()
);
}
fn compiler_flag_sets( fn compiler_flag_sets(
flags: &crate::package::BuildFlags, flags: &crate::package::BuildFlags,
) -> (Vec<String>, Vec<String>, Vec<String>, Vec<String>) { ) -> (Vec<String>, Vec<String>, Vec<String>, Vec<String>) {
@@ -978,7 +1061,16 @@ mod tests {
let staging = temp.path().join("staging"); let staging = temp.path().join("staging");
let dest = temp.path().join("dest"); let dest = temp.path().join("dest");
fs::create_dir_all(staging.join("usr/lib32"))?; fs::create_dir_all(staging.join("usr/lib32"))?;
fs::create_dir_all(staging.join("usr/bin"))?;
fs::write(staging.join("usr/lib32/libfoo.so.1"), "lib32")?; fs::write(staging.join("usr/lib32/libfoo.so.1"), "lib32")?;
fs::write(staging.join("usr/bin/foo"), "bin")?;
fs::create_dir_all(staging.join(crate::shell_helpers::INTERNAL_DEPOT_DIR))?;
fs::write(
staging
.join(crate::shell_helpers::INTERNAL_DEPOT_DIR)
.join("internal.txt"),
"skip",
)?;
stage_lib32_install_tree(&staging, &dest)?; stage_lib32_install_tree(&staging, &dest)?;
@@ -986,6 +1078,13 @@ mod tests {
fs::read_to_string(dest.join("usr/lib32/libfoo.so.1"))?, fs::read_to_string(dest.join("usr/lib32/libfoo.so.1"))?,
"lib32" "lib32"
); );
assert_eq!(fs::read_to_string(dest.join("usr/bin/foo"))?, "bin");
assert!(
!dest
.join(crate::shell_helpers::INTERNAL_DEPOT_DIR)
.join("internal.txt")
.exists()
);
Ok(()) Ok(())
} }
@@ -998,7 +1097,9 @@ mod tests {
let staging = temp.path().join("staging"); let staging = temp.path().join("staging");
let dest = temp.path().join("dest"); let dest = temp.path().join("dest");
fs::create_dir_all(staging.join("usr/lib"))?; fs::create_dir_all(staging.join("usr/lib"))?;
fs::create_dir_all(staging.join("usr/share/man/man1"))?;
fs::write(staging.join("usr/lib/libfoo.so.1"), "relocated")?; fs::write(staging.join("usr/lib/libfoo.so.1"), "relocated")?;
fs::write(staging.join("usr/share/man/man1/foo.1"), "manpage")?;
unix_fs::symlink("libfoo.so.1", staging.join("usr/lib/libfoo.so"))?; unix_fs::symlink("libfoo.so.1", staging.join("usr/lib/libfoo.so"))?;
stage_lib32_install_tree(&staging, &dest)?; stage_lib32_install_tree(&staging, &dest)?;
@@ -1011,6 +1112,11 @@ mod tests {
fs::read_link(dest.join("usr/lib32/libfoo.so"))?, fs::read_link(dest.join("usr/lib32/libfoo.so"))?,
PathBuf::from("libfoo.so.1") PathBuf::from("libfoo.so.1")
); );
assert_eq!(
fs::read_to_string(dest.join("usr/share/man/man1/foo.1"))?,
"manpage"
);
assert!(!dest.join("usr/lib").exists());
Ok(()) Ok(())
} }
} }