Implement Perl build helper commands and integrate into CLI
- Added `run_helper_configure` and `run_helper_install` functions in `perl.rs` to handle Perl-specific build configurations and installations. - Introduced new internal commands in `cli.rs` for Perl configuration and installation. - Updated `internal.rs` to execute Perl helper commands using the new functions. - Enhanced `shell_helpers.rs` to include scripts for Perl configure and install commands. - Modified `hooks.rs` to apply build helper context and directories for post-extract and post-configure commands. - Added tests to ensure the correct execution of Perl build helper commands and their integration with the build process.
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
//! GNU Autotools build system (configure && make && make install)
|
||||
|
||||
use crate::builder::BuildHelperContext;
|
||||
use crate::builder::state::{BuildStep, StateTracker};
|
||||
use crate::cross::CrossConfig;
|
||||
use crate::fakeroot;
|
||||
@@ -501,6 +502,202 @@ pub(crate) fn ensure_host_build(
|
||||
.with_context(|| format!("Failed to resolve host build dir: {}", build_dir.display()))
|
||||
}
|
||||
|
||||
pub(crate) fn run_helper_configure(
|
||||
context: &BuildHelperContext,
|
||||
source_dir: Option<&Path>,
|
||||
build_dir: Option<&Path>,
|
||||
cross: Option<&CrossConfig>,
|
||||
env_vars: &[(String, String)],
|
||||
extra_args: &[String],
|
||||
) -> Result<()> {
|
||||
let flags = context.build_flags();
|
||||
let source_dir = source_dir
|
||||
.map(Path::to_path_buf)
|
||||
.unwrap_or(std::env::current_dir().context("Failed to determine current directory")?);
|
||||
let build_dir = build_dir.map(Path::to_path_buf).unwrap_or_else(|| {
|
||||
flags
|
||||
.build_dir
|
||||
.as_ref()
|
||||
.map(|dir| source_dir.join(dir))
|
||||
.unwrap_or_else(|| source_dir.clone())
|
||||
});
|
||||
fs::create_dir_all(&build_dir)
|
||||
.with_context(|| format!("Failed to create build directory: {}", build_dir.display()))?;
|
||||
|
||||
let mut helper_env = env_vars.to_vec();
|
||||
let cc = if let Some(cc_cfg) = cross {
|
||||
cc_cfg.cc.clone()
|
||||
} else {
|
||||
helper_env
|
||||
.iter()
|
||||
.find(|(key, _)| key == "CC")
|
||||
.map(|(_, value)| value.clone())
|
||||
.unwrap_or_else(|| flags.cc.clone())
|
||||
};
|
||||
|
||||
if let Some(cflags_str) = helper_env
|
||||
.iter()
|
||||
.find(|(key, _)| key == "CFLAGS")
|
||||
.map(|(_, value)| value.clone())
|
||||
.filter(|value| !value.trim().is_empty())
|
||||
{
|
||||
let expanded = expand_shell_commands(&cflags_str, &cc)?;
|
||||
crate::builder::set_env_var(&mut helper_env, "CFLAGS", expanded);
|
||||
}
|
||||
|
||||
let configure_path = helper_configure_path(context, &source_dir);
|
||||
let mut configure_cmd = Command::new(&configure_path);
|
||||
configure_cmd.current_dir(&build_dir);
|
||||
crate::builder::prepare_tool_command(&mut configure_cmd, &helper_env);
|
||||
|
||||
let help_text = configure_help_text(&configure_path, &build_dir, &helper_env);
|
||||
configure_cmd.arg(format!("--prefix={}", flags.prefix));
|
||||
for default_dir_arg in default_configure_install_dirs(&flags, help_text.as_deref()) {
|
||||
configure_cmd.arg(default_dir_arg);
|
||||
}
|
||||
|
||||
let supports_host =
|
||||
configure_supports_option(help_text.as_deref(), "--host", &flags.configure_file);
|
||||
let supports_build =
|
||||
configure_supports_option(help_text.as_deref(), "--build", &flags.configure_file);
|
||||
|
||||
let requested_host = if let Some(cc_cfg) = cross {
|
||||
Some(cc_cfg.host_triple().to_string())
|
||||
} else if !flags.chost.is_empty() {
|
||||
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()
|
||||
} else if !flags.cbuild.is_empty() {
|
||||
Some(flags.cbuild.clone())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if let Some(host) = requested_host {
|
||||
if supports_host {
|
||||
configure_cmd.arg(format!("--host={host}"));
|
||||
} else {
|
||||
crate::log_info!(" configure does not support --host; skipping {}", host);
|
||||
}
|
||||
}
|
||||
if let Some(build) = requested_build {
|
||||
if supports_build {
|
||||
configure_cmd.arg(format!("--build={build}"));
|
||||
} else {
|
||||
crate::log_info!(" configure does not support --build; skipping {}", build);
|
||||
}
|
||||
}
|
||||
|
||||
for arg in &flags.configure {
|
||||
configure_cmd.arg(expand_with_envs(&context.expand_vars(arg), &helper_env));
|
||||
}
|
||||
for arg in crate::builder::static_build_args_for(crate::package::BuildType::Autotools, &flags)?
|
||||
{
|
||||
add_auto_configure_arg_if_supported(&mut configure_cmd, help_text.as_deref(), &arg);
|
||||
}
|
||||
for arg in extra_args {
|
||||
add_auto_configure_arg_if_supported(
|
||||
&mut configure_cmd,
|
||||
help_text.as_deref(),
|
||||
&expand_with_envs(&context.expand_vars(arg), &helper_env),
|
||||
);
|
||||
}
|
||||
|
||||
let status = crate::interrupts::command_status(&mut configure_cmd)
|
||||
.with_context(|| format!("Failed to run helper configure in {}", build_dir.display()))?;
|
||||
if !status.success() {
|
||||
anyhow::bail!("configure failed with status: {}", status);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn run_helper_install(
|
||||
context: &BuildHelperContext,
|
||||
build_dir: Option<&Path>,
|
||||
env_vars: &[(String, String)],
|
||||
extra_args: &[String],
|
||||
) -> Result<()> {
|
||||
let flags = context.build_flags();
|
||||
let source_dir = helper_source_dir();
|
||||
let build_dir = build_dir.map(Path::to_path_buf).unwrap_or_else(|| {
|
||||
flags
|
||||
.build_dir
|
||||
.as_ref()
|
||||
.map(|dir| source_dir.join(dir))
|
||||
.unwrap_or_else(|| source_dir.clone())
|
||||
});
|
||||
let destdir = std::env::var("DESTDIR").context("DESTDIR must be set for autotools_install")?;
|
||||
let make_exec = resolve_make_exec(&flags.make_exec);
|
||||
let install_dirs = resolve_make_dirs(
|
||||
&build_dir,
|
||||
&flags.make_install_dirs,
|
||||
"build.flags.make_install_dirs",
|
||||
)?;
|
||||
let install_targets = phase_targets(
|
||||
&flags.make_install_target,
|
||||
&flags.make_install_targets,
|
||||
Some("install"),
|
||||
);
|
||||
|
||||
for install_dir in install_dirs {
|
||||
let mut install_cmd = fakeroot::wrap_install_command(make_exec, Path::new(&destdir));
|
||||
install_cmd.current_dir(&install_dir);
|
||||
if make_exec_supports_make_assignments(make_exec)
|
||||
&& !has_make_variable_override(&flags.make_install_vars, "DESTDIR")
|
||||
{
|
||||
install_cmd.arg(format!("DESTDIR={destdir}"));
|
||||
}
|
||||
add_make_variable_overrides_if_supported(
|
||||
&mut install_cmd,
|
||||
make_exec,
|
||||
&flags.make_install_vars,
|
||||
"install",
|
||||
)?;
|
||||
for install_target in &install_targets {
|
||||
install_cmd.arg(install_target);
|
||||
}
|
||||
for arg in extra_args {
|
||||
install_cmd.arg(context.expand_vars(arg));
|
||||
}
|
||||
|
||||
let mut install_env = env_vars.to_vec();
|
||||
crate::builder::set_env_var(&mut install_env, "DESTDIR", destdir.clone());
|
||||
crate::builder::prepare_tool_command(&mut install_cmd, &install_env);
|
||||
|
||||
let status = crate::interrupts::command_status(&mut install_cmd).with_context(|| {
|
||||
format!(
|
||||
"Failed to run helper {} {} in {}",
|
||||
make_exec,
|
||||
install_targets.join(" "),
|
||||
install_dir.display()
|
||||
)
|
||||
})?;
|
||||
if !status.success() {
|
||||
anyhow::bail!(
|
||||
"{} {} failed with status: {} (dir: {})",
|
||||
make_exec,
|
||||
install_targets.join(" "),
|
||||
status,
|
||||
install_dir.display()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn num_cpus() -> usize {
|
||||
std::thread::available_parallelism()
|
||||
.map(|n| n.get())
|
||||
@@ -544,6 +741,22 @@ fn resolve_configure_path(spec: &PackageSpec, actual_src: &Path) -> PathBuf {
|
||||
}
|
||||
}
|
||||
|
||||
fn helper_configure_path(context: &BuildHelperContext, actual_src: &Path) -> PathBuf {
|
||||
let flags = context.build_flags();
|
||||
let configured = context.expand_vars(&flags.configure_file);
|
||||
let trimmed = configured.trim();
|
||||
if trimmed.is_empty() {
|
||||
return actual_src.join("configure");
|
||||
}
|
||||
|
||||
let path = Path::new(trimmed);
|
||||
if path.is_absolute() {
|
||||
path.to_path_buf()
|
||||
} else {
|
||||
actual_src.join(path)
|
||||
}
|
||||
}
|
||||
|
||||
fn configure_help_text(
|
||||
configure_path: &Path,
|
||||
build_dir: &Path,
|
||||
@@ -823,6 +1036,12 @@ fn nonempty_trimmed(value: &str) -> Option<&str> {
|
||||
(!trimmed.is_empty()).then_some(trimmed)
|
||||
}
|
||||
|
||||
fn helper_source_dir() -> PathBuf {
|
||||
std::env::var(crate::builder::DEPOT_BUILD_HELPER_SOURCE_DIR_ENV)
|
||||
.map(PathBuf::from)
|
||||
.unwrap_or_else(|_| std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")))
|
||||
}
|
||||
|
||||
pub(crate) fn resolve_make_exec(configured: &str) -> &str {
|
||||
nonempty_trimmed(configured).unwrap_or("make")
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
//! CMake build system
|
||||
|
||||
use crate::builder::BuildHelperContext;
|
||||
use crate::builder::state::{BuildStep, StateTracker};
|
||||
use crate::cross::CrossConfig;
|
||||
use crate::fakeroot;
|
||||
@@ -359,6 +360,139 @@ pub(crate) fn ensure_host_build(
|
||||
.with_context(|| format!("Failed to resolve host build dir: {}", build_dir.display()))
|
||||
}
|
||||
|
||||
pub(crate) fn run_helper_configure(
|
||||
context: &BuildHelperContext,
|
||||
source_dir: Option<&Path>,
|
||||
build_dir: Option<&Path>,
|
||||
cross: Option<&CrossConfig>,
|
||||
env_vars: &[(String, String)],
|
||||
extra_args: &[String],
|
||||
) -> Result<()> {
|
||||
let flags = context.build_flags();
|
||||
let source_dir = source_dir
|
||||
.map(Path::to_path_buf)
|
||||
.unwrap_or(std::env::current_dir().context("Failed to determine current directory")?);
|
||||
let build_dir = build_dir.map(Path::to_path_buf).unwrap_or_else(|| {
|
||||
flags
|
||||
.build_dir
|
||||
.as_ref()
|
||||
.map(|dir| source_dir.join(dir))
|
||||
.unwrap_or_else(|| source_dir.join("build"))
|
||||
});
|
||||
let prefix = effective_cmake_install_prefix(&flags);
|
||||
|
||||
fs::create_dir_all(&build_dir)
|
||||
.with_context(|| format!("Failed to create build directory: {}", build_dir.display()))?;
|
||||
|
||||
let toolchain_file = if let Some(cc_cfg) = cross {
|
||||
Some(cc_cfg.generate_cmake_toolchain(&build_dir)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let mut cmake_cmd = Command::new("cmake");
|
||||
cmake_cmd.current_dir(&build_dir);
|
||||
cmake_cmd.arg("-S").arg(&source_dir);
|
||||
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, prefix) {
|
||||
cmake_cmd.arg(arg);
|
||||
}
|
||||
for arg in cmake_lib32_target_args(&flags, cross) {
|
||||
cmake_cmd.arg(arg);
|
||||
}
|
||||
if let Some(toolchain_file) = &toolchain_file {
|
||||
cmake_cmd.arg(format!(
|
||||
"-DCMAKE_TOOLCHAIN_FILE={}",
|
||||
toolchain_file.display()
|
||||
));
|
||||
}
|
||||
|
||||
let make_exec_override = flags.make_exec.trim();
|
||||
if !make_exec_override.is_empty() {
|
||||
if !cmake_configure_flags_specify_generator(&flags.configure)
|
||||
&& let Some(generator) = cmake_generator_for_make_exec(make_exec_override)
|
||||
{
|
||||
cmake_cmd.arg("-G").arg(generator);
|
||||
}
|
||||
if !cmake_configure_flags_set_make_program(&flags.configure) {
|
||||
cmake_cmd.arg(format!("-DCMAKE_MAKE_PROGRAM={make_exec_override}"));
|
||||
}
|
||||
}
|
||||
|
||||
for flag in &flags.configure {
|
||||
cmake_cmd.arg(expand_with_envs(&context.expand_vars(flag), env_vars));
|
||||
}
|
||||
for arg in crate::builder::static_build_args_for(crate::package::BuildType::CMake, &flags)? {
|
||||
cmake_cmd.arg(arg);
|
||||
}
|
||||
for arg in extra_args {
|
||||
cmake_cmd.arg(expand_with_envs(&context.expand_vars(arg), env_vars));
|
||||
}
|
||||
|
||||
crate::builder::prepare_tool_command(&mut cmake_cmd, &env_vars.to_vec());
|
||||
|
||||
let status = crate::interrupts::command_status(&mut cmake_cmd)
|
||||
.context("Failed to run helper cmake configure")?;
|
||||
if !status.success() {
|
||||
anyhow::bail!("cmake configure failed");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn run_helper_install(
|
||||
context: &BuildHelperContext,
|
||||
build_dir: Option<&Path>,
|
||||
env_vars: &[(String, String)],
|
||||
extra_args: &[String],
|
||||
) -> Result<()> {
|
||||
let flags = context.build_flags();
|
||||
let source_dir = helper_source_dir();
|
||||
let build_dir = build_dir.map(Path::to_path_buf).unwrap_or_else(|| {
|
||||
flags
|
||||
.build_dir
|
||||
.as_ref()
|
||||
.map(|dir| source_dir.join(dir))
|
||||
.unwrap_or_else(|| source_dir.join("build"))
|
||||
});
|
||||
let destdir = std::env::var("DESTDIR").context("DESTDIR must be set for cmake_install")?;
|
||||
let install_targets = phase_targets(&flags.make_install_target, &flags.make_install_targets);
|
||||
|
||||
let mut install_cmd = fakeroot::wrap_install_command("cmake", Path::new(&destdir));
|
||||
if install_targets.is_empty() {
|
||||
install_cmd.arg("--install").arg(&build_dir);
|
||||
} else {
|
||||
install_cmd.arg("--build").arg(&build_dir);
|
||||
install_cmd.arg("--target");
|
||||
for target in &install_targets {
|
||||
install_cmd.arg(target);
|
||||
}
|
||||
}
|
||||
for arg in extra_args {
|
||||
install_cmd.arg(context.expand_vars(arg));
|
||||
}
|
||||
|
||||
let mut install_env = env_vars.to_vec();
|
||||
crate::builder::set_env_var(&mut install_env, "DESTDIR", destdir);
|
||||
crate::builder::prepare_tool_command(&mut install_cmd, &install_env);
|
||||
|
||||
let status = crate::interrupts::command_status(&mut install_cmd)
|
||||
.context("Failed to run helper cmake install")?;
|
||||
if !status.success() {
|
||||
if install_targets.is_empty() {
|
||||
anyhow::bail!("cmake install failed");
|
||||
}
|
||||
anyhow::bail!(
|
||||
"cmake install target(s) '{}' failed",
|
||||
install_targets.join(" ")
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Expand environment variables in a string (e.g., $DEPOT_SYSROOT)
|
||||
fn expand_env_vars(input: &str) -> String {
|
||||
let mut result = input.to_string();
|
||||
@@ -580,6 +714,12 @@ fn num_cpus() -> usize {
|
||||
.unwrap_or(1)
|
||||
}
|
||||
|
||||
fn helper_source_dir() -> PathBuf {
|
||||
std::env::var(crate::builder::DEPOT_BUILD_HELPER_SOURCE_DIR_ENV)
|
||||
.map(PathBuf::from)
|
||||
.unwrap_or_else(|_| std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")))
|
||||
}
|
||||
|
||||
/// Resolve `source_subdir` with multiple fallbacks:
|
||||
/// - empty -> use `src_dir`
|
||||
/// - absolute path -> use if exists
|
||||
|
||||
+18
-8
@@ -51,6 +51,8 @@ pub fn build(
|
||||
let mut env_vars = crate::builder::standard_build_env(spec, cross, true, export_compiler_flags);
|
||||
let shell_helpers = crate::shell_helpers::ShellHelpers::new(&install_destdir)?;
|
||||
shell_helpers.apply_to_env_vars(&mut env_vars);
|
||||
crate::builder::apply_build_helper_context_env(&mut env_vars, spec)?;
|
||||
crate::builder::apply_build_helper_dirs_env(&mut env_vars, Some(src_dir), Some(&build_dir));
|
||||
|
||||
// For custom builds, look for a build.sh script in the source directory
|
||||
let build_script = src_dir.join("build.sh");
|
||||
@@ -280,19 +282,27 @@ fn build_function_mode_install_command(
|
||||
"DEPOT_OUTPUT_NAME='{q_name}'; DEPOT_OUTPUT_DESTDIR='{q_dest}'; DESTDIR=\"$DEPOT_OUTPUT_DESTDIR\"; export DEPOT_OUTPUT_NAME DEPOT_OUTPUT_DESTDIR DESTDIR\n"
|
||||
));
|
||||
wrapper.push_str("depot_output_installed=0\n");
|
||||
wrapper.push_str(&format!(
|
||||
"if depot_has_function depot_install_{fn_suffix}; then depot_install_{fn_suffix}; depot_output_installed=1;\n"
|
||||
));
|
||||
wrapper.push_str(&format!(
|
||||
"elif depot_has_function install_{fn_suffix}; then install_{fn_suffix}; depot_output_installed=1;\n"
|
||||
));
|
||||
if out.name == *primary {
|
||||
wrapper
|
||||
.push_str("elif depot_has_function depot_install; then depot_install; depot_output_installed=1;\n");
|
||||
wrapper.push_str(
|
||||
"if depot_has_function depot_install; then depot_install; depot_output_installed=1;\n",
|
||||
);
|
||||
wrapper.push_str(
|
||||
"elif depot_has_function install; then install; depot_output_installed=1;\n",
|
||||
);
|
||||
wrapper.push_str(&format!(
|
||||
"elif depot_has_function depot_install_{fn_suffix}; then depot_install_{fn_suffix}; depot_output_installed=1;\n"
|
||||
));
|
||||
wrapper.push_str(&format!(
|
||||
"elif depot_has_function install_{fn_suffix}; then install_{fn_suffix}; depot_output_installed=1;\n"
|
||||
));
|
||||
wrapper.push_str("elif [ \"$depot_build_ran\" = 1 ]; then depot_output_installed=1;\n");
|
||||
} else {
|
||||
wrapper.push_str(&format!(
|
||||
"if depot_has_function depot_install_{fn_suffix}; then depot_install_{fn_suffix}; depot_output_installed=1;\n"
|
||||
));
|
||||
wrapper.push_str(&format!(
|
||||
"elif depot_has_function install_{fn_suffix}; then install_{fn_suffix}; depot_output_installed=1;\n"
|
||||
));
|
||||
}
|
||||
wrapper.push_str("fi\n");
|
||||
wrapper.push_str("if [ \"$depot_output_installed\" != 1 ]; then\n");
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
//! Meson build system
|
||||
|
||||
use crate::builder::BuildHelperContext;
|
||||
use crate::builder::state::{BuildStep, StateTracker};
|
||||
use crate::cross::CrossConfig;
|
||||
use crate::fakeroot;
|
||||
@@ -267,12 +268,106 @@ pub(crate) fn ensure_host_build(
|
||||
.with_context(|| format!("Failed to resolve host build dir: {}", build_dir.display()))
|
||||
}
|
||||
|
||||
pub(crate) fn run_helper_configure(
|
||||
context: &BuildHelperContext,
|
||||
source_dir: Option<&Path>,
|
||||
build_dir: Option<&Path>,
|
||||
cross: Option<&CrossConfig>,
|
||||
env_vars: &[(String, String)],
|
||||
extra_args: &[String],
|
||||
) -> Result<()> {
|
||||
let flags = context.build_flags();
|
||||
let source_dir = source_dir
|
||||
.map(Path::to_path_buf)
|
||||
.unwrap_or(std::env::current_dir().context("Failed to determine current directory")?);
|
||||
let build_dir = build_dir
|
||||
.map(Path::to_path_buf)
|
||||
.unwrap_or_else(|| resolve_build_dir(&source_dir, &flags));
|
||||
|
||||
fs::create_dir_all(&build_dir)
|
||||
.with_context(|| format!("Failed to create build directory: {}", build_dir.display()))?;
|
||||
|
||||
let mut helper_env = env_vars.to_vec();
|
||||
configure_pkg_config_env(&mut helper_env, &flags, cross);
|
||||
|
||||
let cross_file = if let Some(cc_cfg) = cross {
|
||||
Some(cc_cfg.generate_meson_cross_file(&build_dir)?)
|
||||
} else if flags.lib32_variant {
|
||||
Some(generate_lib32_meson_cross_file(&flags, &build_dir)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let mut meson_cmd = Command::new("meson");
|
||||
meson_cmd.current_dir(&source_dir);
|
||||
meson_cmd.arg("setup");
|
||||
meson_cmd.arg(&build_dir);
|
||||
|
||||
for arg in meson_setup_args(&flags, cross_file.as_deref(), &helper_env) {
|
||||
meson_cmd.arg(arg);
|
||||
}
|
||||
for arg in crate::builder::static_build_args_for(crate::package::BuildType::Meson, &flags)? {
|
||||
meson_cmd.arg(arg);
|
||||
}
|
||||
for arg in extra_args {
|
||||
meson_cmd.arg(context.expand_vars(arg));
|
||||
}
|
||||
|
||||
crate::builder::prepare_tool_command(&mut meson_cmd, &helper_env);
|
||||
|
||||
let status = crate::interrupts::command_status(&mut meson_cmd)
|
||||
.context("Failed to run helper meson setup")?;
|
||||
if !status.success() {
|
||||
bail!("meson setup failed");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn run_helper_install(
|
||||
context: &BuildHelperContext,
|
||||
build_dir: Option<&Path>,
|
||||
env_vars: &[(String, String)],
|
||||
extra_args: &[String],
|
||||
) -> Result<()> {
|
||||
let flags = context.build_flags();
|
||||
let build_dir = build_dir
|
||||
.map(Path::to_path_buf)
|
||||
.unwrap_or_else(|| resolve_build_dir(&helper_source_dir(), &flags));
|
||||
let destdir = std::env::var("DESTDIR").context("DESTDIR must be set for meson_install")?;
|
||||
|
||||
let mut install_cmd = fakeroot::wrap_install_command("meson", Path::new(&destdir));
|
||||
install_cmd.arg("install");
|
||||
install_cmd.arg("-C").arg(&build_dir);
|
||||
for arg in extra_args {
|
||||
install_cmd.arg(context.expand_vars(arg));
|
||||
}
|
||||
|
||||
let mut install_env = env_vars.to_vec();
|
||||
crate::builder::set_env_var(&mut install_env, "DESTDIR", destdir);
|
||||
crate::builder::prepare_tool_command(&mut install_cmd, &install_env);
|
||||
|
||||
let status = crate::interrupts::command_status(&mut install_cmd)
|
||||
.context("Failed to run helper meson install")?;
|
||||
if !status.success() {
|
||||
bail!("meson install failed");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn num_cpus() -> usize {
|
||||
std::thread::available_parallelism()
|
||||
.map(|n| n.get())
|
||||
.unwrap_or(1)
|
||||
}
|
||||
|
||||
fn helper_source_dir() -> PathBuf {
|
||||
std::env::var(crate::builder::DEPOT_BUILD_HELPER_SOURCE_DIR_ENV)
|
||||
.map(PathBuf::from)
|
||||
.unwrap_or_else(|_| std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")))
|
||||
}
|
||||
|
||||
fn resolve_build_dir(actual_src: &Path, flags: &crate::package::BuildFlags) -> PathBuf {
|
||||
if let Some(dir) = flags
|
||||
.build_dir
|
||||
|
||||
@@ -22,6 +22,9 @@ use walkdir::WalkDir;
|
||||
|
||||
pub type EnvVars = Vec<(String, String)>;
|
||||
pub(crate) const DEPOT_BUILD_HOST_DIR_ENV: &str = "DEPOT_BUILD_HOST_DIR";
|
||||
pub(crate) const DEPOT_BUILD_HELPER_CONTEXT_ENV: &str = "DEPOT_BUILD_HELPER_CONTEXT";
|
||||
pub(crate) const DEPOT_BUILD_HELPER_SOURCE_DIR_ENV: &str = "DEPOT_BUILD_HELPER_SOURCE_DIR";
|
||||
pub(crate) const DEPOT_BUILD_HELPER_BUILD_DIR_ENV: &str = "DEPOT_BUILD_HELPER_BUILD_DIR";
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum TargetBuildKind {
|
||||
@@ -45,6 +48,154 @@ pub(crate) struct InstallDirs {
|
||||
pub infodir: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
|
||||
pub(crate) struct BuildHelperContext {
|
||||
pub package_name: String,
|
||||
pub package_version: String,
|
||||
pub spec_dir: PathBuf,
|
||||
pub flags: BuildFlags,
|
||||
pub lib32_variant: bool,
|
||||
pub host_build_dir: Option<String>,
|
||||
}
|
||||
|
||||
impl BuildHelperContext {
|
||||
pub(crate) fn from_spec(spec: &PackageSpec) -> Self {
|
||||
Self {
|
||||
package_name: spec.package.name.clone(),
|
||||
package_version: spec.package.version.clone(),
|
||||
spec_dir: spec.spec_dir.clone(),
|
||||
flags: spec.build.flags.clone(),
|
||||
lib32_variant: spec.build.flags.lib32_variant,
|
||||
host_build_dir: spec.build.flags.host_build_dir.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn expand_vars(&self, input: &str) -> String {
|
||||
let specdir = self.spec_dir.to_string_lossy();
|
||||
input
|
||||
.replace("$name", &self.package_name)
|
||||
.replace("$version", &self.package_version)
|
||||
.replace("$specdir", &specdir)
|
||||
.replace("$DEPOT_SPECDIR", &specdir)
|
||||
}
|
||||
|
||||
pub(crate) fn build_flags(&self) -> BuildFlags {
|
||||
let mut flags = self.flags.clone();
|
||||
flags.lib32_variant = self.lib32_variant;
|
||||
flags.host_build_dir = self.host_build_dir.clone();
|
||||
flags
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn apply_build_helper_context_env(
|
||||
env_vars: &mut EnvVars,
|
||||
spec: &PackageSpec,
|
||||
) -> Result<()> {
|
||||
let encoded = toml::to_string(&BuildHelperContext::from_spec(spec))
|
||||
.context("Failed to serialize build helper context")?;
|
||||
set_env_var(env_vars, DEPOT_BUILD_HELPER_CONTEXT_ENV, encoded);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn apply_build_helper_dirs_env(
|
||||
env_vars: &mut EnvVars,
|
||||
source_dir: Option<&Path>,
|
||||
build_dir: Option<&Path>,
|
||||
) {
|
||||
if let Some(source_dir) = source_dir {
|
||||
set_env_var(
|
||||
env_vars,
|
||||
DEPOT_BUILD_HELPER_SOURCE_DIR_ENV,
|
||||
source_dir.to_string_lossy().into_owned(),
|
||||
);
|
||||
}
|
||||
if let Some(build_dir) = build_dir {
|
||||
set_env_var(
|
||||
env_vars,
|
||||
DEPOT_BUILD_HELPER_BUILD_DIR_ENV,
|
||||
build_dir.to_string_lossy().into_owned(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn run_autotools_helper_configure(
|
||||
context: &BuildHelperContext,
|
||||
source_dir: Option<&Path>,
|
||||
build_dir: Option<&Path>,
|
||||
cross: Option<&CrossConfig>,
|
||||
env_vars: &EnvVars,
|
||||
extra_args: &[String],
|
||||
) -> Result<()> {
|
||||
autotools::run_helper_configure(context, source_dir, build_dir, cross, env_vars, extra_args)
|
||||
}
|
||||
|
||||
pub(crate) fn run_autotools_helper_install(
|
||||
context: &BuildHelperContext,
|
||||
build_dir: Option<&Path>,
|
||||
env_vars: &EnvVars,
|
||||
extra_args: &[String],
|
||||
) -> Result<()> {
|
||||
autotools::run_helper_install(context, build_dir, env_vars, extra_args)
|
||||
}
|
||||
|
||||
pub(crate) fn run_cmake_helper_configure(
|
||||
context: &BuildHelperContext,
|
||||
source_dir: Option<&Path>,
|
||||
build_dir: Option<&Path>,
|
||||
cross: Option<&CrossConfig>,
|
||||
env_vars: &EnvVars,
|
||||
extra_args: &[String],
|
||||
) -> Result<()> {
|
||||
cmake::run_helper_configure(context, source_dir, build_dir, cross, env_vars, extra_args)
|
||||
}
|
||||
|
||||
pub(crate) fn run_cmake_helper_install(
|
||||
context: &BuildHelperContext,
|
||||
build_dir: Option<&Path>,
|
||||
env_vars: &EnvVars,
|
||||
extra_args: &[String],
|
||||
) -> Result<()> {
|
||||
cmake::run_helper_install(context, build_dir, env_vars, extra_args)
|
||||
}
|
||||
|
||||
pub(crate) fn run_meson_helper_configure(
|
||||
context: &BuildHelperContext,
|
||||
source_dir: Option<&Path>,
|
||||
build_dir: Option<&Path>,
|
||||
cross: Option<&CrossConfig>,
|
||||
env_vars: &EnvVars,
|
||||
extra_args: &[String],
|
||||
) -> Result<()> {
|
||||
meson::run_helper_configure(context, source_dir, build_dir, cross, env_vars, extra_args)
|
||||
}
|
||||
|
||||
pub(crate) fn run_meson_helper_install(
|
||||
context: &BuildHelperContext,
|
||||
build_dir: Option<&Path>,
|
||||
env_vars: &EnvVars,
|
||||
extra_args: &[String],
|
||||
) -> Result<()> {
|
||||
meson::run_helper_install(context, build_dir, env_vars, extra_args)
|
||||
}
|
||||
|
||||
pub(crate) fn run_perl_helper_configure(
|
||||
context: &BuildHelperContext,
|
||||
source_dir: Option<&Path>,
|
||||
env_vars: &EnvVars,
|
||||
extra_args: &[String],
|
||||
) -> Result<()> {
|
||||
perl::run_helper_configure(context, source_dir, env_vars, extra_args)
|
||||
}
|
||||
|
||||
pub(crate) fn run_perl_helper_install(
|
||||
context: &BuildHelperContext,
|
||||
build_dir: Option<&Path>,
|
||||
env_vars: &EnvVars,
|
||||
extra_args: &[String],
|
||||
) -> Result<()> {
|
||||
perl::run_helper_install(context, build_dir, env_vars, extra_args)
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -1353,6 +1504,17 @@ mod tests {
|
||||
assert_eq!(lib32_dirs.libexecdir, "/usr/lib32");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_build_helper_context_restores_runtime_build_flags() {
|
||||
let mut spec = mk_spec(Vec::new(), Vec::new());
|
||||
spec.build.flags.lib32_variant = true;
|
||||
spec.build.flags.host_build_dir = Some("/tmp/build-host".into());
|
||||
|
||||
let restored = BuildHelperContext::from_spec(&spec).build_flags();
|
||||
assert!(restored.lib32_variant);
|
||||
assert_eq!(restored.host_build_dir.as_deref(), Some("/tmp/build-host"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_install_dirs_respect_explicit_overrides_and_derived_defaults() {
|
||||
let dirs = install_dirs(&BuildFlags {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
//! Perl MakeMaker build system (`perl Makefile.PL && make && make test && make install`)
|
||||
|
||||
use crate::builder::BuildHelperContext;
|
||||
use crate::builder::autotools;
|
||||
use crate::builder::state::{BuildStep, StateTracker};
|
||||
use crate::cross::CrossConfig;
|
||||
@@ -261,6 +262,124 @@ pub fn build(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn run_helper_configure(
|
||||
context: &BuildHelperContext,
|
||||
source_dir: Option<&Path>,
|
||||
env_vars: &[(String, String)],
|
||||
extra_args: &[String],
|
||||
) -> Result<()> {
|
||||
let flags = context.build_flags();
|
||||
let source_dir = source_dir
|
||||
.map(Path::to_path_buf)
|
||||
.unwrap_or(std::env::current_dir().context("Failed to determine current directory")?);
|
||||
let configure_script = helper_configure_script(context, &source_dir);
|
||||
let mut helper_env = env_vars.to_vec();
|
||||
crate::builder::set_env_var(&mut helper_env, "PERL_MM_USE_DEFAULT", "1");
|
||||
if !flags.rootfs.is_empty() && flags.rootfs != "/" {
|
||||
crate::builder::set_env_var(
|
||||
&mut helper_env,
|
||||
"PKG_CONFIG_SYSROOT_DIR",
|
||||
flags.rootfs.clone(),
|
||||
);
|
||||
}
|
||||
|
||||
let mut configure_cmd =
|
||||
Command::new(resolved_command_path("perl").unwrap_or_else(|| PathBuf::from("perl")));
|
||||
configure_cmd.current_dir(&source_dir);
|
||||
configure_cmd.arg(&configure_script);
|
||||
if !has_assignment_prefix(&flags.configure, "INSTALLDIRS") {
|
||||
configure_cmd.arg("INSTALLDIRS=vendor");
|
||||
}
|
||||
for arg in &flags.configure {
|
||||
configure_cmd.arg(context.expand_vars(arg));
|
||||
}
|
||||
for arg in crate::builder::static_build_args_for(crate::package::BuildType::Perl, &flags)? {
|
||||
configure_cmd.arg(arg);
|
||||
}
|
||||
for arg in extra_args {
|
||||
configure_cmd.arg(context.expand_vars(arg));
|
||||
}
|
||||
crate::builder::prepare_tool_command(&mut configure_cmd, &helper_env);
|
||||
|
||||
let status = command_status_with_sh_fallback(&mut configure_cmd)
|
||||
.context("Failed to run helper perl configure")?;
|
||||
if !status.success() {
|
||||
anyhow::bail!("perl Makefile.PL failed with status: {}", status);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn run_helper_install(
|
||||
context: &BuildHelperContext,
|
||||
build_dir: Option<&Path>,
|
||||
env_vars: &[(String, String)],
|
||||
extra_args: &[String],
|
||||
) -> Result<()> {
|
||||
let flags = context.build_flags();
|
||||
let build_dir = build_dir
|
||||
.map(Path::to_path_buf)
|
||||
.unwrap_or_else(helper_source_dir);
|
||||
let destdir = std::env::var("DESTDIR").context("DESTDIR must be set for perl_install")?;
|
||||
let make_exec = autotools::resolve_make_exec(&flags.make_exec);
|
||||
let install_dirs = autotools::resolve_make_dirs(
|
||||
&build_dir,
|
||||
&flags.make_install_dirs,
|
||||
"build.flags.make_install_dirs",
|
||||
)?;
|
||||
let install_targets = autotools::phase_targets(
|
||||
&flags.make_install_target,
|
||||
&flags.make_install_targets,
|
||||
Some("install"),
|
||||
);
|
||||
|
||||
for install_dir in install_dirs {
|
||||
let mut install_cmd = fakeroot::wrap_install_command(make_exec, Path::new(&destdir));
|
||||
install_cmd.current_dir(&install_dir);
|
||||
if autotools::make_exec_supports_make_assignments(make_exec)
|
||||
&& !autotools::has_make_variable_override(&flags.make_install_vars, "DESTDIR")
|
||||
{
|
||||
install_cmd.arg(format!("DESTDIR={destdir}"));
|
||||
}
|
||||
autotools::add_make_variable_overrides_if_supported(
|
||||
&mut install_cmd,
|
||||
make_exec,
|
||||
&flags.make_install_vars,
|
||||
"install",
|
||||
)?;
|
||||
for target in &install_targets {
|
||||
install_cmd.arg(target);
|
||||
}
|
||||
for arg in extra_args {
|
||||
install_cmd.arg(context.expand_vars(arg));
|
||||
}
|
||||
|
||||
let mut install_env = env_vars.to_vec();
|
||||
crate::builder::set_env_var(&mut install_env, "DESTDIR", destdir.clone());
|
||||
crate::builder::prepare_tool_command(&mut install_cmd, &install_env);
|
||||
|
||||
let status = command_status_with_sh_fallback(&mut install_cmd).with_context(|| {
|
||||
format!(
|
||||
"Failed to run helper {} {} in {}",
|
||||
make_exec,
|
||||
install_targets.join(" "),
|
||||
install_dir.display()
|
||||
)
|
||||
})?;
|
||||
if !status.success() {
|
||||
anyhow::bail!(
|
||||
"{} {} failed with status: {} (dir: {})",
|
||||
make_exec,
|
||||
install_targets.join(" "),
|
||||
status,
|
||||
install_dir.display()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn resolve_perl_configure_script(spec: &PackageSpec, actual_src: &Path) -> PathBuf {
|
||||
let configured = spec.expand_vars(&spec.build.flags.configure_file);
|
||||
let trimmed = configured.trim();
|
||||
@@ -276,6 +395,22 @@ fn resolve_perl_configure_script(spec: &PackageSpec, actual_src: &Path) -> PathB
|
||||
}
|
||||
}
|
||||
|
||||
fn helper_configure_script(context: &BuildHelperContext, actual_src: &Path) -> PathBuf {
|
||||
let flags = context.build_flags();
|
||||
let configured = context.expand_vars(&flags.configure_file);
|
||||
let trimmed = configured.trim();
|
||||
if trimmed.is_empty() {
|
||||
return actual_src.join("Makefile.PL");
|
||||
}
|
||||
|
||||
let path = Path::new(trimmed);
|
||||
if path.is_absolute() {
|
||||
path.to_path_buf()
|
||||
} else {
|
||||
actual_src.join(path)
|
||||
}
|
||||
}
|
||||
|
||||
fn command_status_with_sh_fallback(cmd: &mut Command) -> std::io::Result<std::process::ExitStatus> {
|
||||
match crate::interrupts::command_status(cmd) {
|
||||
Ok(status) => Ok(status),
|
||||
@@ -346,6 +481,12 @@ fn has_assignment_prefix(args: &[String], name: &str) -> bool {
|
||||
})
|
||||
}
|
||||
|
||||
fn helper_source_dir() -> PathBuf {
|
||||
std::env::var(crate::builder::DEPOT_BUILD_HELPER_SOURCE_DIR_ENV)
|
||||
.map(PathBuf::from)
|
||||
.unwrap_or_else(|_| std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
Reference in New Issue
Block a user