Skip to content

feat: Derive c_stdlib build variants from system requirements#6320

Open
hunger wants to merge 2 commits into
prefix-dev:mainfrom
hunger:push-zzpqursrznyw
Open

feat: Derive c_stdlib build variants from system requirements#6320
hunger wants to merge 2 commits into
prefix-dev:mainfrom
hunger:push-zzpqursrznyw

Conversation

@hunger

@hunger hunger commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Derive c_stdlib build variants from system requirements

Problem

When pixi-build builds a compiled (non-noarch) package, the C stdlib target is
selected through conda-forge's c_stdlib / c_stdlib_version build variants
(consumed by the stdlib('c') recipe function). Today users have to spell those
out by hand in [workspace.build-variants], even though pixi already knows the
target from the workspace's platforms.

Changes

Derive the variant pair from system requirements (pixi_core)

Workspace::variants now derives c_stdlib / c_stdlib_version from the
platform's declared virtual packages and fills them in only where the user
hasn't set them explicitly (an explicit [workspace.build-variants] entry
always wins):

subdir virtual package c_stdlib c_stdlib_version
osx-* __osx macosx_deployment_target the __osx version
linux-* __glibc sysroot the __glibc version

Windows is skipped (no meaningful stdlib version), and a platform with no
matching virtual package derives nothing rather than inventing a value. The
logic lives in the new crates/pixi_core/src/workspace/stdlib_variants.rs.

__musl and __cuda are noted as follow-ups (TODO(#6175)). They are not fully described
in any CEP, so whatever we do there is goiung to be incomplete.

Set MACOSX_DEPLOYMENT_TARGET on macOS (pixi_build_python)

For compiled macOS builds where the c_stdlib_version variant is present, the
python backend injects MACOSX_DEPLOYMENT_TARGET=${{ c_stdlib_version }} into
the build-script env (rendered lazily by rattler-build). It's skipped for noarch
builds, off macOS, and when the variant is absent. An explicit
MACOSX_DEPLOYMENT_TARGET in the backend config is left untouched — the derived
value only fills the gap.

Tests

  • Unit tests for derive_stdlib_variants (osx, linux, windows-skipped,
    glibc-absent, and bare-subdir defaults).
  • Unit test that an explicit build-variant overrides the derived value while an
    unset key is still filled in.
  • Unit tests for macos_deployment_target_env and two end-to-end
    generate_recipe tests (derived value wired in; user config respected).
  • New integration test test_macos_deployment_target_from_system_requirements
    plus fixture tests/data/pixi-build/system-requirements-osx-python pinning
    macos = "12.0" (deliberately different from the 13.0 osx-subdir default).
    It asserts a single compiled artifact is produced on every platform, and on
    macOS that the build script env carries MACOSX_DEPLOYMENT_TARGET=12.0.

Fixes #6175.

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.

Tools: Claude

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.
  • I have verified that changes that would impact the JSON schema have been made in schema/model.py.

hunger added 2 commits June 9, 2026 14:54
Inject conda-forge c_stdlib/c_stdlib_version build variants from a
platform's declared virtual packages (__osx, __glibc) in
Workspace::variants(), so build backends pin the minimum OS/libc target
and stop emitting wheels tagged for the host OS version (e.g.
macosx_26_0). Explicit [workspace.build-variants] entries still win;
derivation only fills absent keys.

osx-* derives macosx_deployment_target, linux-* derives sysroot;
windows and unmatched platforms are skipped. musl and __cuda are left
for a follow-up (TODO marker).

Refs: prefix-dev#6175
…ersion

rattler-build hard-codes MACOSX_DEPLOYMENT_TARGET (11.0/10.9) and ignores
the c_stdlib_version variant, so maturin/PEP 517 wheels are tagged for the
host SDK (e.g. macosx_26_0). For compiled (non-noarch) macOS builds the
python backend now injects a build-script env entry
MACOSX_DEPLOYMENT_TARGET = ${{ c_stdlib_version }}, rendered lazily by
rattler-build from the variant pixi derives off the platform's __osx
system requirement. An explicit value in the backend config wins.

Adds a cross-platform integration test (system-requirements-osx-python
fixture) asserting a non-noarch package builds, plus the deployment-target
value on macOS.

Refs: prefix-dev#6175
@hunger hunger requested a review from ruben-arts June 9, 2026 15:09
@baszalmstra

baszalmstra commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

I think (not entirely sure) that conda-forge adds MACOSX_DEPLOYMENT_TARGET as a variant too.

Nope thats wrong. Its handled by the macosx_deployment_target package.

Comment on lines +42 to +68
/// Build-script env entry pinning the macOS deployment target for compiled
/// (non-noarch) macOS builds (pixi issue #6175).
///
/// rattler-build hard-codes `MACOSX_DEPLOYMENT_TARGET` (11.0/10.9) and ignores
/// the `c_stdlib_version` variant, so maturin/PEP 517 wheels get the host SDK
/// tag. We override it with `${{ c_stdlib_version }}` (rendered lazily by
/// rattler-build), which pixi derives from the platform's `__osx` requirement.
/// `None` off macOS, for noarch, or when the variant is absent.
fn macos_deployment_target_env(
host_platform: Platform,
variants: &HashSet<NormalizedKey>,
is_noarch: bool,
) -> Option<(String, Value<String>)> {
if is_noarch
|| !host_platform.is_osx()
|| !variants.contains(&NormalizedKey::from("c_stdlib_version".to_string()))
{
return None;
}

let template =
JinjaTemplate::new("${{ c_stdlib_version }}".to_string()).expect("valid jinja template");
Some((
"MACOSX_DEPLOYMENT_TARGET".to_string(),
Value::new_template(template, None),
))
}

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.

This is not needed because this is done by the action script of the macos_deployment_target package.

Comment on lines +32 to +38
let (vp_name, provider) = if subdir.is_osx() {
("__osx", "macosx_deployment_target")
} else if subdir.is_linux() {
("__glibc", "sysroot")
} else {
return Vec::new();
};

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.

Note that these are only valid when building against conda-forge. I think we should gate that.

Comment on lines +7 to +10
/// conda-forge variant key naming the C stdlib provider for a build.
const C_STDLIB: &str = "c_stdlib";
/// conda-forge variant key carrying the minimum C stdlib version.
const C_STDLIB_VERSION: &str = "c_stdlib_version";

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.

The variant key name is not conda-forge specific. Only to what it maps.

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.

[pixi-build] Inject system-requirements as c_stdlib variants

2 participants