feat: update depot version and enhance host build support
- Bump the version of the "depot" package from 0.26.1 to 0.27.0 in Cargo.toml and Cargo.lock. - Modify meson.build, autotools.rs, cmake.rs, custom.rs, makefile.rs, and other builder files to include a new parameter for host build directory. - Implement logic to handle host builds across various build systems (Autotools, CMake, Meson). - Add tests to ensure that environment variables for host build directories are correctly expanded. - Introduce new flags in PackageSpec to control host build behavior.
This commit is contained in:
Generated
+1
-1
@@ -418,7 +418,7 @@ checksum = "807800ff3288b621186fe0a8f3392c4652068257302709c24efd918c3dffcdc2"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "depot"
|
name = "depot"
|
||||||
version = "0.26.1"
|
version = "0.27.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"ar",
|
"ar",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "depot"
|
name = "depot"
|
||||||
version = "0.26.1"
|
version = "0.27.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[lints.rust]
|
[lints.rust]
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
project(
|
project(
|
||||||
'depot',
|
'depot',
|
||||||
version: '0.26.1',
|
version: '0.27.0',
|
||||||
meson_version: '>=0.60.0',
|
meson_version: '>=0.60.0',
|
||||||
default_options: ['buildtype=release'],
|
default_options: ['buildtype=release'],
|
||||||
)
|
)
|
||||||
|
|||||||
+146
-1
@@ -1,5 +1,6 @@
|
|||||||
//! GNU Autotools build system (configure && make && make install)
|
//! GNU Autotools build system (configure && make && make install)
|
||||||
|
|
||||||
|
use crate::builder::state::{BuildStep, StateTracker};
|
||||||
use crate::cross::CrossConfig;
|
use crate::cross::CrossConfig;
|
||||||
use crate::fakeroot;
|
use crate::fakeroot;
|
||||||
use crate::package::PackageSpec;
|
use crate::package::PackageSpec;
|
||||||
@@ -15,6 +16,7 @@ pub fn build(
|
|||||||
destdir: &Path,
|
destdir: &Path,
|
||||||
cross: Option<&CrossConfig>,
|
cross: Option<&CrossConfig>,
|
||||||
export_compiler_flags: bool,
|
export_compiler_flags: bool,
|
||||||
|
host_build_dir: Option<&Path>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let flags = &spec.build.flags;
|
let flags = &spec.build.flags;
|
||||||
let make_exec = resolve_make_exec(&flags.make_exec);
|
let make_exec = resolve_make_exec(&flags.make_exec);
|
||||||
@@ -26,6 +28,13 @@ pub fn build(
|
|||||||
|
|
||||||
// Build environment variables
|
// Build environment variables
|
||||||
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);
|
||||||
|
if let Some(host_dir) = host_build_dir {
|
||||||
|
crate::builder::set_env_var(
|
||||||
|
&mut env_vars,
|
||||||
|
crate::builder::DEPOT_BUILD_HOST_DIR_ENV,
|
||||||
|
host_dir.to_string_lossy().into_owned(),
|
||||||
|
);
|
||||||
|
}
|
||||||
let cc = if let Some(cc_cfg) = cross {
|
let cc = if let Some(cc_cfg) = cross {
|
||||||
cc_cfg.cc.clone()
|
cc_cfg.cc.clone()
|
||||||
} else {
|
} else {
|
||||||
@@ -44,7 +53,6 @@ pub fn build(
|
|||||||
crate::builder::set_env_var(&mut env_vars, "CFLAGS", expanded);
|
crate::builder::set_env_var(&mut env_vars, "CFLAGS", expanded);
|
||||||
}
|
}
|
||||||
|
|
||||||
use crate::builder::state::{BuildStep, StateTracker};
|
|
||||||
let mut state = StateTracker::new_with_namespace(
|
let mut state = StateTracker::new_with_namespace(
|
||||||
&actual_src,
|
&actual_src,
|
||||||
spec.build.flags.lib32_variant.then_some("lib32"),
|
spec.build.flags.lib32_variant.then_some("lib32"),
|
||||||
@@ -385,6 +393,104 @@ pub fn build(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn ensure_host_build(
|
||||||
|
spec: &PackageSpec,
|
||||||
|
src_dir: &Path,
|
||||||
|
export_compiler_flags: bool,
|
||||||
|
) -> Result<PathBuf> {
|
||||||
|
let host_spec = crate::builder::host_build_spec(spec);
|
||||||
|
let flags = &host_spec.build.flags;
|
||||||
|
let make_exec = resolve_make_exec(&flags.make_exec);
|
||||||
|
let export_compiler_flags = export_compiler_flags && !flags.no_flags;
|
||||||
|
let actual_src = resolve_actual_src(&host_spec, src_dir)?;
|
||||||
|
let build_dir = crate::builder::host_build_dir_for_source(&actual_src, flags);
|
||||||
|
fs::create_dir_all(&build_dir)?;
|
||||||
|
|
||||||
|
let mut env_vars =
|
||||||
|
crate::builder::standard_build_env(&host_spec, None, true, export_compiler_flags);
|
||||||
|
if export_compiler_flags
|
||||||
|
&& let Some(cflags_str) = env_vars
|
||||||
|
.iter()
|
||||||
|
.find(|(key, _)| key == "CFLAGS")
|
||||||
|
.map(|(_, value)| value.clone())
|
||||||
|
&& !cflags_str.trim().is_empty()
|
||||||
|
{
|
||||||
|
let expanded = expand_shell_commands(&cflags_str, &flags.cc)?;
|
||||||
|
crate::builder::set_env_var(&mut env_vars, "CFLAGS", expanded);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut state = StateTracker::new_with_namespace(&actual_src, Some("host"))?;
|
||||||
|
|
||||||
|
if !state.is_done(BuildStep::Configured) {
|
||||||
|
crate::log_info!(
|
||||||
|
"Running host-side configure build in {}...",
|
||||||
|
build_dir.display()
|
||||||
|
);
|
||||||
|
let configure_path = resolve_configure_path(&host_spec, &actual_src);
|
||||||
|
let mut configure_cmd = Command::new(&configure_path);
|
||||||
|
configure_cmd.current_dir(&build_dir);
|
||||||
|
|
||||||
|
crate::builder::prepare_tool_command(&mut configure_cmd, &env_vars);
|
||||||
|
|
||||||
|
let help_text = configure_help_text(&configure_path, &build_dir, &env_vars);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
for arg in &flags.configure {
|
||||||
|
let expanded = expand_configure_arg(&host_spec, arg, &env_vars);
|
||||||
|
configure_cmd.arg(expanded);
|
||||||
|
}
|
||||||
|
|
||||||
|
let status = crate::interrupts::command_status(&mut configure_cmd)
|
||||||
|
.with_context(|| format!("Failed to run host configure in {}", build_dir.display()))?;
|
||||||
|
|
||||||
|
if !status.success() {
|
||||||
|
anyhow::bail!("host configure failed with status: {}", status);
|
||||||
|
}
|
||||||
|
state.mark_done(BuildStep::Configured)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !state.is_done(BuildStep::PostCompileDone) {
|
||||||
|
let build_targets = phase_targets(&flags.make_target, &flags.make_targets, None);
|
||||||
|
let make_dirs = resolve_make_dirs(&build_dir, &flags.make_dirs, "build.flags.make_dirs")?;
|
||||||
|
for make_dir in make_dirs {
|
||||||
|
let mut make_cmd = Command::new(make_exec);
|
||||||
|
make_cmd.current_dir(&make_dir);
|
||||||
|
make_cmd.arg("-j").arg(num_cpus().to_string());
|
||||||
|
add_make_variable_overrides_if_supported(
|
||||||
|
&mut make_cmd,
|
||||||
|
make_exec,
|
||||||
|
&flags.make_vars,
|
||||||
|
"build",
|
||||||
|
)?;
|
||||||
|
for target in &build_targets {
|
||||||
|
make_cmd.arg(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
crate::builder::prepare_tool_command(&mut make_cmd, &env_vars);
|
||||||
|
|
||||||
|
let status = crate::interrupts::command_status(&mut make_cmd).with_context(|| {
|
||||||
|
format!("Failed to run host {} in {}", make_exec, make_dir.display())
|
||||||
|
})?;
|
||||||
|
|
||||||
|
if !status.success() {
|
||||||
|
anyhow::bail!(
|
||||||
|
"host {} failed with status: {} (dir: {})",
|
||||||
|
make_exec,
|
||||||
|
status,
|
||||||
|
make_dir.display()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
state.mark_done(BuildStep::PostCompileDone)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
fs::canonicalize(&build_dir)
|
||||||
|
.with_context(|| format!("Failed to resolve host build dir: {}", build_dir.display()))
|
||||||
|
}
|
||||||
|
|
||||||
fn num_cpus() -> usize {
|
fn num_cpus() -> usize {
|
||||||
std::thread::available_parallelism()
|
std::thread::available_parallelism()
|
||||||
.map(|n| n.get())
|
.map(|n| n.get())
|
||||||
@@ -851,6 +957,45 @@ mod tests {
|
|||||||
assert_eq!(expanded, "--program-prefix=foo-1.2.3-aarch64-");
|
assert_eq!(expanded, "--program-prefix=foo-1.2.3-aarch64-");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_expand_configure_arg_expands_host_build_dir_env() {
|
||||||
|
let spec = PackageSpec {
|
||||||
|
package: PackageInfo {
|
||||||
|
name: "foo".into(),
|
||||||
|
real_name: None,
|
||||||
|
version: "1.2.3".into(),
|
||||||
|
revision: 1,
|
||||||
|
description: "d".into(),
|
||||||
|
homepage: "h".into(),
|
||||||
|
abi_breaking: false,
|
||||||
|
license: vec!["MIT".into()],
|
||||||
|
},
|
||||||
|
packages: Vec::new(),
|
||||||
|
alternatives: Default::default(),
|
||||||
|
manual_sources: Vec::new(),
|
||||||
|
source: Vec::new(),
|
||||||
|
build: Build {
|
||||||
|
build_type: BuildType::Autotools,
|
||||||
|
flags: BuildFlags::default(),
|
||||||
|
},
|
||||||
|
dependencies: Dependencies::default(),
|
||||||
|
package_alternatives: Default::default(),
|
||||||
|
package_dependencies: Default::default(),
|
||||||
|
spec_dir: PathBuf::from("."),
|
||||||
|
};
|
||||||
|
|
||||||
|
let envs = vec![(
|
||||||
|
crate::builder::DEPOT_BUILD_HOST_DIR_ENV.to_string(),
|
||||||
|
"/tmp/build-host".to_string(),
|
||||||
|
)];
|
||||||
|
let expanded = expand_configure_arg(
|
||||||
|
&spec,
|
||||||
|
"--with-build-tools=$DEPOT_BUILD_HOST_DIR/tools",
|
||||||
|
&envs,
|
||||||
|
);
|
||||||
|
assert_eq!(expanded, "--with-build-tools=/tmp/build-host/tools");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_num_cpus_at_least_one() {
|
fn test_num_cpus_at_least_one() {
|
||||||
let n = num_cpus();
|
let n = num_cpus();
|
||||||
|
|||||||
+2
-1
@@ -17,6 +17,7 @@ pub fn build(
|
|||||||
destdir: &Path,
|
destdir: &Path,
|
||||||
_cross: Option<&CrossConfig>,
|
_cross: Option<&CrossConfig>,
|
||||||
_export_compiler_flags: bool,
|
_export_compiler_flags: bool,
|
||||||
|
_host_build_dir: Option<&Path>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
crate::log_info!(
|
crate::log_info!(
|
||||||
"Binary install: copying files from {} to {} (pkg type={})",
|
"Binary install: copying files from {} to {} (pkg type={})",
|
||||||
@@ -114,7 +115,7 @@ mod tests {
|
|||||||
unix_fs::symlink(&target, src.join("usr/lib/libdummy.so.link"))?;
|
unix_fs::symlink(&target, src.join("usr/lib/libdummy.so.link"))?;
|
||||||
|
|
||||||
let spec = mk_spec("bin-test", "1.0");
|
let spec = mk_spec("bin-test", "1.0");
|
||||||
build(&spec, src, dest, None, true)?;
|
build(&spec, src, dest, None, true, None)?;
|
||||||
|
|
||||||
// Check copied file
|
// Check copied file
|
||||||
assert!(dest.join("usr/bin/hello").exists());
|
assert!(dest.join("usr/bin/hello").exists());
|
||||||
|
|||||||
+111
-3
@@ -1,11 +1,12 @@
|
|||||||
//! CMake build system
|
//! CMake build system
|
||||||
|
|
||||||
|
use crate::builder::state::{BuildStep, StateTracker};
|
||||||
use crate::cross::CrossConfig;
|
use crate::cross::CrossConfig;
|
||||||
use crate::fakeroot;
|
use crate::fakeroot;
|
||||||
use crate::package::PackageSpec;
|
use crate::package::PackageSpec;
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::Path;
|
use std::path::{Path, PathBuf};
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
pub fn build(
|
pub fn build(
|
||||||
@@ -14,6 +15,7 @@ pub fn build(
|
|||||||
destdir: &Path,
|
destdir: &Path,
|
||||||
cross: Option<&CrossConfig>,
|
cross: Option<&CrossConfig>,
|
||||||
export_compiler_flags: bool,
|
export_compiler_flags: bool,
|
||||||
|
host_build_dir: Option<&Path>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let flags = &spec.build.flags;
|
let flags = &spec.build.flags;
|
||||||
let make_exec_override = flags.make_exec.trim();
|
let make_exec_override = flags.make_exec.trim();
|
||||||
@@ -32,7 +34,14 @@ pub fn build(
|
|||||||
fs::create_dir_all(destdir)?;
|
fs::create_dir_all(destdir)?;
|
||||||
|
|
||||||
// Environment variables
|
// Environment variables
|
||||||
let 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);
|
||||||
|
if let Some(host_dir) = host_build_dir {
|
||||||
|
crate::builder::set_env_var(
|
||||||
|
&mut env_vars,
|
||||||
|
crate::builder::DEPOT_BUILD_HOST_DIR_ENV,
|
||||||
|
host_dir.to_string_lossy().into_owned(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Extract prefix from configure flags (cmake-style -DCMAKE_INSTALL_PREFIX=)
|
// Extract prefix from configure flags (cmake-style -DCMAKE_INSTALL_PREFIX=)
|
||||||
let prefix = cmake_cache_entry_value(&flags.configure, "CMAKE_INSTALL_PREFIX")
|
let prefix = cmake_cache_entry_value(&flags.configure, "CMAKE_INSTALL_PREFIX")
|
||||||
@@ -45,7 +54,6 @@ pub fn build(
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::builder::state::{BuildStep, StateTracker};
|
|
||||||
let mut state = StateTracker::new_with_namespace(
|
let mut state = StateTracker::new_with_namespace(
|
||||||
&actual_src,
|
&actual_src,
|
||||||
spec.build.flags.lib32_variant.then_some("lib32"),
|
spec.build.flags.lib32_variant.then_some("lib32"),
|
||||||
@@ -257,6 +265,96 @@ pub fn build(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn ensure_host_build(
|
||||||
|
spec: &PackageSpec,
|
||||||
|
src_dir: &Path,
|
||||||
|
export_compiler_flags: bool,
|
||||||
|
) -> Result<PathBuf> {
|
||||||
|
let host_spec = crate::builder::host_build_spec(spec);
|
||||||
|
let flags = &host_spec.build.flags;
|
||||||
|
|
||||||
|
let actual_src = resolve_actual_src(&host_spec, src_dir)?;
|
||||||
|
let build_dir = crate::builder::host_build_dir_for_source(&actual_src, flags);
|
||||||
|
|
||||||
|
fs::create_dir_all(&build_dir)?;
|
||||||
|
|
||||||
|
let env_vars =
|
||||||
|
crate::builder::standard_build_env(&host_spec, None, true, export_compiler_flags);
|
||||||
|
let prefix = cmake_cache_entry_value(&flags.configure, "CMAKE_INSTALL_PREFIX")
|
||||||
|
.unwrap_or(flags.prefix.as_str());
|
||||||
|
|
||||||
|
let mut state = StateTracker::new_with_namespace(&actual_src, Some("host"))?;
|
||||||
|
|
||||||
|
if !state.is_done(BuildStep::Configured) {
|
||||||
|
crate::log_info!(
|
||||||
|
"Running host-side cmake configure in {}...",
|
||||||
|
build_dir.display()
|
||||||
|
);
|
||||||
|
let mut cmake_cmd = Command::new("cmake");
|
||||||
|
cmake_cmd.current_dir(&build_dir);
|
||||||
|
cmake_cmd.arg("-S").arg(&actual_src);
|
||||||
|
cmake_cmd.arg("-B").arg(&build_dir);
|
||||||
|
cmake_cmd.arg(format!("-DCMAKE_INSTALL_PREFIX={}", prefix));
|
||||||
|
cmake_cmd.arg("-DCMAKE_BUILD_TYPE=Release");
|
||||||
|
for arg in cmake_install_dir_args(flags) {
|
||||||
|
cmake_cmd.arg(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
let expanded = expand_with_envs(flag, &env_vars);
|
||||||
|
cmake_cmd.arg(&expanded);
|
||||||
|
}
|
||||||
|
|
||||||
|
crate::builder::prepare_tool_command(&mut cmake_cmd, &env_vars);
|
||||||
|
|
||||||
|
let status = crate::interrupts::command_status(&mut cmake_cmd)
|
||||||
|
.context("Failed to run host cmake")?;
|
||||||
|
if !status.success() {
|
||||||
|
anyhow::bail!("host cmake configure failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
state.mark_done(BuildStep::Configured)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !state.is_done(BuildStep::PostCompileDone) {
|
||||||
|
let build_targets = phase_targets(&flags.make_target, &flags.make_targets);
|
||||||
|
let mut build_cmd = Command::new("cmake");
|
||||||
|
build_cmd.arg("--build").arg(&build_dir);
|
||||||
|
build_cmd.arg("-j").arg(num_cpus().to_string());
|
||||||
|
if !build_targets.is_empty() {
|
||||||
|
build_cmd.arg("--target");
|
||||||
|
for target in &build_targets {
|
||||||
|
build_cmd.arg(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
crate::builder::prepare_tool_command(&mut build_cmd, &env_vars);
|
||||||
|
|
||||||
|
let status = crate::interrupts::command_status(&mut build_cmd)
|
||||||
|
.with_context(|| format!("Failed to run host cmake build for {}", spec.package.name))?;
|
||||||
|
if !status.success() {
|
||||||
|
anyhow::bail!("host cmake build failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
state.mark_done(BuildStep::PostCompileDone)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
fs::canonicalize(&build_dir)
|
||||||
|
.with_context(|| format!("Failed to resolve host build dir: {}", build_dir.display()))
|
||||||
|
}
|
||||||
|
|
||||||
/// Expand environment variables in a string (e.g., $DEPOT_SYSROOT)
|
/// Expand environment variables in a string (e.g., $DEPOT_SYSROOT)
|
||||||
fn expand_env_vars(input: &str) -> String {
|
fn expand_env_vars(input: &str) -> String {
|
||||||
let mut result = input.to_string();
|
let mut result = input.to_string();
|
||||||
@@ -513,6 +611,16 @@ mod tests {
|
|||||||
// $HOME should be expanded from process env (may be present)
|
// $HOME should be expanded from process env (may be present)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_expand_with_envs_expands_host_build_dir() {
|
||||||
|
let envs = vec![(
|
||||||
|
crate::builder::DEPOT_BUILD_HOST_DIR_ENV.to_string(),
|
||||||
|
"/tmp/build-host".to_string(),
|
||||||
|
)];
|
||||||
|
let out = expand_with_envs("-DTOOLS_DIR=$DEPOT_BUILD_HOST_DIR/bin", &envs);
|
||||||
|
assert_eq!(out, "-DTOOLS_DIR=/tmp/build-host/bin");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_num_cpus_at_least_one() {
|
fn test_num_cpus_at_least_one() {
|
||||||
let n = num_cpus();
|
let n = num_cpus();
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ pub fn build(
|
|||||||
destdir: &Path,
|
destdir: &Path,
|
||||||
cross: Option<&CrossConfig>,
|
cross: Option<&CrossConfig>,
|
||||||
export_compiler_flags: bool,
|
export_compiler_flags: bool,
|
||||||
|
_host_build_dir: Option<&Path>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let flags = &spec.build.flags;
|
let flags = &spec.build.flags;
|
||||||
let build_dir = if let Some(dir) = &flags.build_dir {
|
let build_dir = if let Some(dir) = &flags.build_dir {
|
||||||
@@ -330,7 +331,7 @@ mod tests {
|
|||||||
|
|
||||||
let spec = mk_spec("custom-no-build", "1.0");
|
let spec = mk_spec("custom-no-build", "1.0");
|
||||||
|
|
||||||
let res = build(&spec, tmp_src.path(), tmp_dest.path(), None, true);
|
let res = build(&spec, tmp_src.path(), tmp_dest.path(), None, true, None);
|
||||||
assert!(res.is_err());
|
assert!(res.is_err());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -356,7 +357,7 @@ mod tests {
|
|||||||
spec.spec_dir = spec_dir.path().to_path_buf();
|
spec.spec_dir = spec_dir.path().to_path_buf();
|
||||||
|
|
||||||
// src_dir is empty; build() should copy build.sh from spec_dir and run it (no-op)
|
// src_dir is empty; build() should copy build.sh from spec_dir and run it (no-op)
|
||||||
build(&spec, tmp_src.path(), tmp_dest.path(), None, true)?;
|
build(&spec, tmp_src.path(), tmp_dest.path(), None, true, None)?;
|
||||||
// If we reached here, build() succeeded and build.sh was copied into src
|
// If we reached here, build() succeeded and build.sh was copied into src
|
||||||
assert!(tmp_src.path().join("build.sh").exists());
|
assert!(tmp_src.path().join("build.sh").exists());
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -404,7 +405,7 @@ depot_install_dev_pkg() {
|
|||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
});
|
});
|
||||||
|
|
||||||
build(&spec, tmp_src.path(), tmp_dest.path(), None, true)?;
|
build(&spec, tmp_src.path(), tmp_dest.path(), None, true, None)?;
|
||||||
|
|
||||||
assert!(tmp_dest.path().join("usr/share/primary.txt").exists());
|
assert!(tmp_dest.path().join("usr/share/primary.txt").exists());
|
||||||
assert!(
|
assert!(
|
||||||
@@ -454,7 +455,7 @@ depot_install() {
|
|||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
});
|
});
|
||||||
|
|
||||||
let err = build(&spec, tmp_src.path(), tmp_dest.path(), None, true)
|
let err = build(&spec, tmp_src.path(), tmp_dest.path(), None, true, None)
|
||||||
.expect_err("missing per-output install handler should fail");
|
.expect_err("missing per-output install handler should fail");
|
||||||
assert!(err.to_string().contains("Custom build script failed"));
|
assert!(err.to_string().contains("Custom build script failed"));
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -482,7 +483,7 @@ exit 0
|
|||||||
}
|
}
|
||||||
|
|
||||||
let spec = mk_spec("custom-fail-fast", "1.0");
|
let spec = mk_spec("custom-fail-fast", "1.0");
|
||||||
let err = build(&spec, tmp_src.path(), tmp_dest.path(), None, true)
|
let err = build(&spec, tmp_src.path(), tmp_dest.path(), None, true, None)
|
||||||
.expect_err("non-function custom scripts should fail when a command fails");
|
.expect_err("non-function custom scripts should fail when a command fails");
|
||||||
assert!(err.to_string().contains("Custom build script failed"));
|
assert!(err.to_string().contains("Custom build script failed"));
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -539,7 +540,7 @@ exec "$@"
|
|||||||
let mut spec = mk_spec("custom-lib32", "1.0");
|
let mut spec = mk_spec("custom-lib32", "1.0");
|
||||||
spec.build.flags.lib32_variant = true;
|
spec.build.flags.lib32_variant = true;
|
||||||
|
|
||||||
build(&spec, tmp_src.path(), tmp_dest.path(), None, true)?;
|
build(&spec, tmp_src.path(), tmp_dest.path(), None, true, None)?;
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
std::fs::read_to_string(tmp_dest.path().join("usr/lib32/libfoo.so.1"))?,
|
std::fs::read_to_string(tmp_dest.path().join("usr/lib32/libfoo.so.1"))?,
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ pub fn build(
|
|||||||
destdir: &Path,
|
destdir: &Path,
|
||||||
cross: Option<&CrossConfig>,
|
cross: Option<&CrossConfig>,
|
||||||
export_compiler_flags: bool,
|
export_compiler_flags: bool,
|
||||||
|
_host_build_dir: Option<&Path>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let mut state = StateTracker::new_with_namespace(
|
let mut state = StateTracker::new_with_namespace(
|
||||||
src_dir,
|
src_dir,
|
||||||
@@ -217,7 +218,7 @@ exec "$@"
|
|||||||
"cp built.txt $DESTDIR/usr/bin/installed.txt".into(),
|
"cp built.txt $DESTDIR/usr/bin/installed.txt".into(),
|
||||||
];
|
];
|
||||||
|
|
||||||
build(&spec, src_path, dest_path, None, true)?;
|
build(&spec, src_path, dest_path, None, true, None)?;
|
||||||
|
|
||||||
// Verify build step
|
// Verify build step
|
||||||
let built_file = src_path.join("built.txt");
|
let built_file = src_path.join("built.txt");
|
||||||
@@ -271,7 +272,7 @@ exec "$@"
|
|||||||
"printf 'bin' > \"$DESTDIR/usr/bin/foo\"".into(),
|
"printf 'bin' > \"$DESTDIR/usr/bin/foo\"".into(),
|
||||||
];
|
];
|
||||||
|
|
||||||
build(&spec, src_path, dest_path, None, true)?;
|
build(&spec, src_path, dest_path, None, true, None)?;
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
fs::read_to_string(dest_path.join("usr/lib32/libfoo.so.1"))?,
|
fs::read_to_string(dest_path.join("usr/lib32/libfoo.so.1"))?,
|
||||||
|
|||||||
+88
-2
@@ -1,5 +1,6 @@
|
|||||||
//! Meson build system
|
//! Meson build system
|
||||||
|
|
||||||
|
use crate::builder::state::{BuildStep, StateTracker};
|
||||||
use crate::cross::CrossConfig;
|
use crate::cross::CrossConfig;
|
||||||
use crate::fakeroot;
|
use crate::fakeroot;
|
||||||
use crate::package::PackageSpec;
|
use crate::package::PackageSpec;
|
||||||
@@ -14,6 +15,7 @@ pub fn build(
|
|||||||
destdir: &Path,
|
destdir: &Path,
|
||||||
cross: Option<&CrossConfig>,
|
cross: Option<&CrossConfig>,
|
||||||
export_compiler_flags: bool,
|
export_compiler_flags: bool,
|
||||||
|
host_build_dir: Option<&Path>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let flags = &spec.build.flags;
|
let flags = &spec.build.flags;
|
||||||
|
|
||||||
@@ -27,7 +29,14 @@ pub fn build(
|
|||||||
fs::create_dir_all(destdir)?;
|
fs::create_dir_all(destdir)?;
|
||||||
|
|
||||||
// Environment variables
|
// Environment variables
|
||||||
let 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);
|
||||||
|
if let Some(host_dir) = host_build_dir {
|
||||||
|
crate::builder::set_env_var(
|
||||||
|
&mut env_vars,
|
||||||
|
crate::builder::DEPOT_BUILD_HOST_DIR_ENV,
|
||||||
|
host_dir.to_string_lossy().into_owned(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Generate cross file if cross-compiling, or when the lib32 variant needs
|
// Generate cross file if cross-compiling, or when the lib32 variant needs
|
||||||
// Meson to treat the build as x86 instead of the native x86_64 host.
|
// Meson to treat the build as x86 instead of the native x86_64 host.
|
||||||
@@ -39,7 +48,6 @@ pub fn build(
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::builder::state::{BuildStep, StateTracker};
|
|
||||||
let mut state = StateTracker::new_with_namespace(
|
let mut state = StateTracker::new_with_namespace(
|
||||||
&actual_src,
|
&actual_src,
|
||||||
spec.build.flags.lib32_variant.then_some("lib32"),
|
spec.build.flags.lib32_variant.then_some("lib32"),
|
||||||
@@ -188,6 +196,68 @@ pub fn build(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn ensure_host_build(
|
||||||
|
spec: &PackageSpec,
|
||||||
|
src_dir: &Path,
|
||||||
|
export_compiler_flags: bool,
|
||||||
|
) -> Result<PathBuf> {
|
||||||
|
let host_spec = crate::builder::host_build_spec(spec);
|
||||||
|
let flags = &host_spec.build.flags;
|
||||||
|
|
||||||
|
let actual_src = resolve_actual_src(&host_spec, src_dir)?;
|
||||||
|
let build_dir = crate::builder::host_build_dir_for_source(&actual_src, flags);
|
||||||
|
|
||||||
|
fs::create_dir_all(&build_dir)?;
|
||||||
|
|
||||||
|
let env_vars =
|
||||||
|
crate::builder::standard_build_env(&host_spec, None, true, export_compiler_flags);
|
||||||
|
let mut state = StateTracker::new_with_namespace(&actual_src, Some("host"))?;
|
||||||
|
|
||||||
|
if !state.is_done(BuildStep::Configured) {
|
||||||
|
crate::log_info!(
|
||||||
|
"Running host-side meson setup in {}...",
|
||||||
|
build_dir.display()
|
||||||
|
);
|
||||||
|
let mut meson_cmd = Command::new("meson");
|
||||||
|
meson_cmd.current_dir(&actual_src);
|
||||||
|
meson_cmd.arg("setup");
|
||||||
|
meson_cmd.arg(&build_dir);
|
||||||
|
|
||||||
|
for arg in meson_setup_args(flags, None, &env_vars) {
|
||||||
|
meson_cmd.arg(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
crate::builder::prepare_tool_command(&mut meson_cmd, &env_vars);
|
||||||
|
|
||||||
|
let status = crate::interrupts::command_status(&mut meson_cmd)
|
||||||
|
.context("Failed to run host meson setup")?;
|
||||||
|
if !status.success() {
|
||||||
|
anyhow::bail!("host meson setup failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
state.mark_done(BuildStep::Configured)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !state.is_done(BuildStep::PostCompileDone) {
|
||||||
|
let mut ninja_cmd = Command::new("ninja");
|
||||||
|
ninja_cmd.current_dir(&build_dir);
|
||||||
|
ninja_cmd.arg("-j").arg(num_cpus().to_string());
|
||||||
|
|
||||||
|
crate::builder::prepare_tool_command(&mut ninja_cmd, &env_vars);
|
||||||
|
|
||||||
|
let status = crate::interrupts::command_status(&mut ninja_cmd)
|
||||||
|
.with_context(|| format!("Failed to run host ninja for {}", spec.package.name))?;
|
||||||
|
if !status.success() {
|
||||||
|
anyhow::bail!("host ninja build failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
state.mark_done(BuildStep::PostCompileDone)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
fs::canonicalize(&build_dir)
|
||||||
|
.with_context(|| format!("Failed to resolve host build dir: {}", build_dir.display()))
|
||||||
|
}
|
||||||
|
|
||||||
fn num_cpus() -> usize {
|
fn num_cpus() -> usize {
|
||||||
std::thread::available_parallelism()
|
std::thread::available_parallelism()
|
||||||
.map(|n| n.get())
|
.map(|n| n.get())
|
||||||
@@ -485,6 +555,22 @@ mod tests {
|
|||||||
assert!(args.iter().any(|a| a == "--buildtype=release"));
|
assert!(args.iter().any(|a| a == "--buildtype=release"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_meson_setup_args_expand_host_build_dir() {
|
||||||
|
let mut flags = BuildFlags::default();
|
||||||
|
flags.configure = vec!["-Dtools_dir=$DEPOT_BUILD_HOST_DIR/bin".into()];
|
||||||
|
|
||||||
|
let args = meson_setup_args(
|
||||||
|
&flags,
|
||||||
|
None,
|
||||||
|
&[(
|
||||||
|
crate::builder::DEPOT_BUILD_HOST_DIR_ENV.to_string(),
|
||||||
|
"/tmp/build-host".to_string(),
|
||||||
|
)],
|
||||||
|
);
|
||||||
|
assert!(args.iter().any(|a| a == "-Dtools_dir=/tmp/build-host/bin"));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_meson_setup_args_include_install_dirs() {
|
fn test_meson_setup_args_include_install_dirs() {
|
||||||
let args = meson_setup_args(&BuildFlags::default(), None, &[]);
|
let args = meson_setup_args(&BuildFlags::default(), None, &[]);
|
||||||
|
|||||||
+244
-15
@@ -21,6 +21,13 @@ use std::process::{Command, Stdio};
|
|||||||
use walkdir::WalkDir;
|
use walkdir::WalkDir;
|
||||||
|
|
||||||
pub type EnvVars = Vec<(String, String)>;
|
pub type EnvVars = Vec<(String, String)>;
|
||||||
|
pub(crate) const DEPOT_BUILD_HOST_DIR_ENV: &str = "DEPOT_BUILD_HOST_DIR";
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum TargetBuildKind {
|
||||||
|
Primary,
|
||||||
|
Lib32,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub(crate) struct InstallDirs {
|
pub(crate) struct InstallDirs {
|
||||||
@@ -55,6 +62,99 @@ fn default_libdir_for_variant(lib32_variant: bool) -> &'static str {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn normalized_arch(arch: &str) -> &str {
|
||||||
|
match arch.trim() {
|
||||||
|
"amd64" => "x86_64",
|
||||||
|
"arm64" => "aarch64",
|
||||||
|
other => other,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lib32_arch_for(arch: &str) -> String {
|
||||||
|
match normalized_arch(arch) {
|
||||||
|
"x86_64" => "i686".to_string(),
|
||||||
|
other => other.to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn host_arch() -> &'static str {
|
||||||
|
normalized_arch(std::env::consts::ARCH)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn effective_target_arch(
|
||||||
|
flags: &crate::package::BuildFlags,
|
||||||
|
cross: Option<&CrossConfig>,
|
||||||
|
kind: TargetBuildKind,
|
||||||
|
) -> String {
|
||||||
|
match kind {
|
||||||
|
TargetBuildKind::Lib32 => {
|
||||||
|
if let Some(cc_cfg) = cross {
|
||||||
|
return crate::cross::target_arch_from_triple(&crate::cross::lib32_target_triple(
|
||||||
|
cc_cfg.host_triple(),
|
||||||
|
))
|
||||||
|
.to_string();
|
||||||
|
}
|
||||||
|
if !flags.chost.trim().is_empty() {
|
||||||
|
return crate::cross::target_arch_from_triple(&crate::cross::lib32_target_triple(
|
||||||
|
flags.chost.trim(),
|
||||||
|
))
|
||||||
|
.to_string();
|
||||||
|
}
|
||||||
|
let base = if flags.carch.trim().is_empty() {
|
||||||
|
host_arch()
|
||||||
|
} else {
|
||||||
|
flags.carch.trim()
|
||||||
|
};
|
||||||
|
lib32_arch_for(base)
|
||||||
|
}
|
||||||
|
TargetBuildKind::Primary => {
|
||||||
|
if let Some(cc_cfg) = cross {
|
||||||
|
return crate::cross::target_arch_from_triple(cc_cfg.host_triple()).to_string();
|
||||||
|
}
|
||||||
|
if !flags.chost.trim().is_empty() {
|
||||||
|
return crate::cross::target_arch_from_triple(flags.chost.trim()).to_string();
|
||||||
|
}
|
||||||
|
if !flags.carch.trim().is_empty() {
|
||||||
|
return flags.carch.trim().to_string();
|
||||||
|
}
|
||||||
|
host_arch().to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn target_arch_differs_from_host(
|
||||||
|
flags: &crate::package::BuildFlags,
|
||||||
|
cross: Option<&CrossConfig>,
|
||||||
|
kind: TargetBuildKind,
|
||||||
|
) -> bool {
|
||||||
|
normalized_arch(&effective_target_arch(flags, cross, kind)) != host_arch()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn default_host_build_dir_name(flags: &crate::package::BuildFlags) -> String {
|
||||||
|
match flags.build_dir.as_deref().map(str::trim) {
|
||||||
|
Some(dir) if !dir.is_empty() => format!("{}-host", dir),
|
||||||
|
_ => "build-host".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn host_build_dir_for_source(
|
||||||
|
src_root: &Path,
|
||||||
|
flags: &crate::package::BuildFlags,
|
||||||
|
) -> PathBuf {
|
||||||
|
src_root.join(default_host_build_dir_name(flags))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn host_build_spec(spec: &PackageSpec) -> PackageSpec {
|
||||||
|
let mut host_spec = spec.clone();
|
||||||
|
host_spec.build.flags.lib32_variant = false;
|
||||||
|
host_spec.build.flags.chost.clear();
|
||||||
|
host_spec.build.flags.cbuild.clear();
|
||||||
|
host_spec.build.flags.carch = host_arch().to_string();
|
||||||
|
host_spec.build.flags.host_build_dir = None;
|
||||||
|
host_spec.build.flags.build_dir = Some(default_host_build_dir_name(&spec.build.flags));
|
||||||
|
host_spec
|
||||||
|
}
|
||||||
|
|
||||||
fn configured_install_dir(value: &str, default: &str) -> String {
|
fn configured_install_dir(value: &str, default: &str) -> String {
|
||||||
let trimmed = value.trim();
|
let trimmed = value.trim();
|
||||||
if trimmed.is_empty() {
|
if trimmed.is_empty() {
|
||||||
@@ -357,8 +457,14 @@ pub fn standard_build_env(
|
|||||||
if !flags.cbuild.is_empty() {
|
if !flags.cbuild.is_empty() {
|
||||||
set_env_var(&mut env_vars, "CBUILD", flags.cbuild.clone());
|
set_env_var(&mut env_vars, "CBUILD", flags.cbuild.clone());
|
||||||
}
|
}
|
||||||
if !flags.carch.is_empty() {
|
let target_kind = if flags.lib32_variant {
|
||||||
set_env_var(&mut env_vars, "CARCH", flags.carch.clone());
|
TargetBuildKind::Lib32
|
||||||
|
} else {
|
||||||
|
TargetBuildKind::Primary
|
||||||
|
};
|
||||||
|
let effective_carch = effective_target_arch(flags, cross, target_kind);
|
||||||
|
if !effective_carch.is_empty() {
|
||||||
|
set_env_var(&mut env_vars, "CARCH", effective_carch);
|
||||||
}
|
}
|
||||||
if !flags.prefix.is_empty() {
|
if !flags.prefix.is_empty() {
|
||||||
set_env_var(&mut env_vars, "PREFIX", flags.prefix.clone());
|
set_env_var(&mut env_vars, "PREFIX", flags.prefix.clone());
|
||||||
@@ -422,6 +528,34 @@ pub fn standard_build_env(
|
|||||||
env_vars
|
env_vars
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn ensure_host_build(
|
||||||
|
spec: &PackageSpec,
|
||||||
|
src_dir: &Path,
|
||||||
|
cross: Option<&CrossConfig>,
|
||||||
|
export_compiler_flags: bool,
|
||||||
|
kind: TargetBuildKind,
|
||||||
|
) -> Result<Option<PathBuf>> {
|
||||||
|
if !spec.build.flags.host_build
|
||||||
|
|| !target_arch_differs_from_host(&spec.build.flags, cross, kind)
|
||||||
|
{
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
let host_dir = match spec.build.build_type {
|
||||||
|
BuildType::Autotools => autotools::ensure_host_build(spec, src_dir, export_compiler_flags)?,
|
||||||
|
BuildType::CMake => cmake::ensure_host_build(spec, src_dir, export_compiler_flags)?,
|
||||||
|
BuildType::Meson => meson::ensure_host_build(spec, src_dir, export_compiler_flags)?,
|
||||||
|
other => {
|
||||||
|
anyhow::bail!(
|
||||||
|
"build.flags.host_build is currently supported only for autotools/cmake/meson (got {:?})",
|
||||||
|
other
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Some(host_dir))
|
||||||
|
}
|
||||||
|
|
||||||
/// Prepare a Command with a hermetic environment and some essential variables preserved.
|
/// Prepare a Command with a hermetic environment and some essential variables preserved.
|
||||||
pub fn prepare_command(cmd: &mut Command, env_vars: &EnvVars) {
|
pub fn prepare_command(cmd: &mut Command, env_vars: &EnvVars) {
|
||||||
cmd.env_clear();
|
cmd.env_clear();
|
||||||
@@ -498,6 +632,7 @@ pub fn build(
|
|||||||
destdir: &Path,
|
destdir: &Path,
|
||||||
cross: Option<&CrossConfig>,
|
cross: Option<&CrossConfig>,
|
||||||
export_compiler_flags: bool,
|
export_compiler_flags: bool,
|
||||||
|
host_build_dir: Option<&Path>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
if let Some(cc) = cross {
|
if let Some(cc) = cross {
|
||||||
crate::log_info!(
|
crate::log_info!(
|
||||||
@@ -515,25 +650,84 @@ pub fn build(
|
|||||||
}
|
}
|
||||||
|
|
||||||
match spec.build.build_type {
|
match spec.build.build_type {
|
||||||
BuildType::Autotools => {
|
BuildType::Autotools => autotools::build(
|
||||||
autotools::build(spec, src_dir, destdir, cross, export_compiler_flags)
|
spec,
|
||||||
}
|
src_dir,
|
||||||
BuildType::CMake => cmake::build(spec, src_dir, destdir, cross, export_compiler_flags),
|
destdir,
|
||||||
BuildType::Meson => meson::build(spec, src_dir, destdir, cross, export_compiler_flags),
|
cross,
|
||||||
BuildType::Perl => perl::build(spec, src_dir, destdir, cross, export_compiler_flags),
|
export_compiler_flags,
|
||||||
BuildType::Custom => custom::build(spec, src_dir, destdir, cross, export_compiler_flags),
|
host_build_dir,
|
||||||
BuildType::Python => python::build(spec, src_dir, destdir, cross, export_compiler_flags),
|
),
|
||||||
BuildType::Rust => rust::build(spec, src_dir, destdir, cross, export_compiler_flags),
|
BuildType::CMake => cmake::build(
|
||||||
BuildType::Bin => bin::build(spec, src_dir, destdir, cross, export_compiler_flags),
|
spec,
|
||||||
|
src_dir,
|
||||||
|
destdir,
|
||||||
|
cross,
|
||||||
|
export_compiler_flags,
|
||||||
|
host_build_dir,
|
||||||
|
),
|
||||||
|
BuildType::Meson => meson::build(
|
||||||
|
spec,
|
||||||
|
src_dir,
|
||||||
|
destdir,
|
||||||
|
cross,
|
||||||
|
export_compiler_flags,
|
||||||
|
host_build_dir,
|
||||||
|
),
|
||||||
|
BuildType::Perl => perl::build(
|
||||||
|
spec,
|
||||||
|
src_dir,
|
||||||
|
destdir,
|
||||||
|
cross,
|
||||||
|
export_compiler_flags,
|
||||||
|
host_build_dir,
|
||||||
|
),
|
||||||
|
BuildType::Custom => custom::build(
|
||||||
|
spec,
|
||||||
|
src_dir,
|
||||||
|
destdir,
|
||||||
|
cross,
|
||||||
|
export_compiler_flags,
|
||||||
|
host_build_dir,
|
||||||
|
),
|
||||||
|
BuildType::Python => python::build(
|
||||||
|
spec,
|
||||||
|
src_dir,
|
||||||
|
destdir,
|
||||||
|
cross,
|
||||||
|
export_compiler_flags,
|
||||||
|
host_build_dir,
|
||||||
|
),
|
||||||
|
BuildType::Rust => rust::build(
|
||||||
|
spec,
|
||||||
|
src_dir,
|
||||||
|
destdir,
|
||||||
|
cross,
|
||||||
|
export_compiler_flags,
|
||||||
|
host_build_dir,
|
||||||
|
),
|
||||||
|
BuildType::Bin => bin::build(
|
||||||
|
spec,
|
||||||
|
src_dir,
|
||||||
|
destdir,
|
||||||
|
cross,
|
||||||
|
export_compiler_flags,
|
||||||
|
host_build_dir,
|
||||||
|
),
|
||||||
BuildType::Meta => {
|
BuildType::Meta => {
|
||||||
// Metapackages are metadata-only; create an empty staging root and let
|
// Metapackages are metadata-only; create an empty staging root and let
|
||||||
// packaging/installation metadata carry dependencies.
|
// packaging/installation metadata carry dependencies.
|
||||||
std::fs::create_dir_all(destdir)?;
|
std::fs::create_dir_all(destdir)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
BuildType::Makefile => {
|
BuildType::Makefile => makefile::build(
|
||||||
makefile::build(spec, src_dir, destdir, cross, export_compiler_flags)
|
spec,
|
||||||
}
|
src_dir,
|
||||||
|
destdir,
|
||||||
|
cross,
|
||||||
|
export_compiler_flags,
|
||||||
|
host_build_dir,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -675,6 +869,41 @@ mod tests {
|
|||||||
assert!(env.iter().any(|(k, v)| k == "CPP" && v == "clang-cpp"));
|
assert!(env.iter().any(|(k, v)| k == "CPP" && v == "clang-cpp"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_standard_build_env_exports_effective_carch_for_cross_and_lib32() {
|
||||||
|
let spec = mk_spec(Vec::new(), Vec::new());
|
||||||
|
let cross = CrossConfig {
|
||||||
|
prefix: "aarch64-linux-gnu".into(),
|
||||||
|
cc: "aarch64-linux-gnu-gcc".into(),
|
||||||
|
cxx: "aarch64-linux-gnu-g++".into(),
|
||||||
|
ar: "aarch64-linux-gnu-ar".into(),
|
||||||
|
ranlib: "aarch64-linux-gnu-ranlib".into(),
|
||||||
|
strip: "aarch64-linux-gnu-strip".into(),
|
||||||
|
ld: "aarch64-linux-gnu-ld".into(),
|
||||||
|
nm: "aarch64-linux-gnu-nm".into(),
|
||||||
|
objcopy: "aarch64-linux-gnu-objcopy".into(),
|
||||||
|
objdump: "aarch64-linux-gnu-objdump".into(),
|
||||||
|
readelf: "aarch64-linux-gnu-readelf".into(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let cross_env = standard_build_env(&spec, Some(&cross), true, true);
|
||||||
|
assert!(
|
||||||
|
cross_env
|
||||||
|
.iter()
|
||||||
|
.any(|(k, v)| k == "CARCH" && v == "aarch64"),
|
||||||
|
"expected cross builds to export target CARCH"
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut lib32_spec = spec.clone();
|
||||||
|
lib32_spec.build.flags.lib32_variant = true;
|
||||||
|
lib32_spec.build.flags.carch = "x86_64".into();
|
||||||
|
let lib32_env = standard_build_env(&lib32_spec, None, true, true);
|
||||||
|
assert!(
|
||||||
|
lib32_env.iter().any(|(k, v)| k == "CARCH" && v == "i686"),
|
||||||
|
"expected lib32 builds to export i686 CARCH"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_standard_build_env_respects_export_compiler_flags_toggle() {
|
fn test_standard_build_env_respects_export_compiler_flags_toggle() {
|
||||||
let mut spec = mk_spec(vec!["-O2"], vec!["-Wl,--as-needed"]);
|
let mut spec = mk_spec(vec!["-O2"], vec!["-Wl,--as-needed"]);
|
||||||
|
|||||||
+3
-2
@@ -17,6 +17,7 @@ pub fn build(
|
|||||||
destdir: &Path,
|
destdir: &Path,
|
||||||
cross: Option<&CrossConfig>,
|
cross: Option<&CrossConfig>,
|
||||||
export_compiler_flags: bool,
|
export_compiler_flags: bool,
|
||||||
|
_host_build_dir: Option<&Path>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let flags = &spec.build.flags;
|
let flags = &spec.build.flags;
|
||||||
if flags.build_dir.is_some() {
|
if flags.build_dir.is_some() {
|
||||||
@@ -459,7 +460,7 @@ exec "$@"
|
|||||||
spec.build.flags.make_exec = tools_path.join("make").to_string_lossy().into_owned();
|
spec.build.flags.make_exec = tools_path.join("make").to_string_lossy().into_owned();
|
||||||
spec.build.flags.configure = vec!["CCFLAGS=-fPIC".into()];
|
spec.build.flags.configure = vec!["CCFLAGS=-fPIC".into()];
|
||||||
|
|
||||||
let build_result = build(&spec, src_path, dest_path, None, true);
|
let build_result = build(&spec, src_path, dest_path, None, true, None);
|
||||||
|
|
||||||
build_result?;
|
build_result?;
|
||||||
|
|
||||||
@@ -490,7 +491,7 @@ exec "$@"
|
|||||||
let mut spec = mk_spec("perl-test", "1.0");
|
let mut spec = mk_spec("perl-test", "1.0");
|
||||||
spec.build.flags.build_dir = Some("build".into());
|
spec.build.flags.build_dir = Some("build".into());
|
||||||
|
|
||||||
let err = build(&spec, tmp_src.path(), tmp_dest.path(), None, true)
|
let err = build(&spec, tmp_src.path(), tmp_dest.path(), None, true, None)
|
||||||
.expect_err("perl build should reject build_dir");
|
.expect_err("perl build should reject build_dir");
|
||||||
assert!(
|
assert!(
|
||||||
err.to_string()
|
err.to_string()
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ pub fn build(
|
|||||||
destdir: &Path,
|
destdir: &Path,
|
||||||
cross: Option<&CrossConfig>,
|
cross: Option<&CrossConfig>,
|
||||||
export_compiler_flags: bool,
|
export_compiler_flags: bool,
|
||||||
|
_host_build_dir: Option<&Path>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let flags = &spec.build.flags;
|
let flags = &spec.build.flags;
|
||||||
let actual_src = resolve_actual_src(spec, src_dir)?;
|
let actual_src = resolve_actual_src(spec, src_dir)?;
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ pub fn build(
|
|||||||
destdir: &Path,
|
destdir: &Path,
|
||||||
cross: Option<&CrossConfig>,
|
cross: Option<&CrossConfig>,
|
||||||
export_compiler_flags: bool,
|
export_compiler_flags: bool,
|
||||||
|
_host_build_dir: Option<&Path>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let flags = &spec.build.flags;
|
let flags = &spec.build.flags;
|
||||||
|
|
||||||
|
|||||||
+35
-1
@@ -1182,9 +1182,19 @@ fn build_lib32_companion_package(
|
|||||||
}
|
}
|
||||||
|
|
||||||
crate::log_info!("Running separate lib32 build pass...");
|
crate::log_info!("Running separate lib32 build pass...");
|
||||||
|
let host_build_dir = builder::ensure_host_build(
|
||||||
|
pkg_spec,
|
||||||
|
src_dir,
|
||||||
|
cross_config,
|
||||||
|
export_compiler_flags,
|
||||||
|
builder::TargetBuildKind::Lib32,
|
||||||
|
)?;
|
||||||
let mut lib32_input = pkg_spec.clone();
|
let mut lib32_input = pkg_spec.clone();
|
||||||
lib32_input.build.flags.build_32 = true;
|
lib32_input.build.flags.build_32 = true;
|
||||||
let lib32_build_spec = make_lib32_build_spec(&lib32_input);
|
let mut lib32_build_spec = make_lib32_build_spec(&lib32_input);
|
||||||
|
if let Some(host_dir) = host_build_dir.as_ref() {
|
||||||
|
lib32_build_spec.build.flags.host_build_dir = Some(host_dir.to_string_lossy().into_owned());
|
||||||
|
}
|
||||||
let lib32_pkg_spec = make_lib32_package_spec(pkg_spec);
|
let lib32_pkg_spec = make_lib32_package_spec(pkg_spec);
|
||||||
let lib32_destdir = config
|
let lib32_destdir = config
|
||||||
.build_dir
|
.build_dir
|
||||||
@@ -1208,6 +1218,7 @@ fn build_lib32_companion_package(
|
|||||||
&lib32_destdir,
|
&lib32_destdir,
|
||||||
cross_config,
|
cross_config,
|
||||||
export_compiler_flags,
|
export_compiler_flags,
|
||||||
|
host_build_dir.as_deref(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let lib32_src = lib32_destdir.join("usr/lib32");
|
let lib32_src = lib32_destdir.join("usr/lib32");
|
||||||
@@ -4545,6 +4556,16 @@ fn run_direct_install_request(
|
|||||||
// 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());
|
built_src_dir = Some(src_dir.clone());
|
||||||
|
let host_build_dir = builder::ensure_host_build(
|
||||||
|
&pkg_spec,
|
||||||
|
&src_dir,
|
||||||
|
cross_config.as_ref(),
|
||||||
|
!options.no_flags,
|
||||||
|
builder::TargetBuildKind::Primary,
|
||||||
|
)?;
|
||||||
|
if let Some(host_dir) = host_build_dir.as_ref() {
|
||||||
|
pkg_spec.build.flags.host_build_dir = Some(host_dir.to_string_lossy().into_owned());
|
||||||
|
}
|
||||||
|
|
||||||
// 3. Build
|
// 3. Build
|
||||||
let destdir = config
|
let destdir = config
|
||||||
@@ -4559,6 +4580,7 @@ fn run_direct_install_request(
|
|||||||
&destdir,
|
&destdir,
|
||||||
cross_config.as_ref(),
|
cross_config.as_ref(),
|
||||||
!options.no_flags,
|
!options.no_flags,
|
||||||
|
host_build_dir.as_deref(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// 3.1 Copy license files into staged tree
|
// 3.1 Copy license files into staged tree
|
||||||
@@ -5108,6 +5130,17 @@ pub fn run(cli: Cli) -> Result<()> {
|
|||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|p| cross::CrossConfig::from_prefix(p))
|
.map(|p| cross::CrossConfig::from_prefix(p))
|
||||||
.transpose()?;
|
.transpose()?;
|
||||||
|
let host_build_dir = builder::ensure_host_build(
|
||||||
|
&pkg_spec,
|
||||||
|
&src_dir,
|
||||||
|
cross_config.as_ref(),
|
||||||
|
!no_flags,
|
||||||
|
builder::TargetBuildKind::Primary,
|
||||||
|
)?;
|
||||||
|
if let Some(host_dir) = host_build_dir.as_ref() {
|
||||||
|
pkg_spec.build.flags.host_build_dir =
|
||||||
|
Some(host_dir.to_string_lossy().into_owned());
|
||||||
|
}
|
||||||
if !lib32_only {
|
if !lib32_only {
|
||||||
builder::build(
|
builder::build(
|
||||||
&pkg_spec,
|
&pkg_spec,
|
||||||
@@ -5115,6 +5148,7 @@ pub fn run(cli: Cli) -> Result<()> {
|
|||||||
&destdir,
|
&destdir,
|
||||||
cross_config.as_ref(),
|
cross_config.as_ref(),
|
||||||
!no_flags,
|
!no_flags,
|
||||||
|
host_build_dir.as_deref(),
|
||||||
)?;
|
)?;
|
||||||
if let Some(watcher) = interrupt_watcher.as_ref() {
|
if let Some(watcher) = interrupt_watcher.as_ref() {
|
||||||
watcher.check()?;
|
watcher.check()?;
|
||||||
|
|||||||
@@ -865,6 +865,11 @@ impl PackageSpec {
|
|||||||
self.build.flags.lib32_only = b;
|
self.build.flags.lib32_only = b;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
"host_build" | "host-build" => {
|
||||||
|
if let Some(b) = toml_value_as_boolish(v) {
|
||||||
|
self.build.flags.host_build = b;
|
||||||
|
}
|
||||||
|
}
|
||||||
"configure_lib32" | "configure-lib32" => {
|
"configure_lib32" | "configure-lib32" => {
|
||||||
if let Some(arr) = v.as_array() {
|
if let Some(arr) = v.as_array() {
|
||||||
self.build.flags.configure_lib32 = arr
|
self.build.flags.configure_lib32 = arr
|
||||||
@@ -4126,6 +4131,14 @@ pub struct BuildFlags {
|
|||||||
deserialize_with = "deserialize_boolish"
|
deserialize_with = "deserialize_boolish"
|
||||||
)]
|
)]
|
||||||
pub lib32_only: bool,
|
pub lib32_only: bool,
|
||||||
|
/// Perform an additional native host-side helper build when the active target arch differs.
|
||||||
|
#[serde(
|
||||||
|
default,
|
||||||
|
alias = "host-build",
|
||||||
|
alias = "host_build",
|
||||||
|
deserialize_with = "deserialize_boolish"
|
||||||
|
)]
|
||||||
|
pub host_build: bool,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub configure: Vec<String>,
|
pub configure: Vec<String>,
|
||||||
/// PEP 517 config settings for Python builds (each entry is `KEY=VALUE` or `KEY`).
|
/// PEP 517 config settings for Python builds (each entry is `KEY=VALUE` or `KEY`).
|
||||||
@@ -4403,6 +4416,9 @@ pub struct BuildFlags {
|
|||||||
/// Internal runtime marker used to adjust builder behavior for the lib32 variant.
|
/// Internal runtime marker used to adjust builder behavior for the lib32 variant.
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
pub lib32_variant: bool,
|
pub lib32_variant: bool,
|
||||||
|
/// Internal runtime marker containing the absolute path to the native host helper build dir.
|
||||||
|
#[serde(skip)]
|
||||||
|
pub host_build_dir: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for BuildFlags {
|
impl Default for BuildFlags {
|
||||||
@@ -4432,6 +4448,7 @@ impl Default for BuildFlags {
|
|||||||
skip_tests: false,
|
skip_tests: false,
|
||||||
build_32: false,
|
build_32: false,
|
||||||
lib32_only: false,
|
lib32_only: false,
|
||||||
|
host_build: false,
|
||||||
configure: Vec::new(),
|
configure: Vec::new(),
|
||||||
config_settings: Vec::new(),
|
config_settings: Vec::new(),
|
||||||
configure_lib32: Vec::new(),
|
configure_lib32: Vec::new(),
|
||||||
@@ -4491,6 +4508,7 @@ impl Default for BuildFlags {
|
|||||||
build_dir: None,
|
build_dir: None,
|
||||||
binary_type: String::new(),
|
binary_type: String::new(),
|
||||||
lib32_variant: false,
|
lib32_variant: false,
|
||||||
|
host_build_dir: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user