Skip to content

feat: Extra build dependencies#5746

Open
HARSHVARANDANI wants to merge 32 commits intoprefix-dev:mainfrom
HARSHVARANDANI:feat/extra-build-dependencies
Open

feat: Extra build dependencies#5746
HARSHVARANDANI wants to merge 32 commits intoprefix-dev:mainfrom
HARSHVARANDANI:feat/extra-build-dependencies

Conversation

@HARSHVARANDANI
Copy link
Copy Markdown

@HARSHVARANDANI HARSHVARANDANI commented Mar 21, 2026

Description

This PR adds support for specifying extra build dependencies for PyPI packages via pixi.toml.

Some PyPI packages rely on build-time dependencies that are not properly declared in their build-system.requires. This can cause builds to fail when using build isolation, making environments non-reproducible without manual intervention.

This change allows users to explicitly declare missing build dependencies directly in pixi.toml, enabling reproducible environments using a single configuration file.

Example:

[extra-build-dependencies]
fused-ssim = ["torch"]

Pixi will ensure that the specified dependencies are available in the PEP 517 build environment when building the package.

Motivation

Certain PyPI packages import or require dependencies during build time but fail to declare them in their metadata.

Examples include packages that:

  • import torch during setup
  • require numpy headers to compile extensions
  • dynamically configure build extensions
  • rely on build-time tooling such as ninja, packaging, etc.

Without this feature, users must:

  • disable build isolation
  • manually preinstall dependencies
  • maintain separate environment setup steps

This reduces reproducibility and complicates workflows.

This feature brings Pixi in line with similar functionality already available in uv.

Fixes #5614

Behavior

When building a PyPI package from source:

build dependencies = build-system.requires + extra-build-dependencies

Extra dependencies are only available during the build phase and are not installed in the runtime environment unless explicitly declared in [pypi-dependencies].

How Has This Been Tested?

Integration tests confirm:

  • manifest parsing accepts [extra-build-dependencies]
  • build dependencies are injected correctly
  • build succeeds when missing build dependency is provided
  • runtime environment is unaffected
  • works with no-build-isolation
  • lockfile generation unchanged

A custom test package requiring numpy during build phase was used to validate the full pipeline.

AI Disclosure

  • This PR contains AI-generated content.
    • I have tested any AI-generated content in my PR.
    • I take responsibility for any AI-generated content in my PR.

Checklist:

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • I have added sufficient tests to cover my changes.

@HARSHVARANDANI HARSHVARANDANI changed the title feat:extra build dependencies feat: Extra build dependencies Mar 21, 2026
@HARSHVARANDANI HARSHVARANDANI force-pushed the feat/extra-build-dependencies branch 2 times, most recently from e714a86 to a6604de Compare March 22, 2026 19:18
Signed-off-by: HARSHVARANDANI <hpvarandani@gmail.com>
Signed-off-by: HARSHVARANDANI <hpvarandani@gmail.com>
Signed-off-by: HARSHVARANDANI <hpvarandani@gmail.com>
… CI since the function is no longer unused

Signed-off-by: HARSHVARANDANI <hpvarandani@gmail.com>
…accepted in a real pypi lock/update

Signed-off-by: HARSHVARANDANI <hpvarandani@gmail.com>
… requires/config/variables instead of local defaults

Signed-off-by: HARSHVARANDANI <hpvarandani@gmail.com>
…rams

Signed-off-by: HARSHVARANDANI <hpvarandani@gmail.com>
…est during both lock update context initialization paths

Signed-off-by: HARSHVARANDANI <hpvarandani@gmail.com>
… the conversion behavior

Signed-off-by: HARSHVARANDANI <hpvarandani@gmail.com>
…OML conversion

Signed-off-by: HARSHVARANDANI <hpvarandani@gmail.com>
…EP508 build requirements

Signed-off-by: HARSHVARANDANI <hpvarandani@gmail.com>
Signed-off-by: HARSHVARANDANI <hpvarandani@gmail.com>
…te dependencies

Signed-off-by: HARSHVARANDANI <hpvarandani@gmail.com>
@HARSHVARANDANI HARSHVARANDANI force-pushed the feat/extra-build-dependencies branch from a6604de to 896a854 Compare March 22, 2026 19:35
@HARSHVARANDANI
Copy link
Copy Markdown
Author

@baszalmstra Could you take a look at this when you've got time? Some feedback would be really helpful.
Thank you! 🙂

Copy link
Copy Markdown
Contributor

@tdejager tdejager left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some small changes

Comment thread crates/pixi_uv_context/src/lib.rs Outdated
Comment on lines +31 to +69
/// Convert manifest-defined extra build dependencies into uv's
/// [`ExtraBuildRequires`] structure.
///
/// Each manifest requirement is converted to a uv requirement and wrapped in an
/// [`ExtraBuildRequirement`] with `match_runtime = false` for v1 behavior.
///
/// The `workspace_root` parameter is currently unused but kept in the API to
/// preserve call-site intent and future conversion support for path-based
/// requirement forms.
pub fn convert_extra_build_dependencies(
deps: &Option<IndexMap<PypiPackageName, Vec<pep508_rs::Requirement>>>,
_workspace_root: &Path,
) -> Result<ExtraBuildRequires, pixi_uv_conversions::ConversionError> {
let mut extra_build_requires = ExtraBuildRequires::default();

for (package, specs) in deps.iter().flatten() {
let requirements = specs
.iter()
.map(|spec| {
pep508_requirement_to_uv_requirement(spec.clone()).map(|requirement| {
ExtraBuildRequirement {
requirement,
match_runtime: false,
}
})
})
.collect::<Result<Vec<_>, _>>()?;

if requirements.is_empty() {
continue;
}

let package_name = uv_normalize::PackageName::from_str(package.as_normalized().as_ref())
.expect("pypi package names in manifest should always be valid");
extra_build_requires.insert(package_name, requirements);
}

Ok(extra_build_requires)
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this can go into the pixi_uv_conversions crate.

Comment thread crates/pixi_uv_context/src/lib.rs Outdated
Comment on lines +208 to +239
mod tests {
use std::str::FromStr;

use indexmap::IndexMap;
use pixi_pypi_spec::PypiPackageName;

use super::convert_extra_build_dependencies;

#[test]
fn converts_extra_build_dependencies() {
let mut deps: IndexMap<PypiPackageName, Vec<pep508_rs::Requirement>> = IndexMap::new();
deps.insert(
PypiPackageName::from_str("fused-ssim").unwrap(),
vec![pep508_rs::Requirement::from_str("torch>=2").unwrap()],
);

let converted = convert_extra_build_dependencies(&Some(deps), std::path::Path::new("."))
.expect("conversion should succeed");

let pkg_name = uv_normalize::PackageName::from_str("fused-ssim").unwrap();
let requirements = converted.get(&pkg_name).expect("package should be present");
assert_eq!(requirements.len(), 1);
assert_eq!(requirements[0].requirement.name.as_ref(), "torch");
assert!(!requirements[0].match_runtime);
}

#[test]
fn empty_extra_build_dependencies_is_noop() {
let converted = convert_extra_build_dependencies(&None, std::path::Path::new(".")).unwrap();
assert!(converted.is_empty());
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same for this.

Copy link
Copy Markdown
Contributor

@tdejager tdejager left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also we @ruben-arts pointed me to this but we should make the extra-build-dependencies avialable under the dependency types, merge these across feature somehow and re-construct the map before doing the environment installation and solve.

@HARSHVARANDANI HARSHVARANDANI requested a review from tdejager April 1, 2026 16:45
@HARSHVARANDANI
Copy link
Copy Markdown
Author

@tdejager I have made requested changes. If you could please check for any more changes needed?

@tdejager
Copy link
Copy Markdown
Contributor

tdejager commented Apr 7, 2026

Hey, this did not make the changes we requested its still a top-level table.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Failed to install deps with no-build-isolation

2 participants