From 9cc1071ae2233da0e2c90b835454d1167e2090ea Mon Sep 17 00:00:00 2001 From: Julian Hofer Date: Wed, 3 Jun 2026 11:52:02 +0000 Subject: [PATCH 1/4] feat(build): support if(...) conditional package dependencies Add support for conditional dependencies in the [package] section using an if() key inside the dependency tables, e.g. [package.build-dependencies."if(host_platform != build_platform)"]. The expression is not evaluated by pixi; it is modelled as a dedicated ConditionalExpression type in the project model, separate from platform target selectors, and passed through verbatim to rattler-build as part of pixi-build-api-version 5. The legacy [package.target.*] tables keep working but emit a deprecation warning that spells out the equivalent if(...) tables, and they are removed from the JSON schema. Workspace [target.*] tables reject expression selectors with an error pointing at the package dependency tables. The passthrough test backend has no jinja evaluator and panics on if(...) conditionals instead of silently dropping them. --- .../src/generated_recipe.rs | 11 +- .../src/specs_conversion.rs | 297 +++++++++----- .../tests/integration/common/model.rs | 1 + .../tests/integration/protocol.rs | 1 + .../pixi_build_backend_passthrough/src/lib.rs | 37 +- .../pixi_build_rattler_build/src/protocol.rs | 6 + .../src/project_model.rs | 23 +- ..._v1_examples@conditional-dependencies.snap | 70 ++++ crates/pixi_build_types/src/lib.rs | 12 +- crates/pixi_build_types/src/project_model.rs | 101 ++++- crates/pixi_manifest/src/manifests/package.rs | 16 +- crates/pixi_manifest/src/target.rs | 52 ++- crates/pixi_manifest/src/toml/manifest.rs | 27 ++ crates/pixi_manifest/src/toml/package.rs | 362 +++++++++++++++++- .../src/utils/inheritable_package_map.rs | 110 +++++- .../pixi_manifest/src/warning/deprecation.rs | 23 +- docs/build/dependency_types.md | 38 ++ .../invalid/package_target_removed.toml | 19 + schema/examples/valid/full.toml | 4 +- schema/model.py | 43 +-- schema/pixi_build_api.json | 12 +- schema/pyproject/partial-pixi.json | 224 ++++------- schema/pyproject/schema.json | 224 ++++------- schema/schema.json | 224 ++++------- .../rattler-build-backend/smokey2/pixi.toml | 2 +- .../data/pixi-build/target-specific/pixi.toml | 4 +- 26 files changed, 1359 insertions(+), 584 deletions(-) create mode 100644 crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_examples@conditional-dependencies.snap create mode 100644 schema/examples/invalid/package_target_removed.toml diff --git a/crates/pixi_build_backend/src/generated_recipe.rs b/crates/pixi_build_backend/src/generated_recipe.rs index ec4bd110e4..6579676668 100644 --- a/crates/pixi_build_backend/src/generated_recipe.rs +++ b/crates/pixi_build_backend/src/generated_recipe.rs @@ -16,7 +16,9 @@ use serde::de::DeserializeOwned; use thiserror::Error; use url::Url; -use crate::specs_conversion::from_targets_v1_to_conditional_requirements; +use crate::specs_conversion::{ + SelectorConversionError, from_targets_v1_to_conditional_requirements, +}; #[derive(Debug, Clone, Default)] pub struct PythonParams { @@ -151,6 +153,9 @@ pub enum GenerateRecipeError { #[source] MetadataProviderError, ), + #[error(transparent)] + #[diagnostic(transparent)] + InvalidSelectorExpression(#[from] SelectorConversionError), } #[derive(Clone)] @@ -247,7 +252,7 @@ impl GeneratedRecipe { ); let requirements = - from_targets_v1_to_conditional_requirements(&model.targets.unwrap_or_default()); + from_targets_v1_to_conditional_requirements(&model.targets.unwrap_or_default())?; macro_rules! derive_value { ($ident:ident) => { @@ -409,6 +414,7 @@ mod tests { ..Target::default() }), targets: None, + conditional: None, }), ..ProjectModel::default() }; @@ -444,6 +450,7 @@ mod tests { targets: Some(Targets { default_target: None, targets: Some(platform_targets), + conditional: None, }), ..ProjectModel::default() }; diff --git a/crates/pixi_build_backend/src/specs_conversion.rs b/crates/pixi_build_backend/src/specs_conversion.rs index 3e3c349a73..8b03765c33 100644 --- a/crates/pixi_build_backend/src/specs_conversion.rs +++ b/crates/pixi_build_backend/src/specs_conversion.rs @@ -21,14 +21,22 @@ use rattler_build_recipe::stage0::{ }; use crate::package_dependency::{PackageDependency, SourceMatchSpec}; +use miette::Diagnostic; use rattler_conda_types::{ Channel, MatchSpec, PackageName, PackageNameMatcher, package::RunExportsJson, }; use serde::Deserialize; +use thiserror::Error; use url::Url; use crate::encoded_source_spec_url::EncodedSourceSpecUrl; +#[derive(Debug, Error, Diagnostic)] +pub enum SelectorConversionError { + #[error("invalid selector expression `{expression}`: {message}")] + InvalidExpression { expression: String, message: String }, +} + pub fn from_source_url_to_source_package(source_url: Url) -> Option { match source_url.scheme() { "source" => Some(EncodedSourceSpecUrl::from(source_url).into()), @@ -75,13 +83,23 @@ pub fn convert_variant_to_pixi_build_types( pixi_build_types::VariantValue::deserialize(value) } -pub fn to_rattler_build_selector(selector: &TargetSelector, platform_kind: PlatformKind) -> String { - match selector { +pub fn to_rattler_build_selector( + selector: &TargetSelector, + platform_kind: PlatformKind, +) -> Result { + let selector_str = match selector { TargetSelector::Platform(p) | TargetSelector::Subdir(p) => { format!("{platform_kind}_platform == '{p}'") } _ => selector.to_string(), - } + }; + + JinjaExpression::new(selector_str.clone()).map_err(|message| { + SelectorConversionError::InvalidExpression { + expression: selector_str, + message, + } + }) } /// Convert a `PackageDependency` to a `SerializableMatchSpec` for use in @@ -98,126 +116,121 @@ fn package_dependency_to_item(dep: PackageDependency) -> Item Requirements { - let mut build_items = ConditionalList::default(); - let mut host_items = ConditionalList::default(); - let mut run_items = ConditionalList::default(); - let mut run_constraints_items = ConditionalList::default(); - let mut extras: BTreeMap> = BTreeMap::new(); +/// Accumulates the per-section requirement items while converting targets. +#[derive(Default)] +struct RequirementItems { + build: ConditionalList, + host: ConditionalList, + run: ConditionalList, + run_constraints: ConditionalList, + extras: BTreeMap>, +} - // Add default target - if let Some(default_target) = &targets.default_target { - let package_requirements = PackageSpecDependencies::from(default_target); +impl RequirementItems { + /// Add the dependencies of `target`, wrapping each one in `condition` when + /// one is given. + fn add_target(&mut self, target: &Target, condition: Option<&JinjaExpression>) { + let to_item = |dep: PackageDependency| -> Item { + let item = package_dependency_to_item(dep); + match condition { + Some(condition) => Item::Conditional(Conditional { + condition: condition.clone(), + then: NestedItemList::single(item), + else_value: None, + condition_span: None, + }), + None => item, + } + }; - build_items.extend( - package_requirements + let requirements = PackageSpecDependencies::from(target); + self.build.extend( + requirements .build .into_iter() .map(|spec| spec.1) - .map(package_dependency_to_item), + .map(to_item), ); - - host_items.extend( - package_requirements + self.host.extend( + requirements .host .into_iter() .map(|spec| spec.1) - .map(package_dependency_to_item), - ); - - run_items.extend( - package_requirements - .run - .into_iter() - .map(|spec| spec.1) - .map(package_dependency_to_item), + .map(to_item), ); - - run_constraints_items.extend( - package_requirements + self.run + .extend(requirements.run.into_iter().map(|spec| spec.1).map(to_item)); + self.run_constraints.extend( + requirements .run_constraints .into_iter() .map(|spec| spec.1) - .map(package_dependency_to_item), + .map(to_item), ); - if let Some(default_extras) = &default_target.extra_dependencies { - for (group, deps) in default_extras { + if let Some(target_extras) = &target.extra_dependencies { + for (group, deps) in target_extras { let items = package_specs_to_package_dependency(deps.clone()) .unwrap() .into_iter() - .map(package_dependency_to_item); - extras.entry(group.to_string()).or_default().extend(items); + .map(to_item); + self.extras + .entry(group.to_string()) + .or_default() + .extend(items); } } } +} + +pub fn from_targets_v1_to_conditional_requirements( + targets: &Targets, +) -> Result { + let mut items = RequirementItems::default(); - // Add specific targets + // Add default target + if let Some(default_target) = &targets.default_target { + items.add_target(default_target, None); + } + + // Add specific targets. The platform selector becomes a condition on every + // dependency under the target. if let Some(specific_targets) = &targets.targets { for (selector, target) in specific_targets { - let package_requirements = PackageSpecDependencies::from(target); - let selector_str = to_rattler_build_selector(selector, PlatformKind::Host); - - // Helper to wrap a dep in a conditional - let make_conditional = |dep: PackageDependency| -> Item { - Item::Conditional(Conditional { - condition: JinjaExpression::new(selector_str.clone()) - .expect("valid jinja expression"), - then: NestedItemList::single(package_dependency_to_item(dep)), - else_value: None, - condition_span: None, - }) - }; + let condition = to_rattler_build_selector(selector, PlatformKind::Host)?; + items.add_target(target, Some(&condition)); + } + } - build_items.extend( - package_requirements - .build - .into_iter() - .map(|spec| spec.1) - .map(make_conditional), - ); - host_items.extend( - package_requirements - .host - .into_iter() - .map(|spec| spec.1) - .map(make_conditional), - ); - run_items.extend( - package_requirements - .run - .into_iter() - .map(|spec| spec.1) - .map(make_conditional), - ); - run_constraints_items.extend( - package_requirements - .run_constraints - .into_iter() - .map(|spec| spec.1) - .map(make_conditional), - ); - - if let Some(target_extras) = &target.extra_dependencies { - for (group, deps) in target_extras { - let items = package_specs_to_package_dependency(deps.clone()) - .unwrap() - .into_iter() - .map(&make_conditional); - extras.entry(group.to_string()).or_default().extend(items); + // Add conditional `if(...)` targets. The expression is handed to + // rattler-build verbatim; pixi does not evaluate it. + if let Some(conditional_targets) = &targets.conditional { + for (expression, target) in conditional_targets { + let condition = JinjaExpression::new(expression.to_string()).map_err(|message| { + SelectorConversionError::InvalidExpression { + expression: expression.to_string(), + message, } - } + })?; + items.add_target(target, Some(&condition)); } } - Requirements { - build: build_items, - host: host_items, - run: run_items, - run_constraints: run_constraints_items, + let RequirementItems { + build, + host, + run, + run_constraints, + extras, + } = items; + Ok(Requirements { + build, + host, + run, + run_constraints, extras, ..Default::default() - } + }) } pub(crate) fn source_package_spec_to_package_dependency( @@ -510,6 +523,7 @@ pub fn from_build_v1_args_to_finalized_dependencies( #[cfg(test)] mod test { + use pixi_build_types::ConditionalExpression; use rattler_conda_types::ParseMatchSpecOptions; use super::*; @@ -609,8 +623,9 @@ mod test { ..Target::default() }), targets: None, + conditional: None, }; - let requirements = from_targets_v1_to_conditional_requirements(&targets); + let requirements = from_targets_v1_to_conditional_requirements(&targets).unwrap(); let value = serde_json::to_value(&requirements.extras).unwrap(); assert_eq!( @@ -621,6 +636,96 @@ mod test { ); } + #[test] + fn test_to_rattler_build_selector_platform() { + // Platform selectors become `_platform == '...'`. + assert_eq!( + to_rattler_build_selector( + &TargetSelector::Platform("linux-64".to_string()), + PlatformKind::Host + ) + .unwrap() + .source(), + "host_platform == 'linux-64'" + ); + } + + /// A conditional `if(...)` dependency is wrapped in a `Conditional` carrying + /// the user's expression verbatim. + #[test] + fn test_conditional_expression_passthrough() { + let mut dependencies = OrderMap::new(); + dependencies.insert( + SourcePackageName::from(PackageName::new_unchecked("foo")), + BinaryPackageSpec { + version: Some("*".parse().unwrap()), + ..BinaryPackageSpec::default() + } + .into(), + ); + + let mut conditional = OrderMap::new(); + conditional.insert( + ConditionalExpression::new("host_platform != build_platform"), + Target { + build_dependencies: Some(dependencies), + ..Target::default() + }, + ); + let targets = Targets { + default_target: None, + targets: None, + conditional: Some(conditional), + }; + + let requirements = from_targets_v1_to_conditional_requirements(&targets).unwrap(); + + let value = serde_json::to_string(&requirements.build).unwrap(); + assert!( + value.contains("host_platform != build_platform"), + "conditional expression must be preserved verbatim: {value}" + ); + assert!( + value.contains("foo"), + "conditional dependency must be present: {value}" + ); + } + + /// A malformed user-supplied expression selector must surface as an error + /// rather than panicking inside `JinjaExpression::new`. + #[test] + fn test_invalid_expression_selector_errors_instead_of_panicking() { + let mut dependencies = OrderMap::new(); + dependencies.insert( + SourcePackageName::from(PackageName::new_unchecked("foo")), + BinaryPackageSpec { + version: Some("*".parse().unwrap()), + ..BinaryPackageSpec::default() + } + .into(), + ); + + let mut conditional = OrderMap::new(); + conditional.insert( + ConditionalExpression::new(")("), + Target { + build_dependencies: Some(dependencies), + ..Target::default() + }, + ); + let targets = Targets { + default_target: None, + targets: None, + conditional: Some(conditional), + }; + + let result = from_targets_v1_to_conditional_requirements(&targets); + assert!( + result.is_err(), + "a malformed selector expression must return an error, not panic" + ); + } + /// Per-target extras must be wrapped in a `Conditional` so the resulting /// recipe only pulls them in for the matching platform selector. #[test] @@ -652,9 +757,10 @@ mod test { let targets = Targets { default_target: None, targets: Some(platform_targets), + conditional: None, }; - let requirements = from_targets_v1_to_conditional_requirements(&targets); + let requirements = from_targets_v1_to_conditional_requirements(&targets).unwrap(); let test_group = requirements .extras .get("test") @@ -754,9 +860,10 @@ mod test { let targets = Targets { default_target: Some(target_with_only_run_constraints("everywhere", ">=1.0")), targets: Some(targets_map), + conditional: None, }; - let req = from_targets_v1_to_conditional_requirements(&targets); + let req = from_targets_v1_to_conditional_requirements(&targets).unwrap(); assert!(req.build.is_empty()); assert!(req.host.is_empty()); assert!(req.run.is_empty()); diff --git a/crates/pixi_build_backend/tests/integration/common/model.rs b/crates/pixi_build_backend/tests/integration/common/model.rs index 4238785136..43bbf1517c 100644 --- a/crates/pixi_build_backend/tests/integration/common/model.rs +++ b/crates/pixi_build_backend/tests/integration/common/model.rs @@ -119,6 +119,7 @@ pub(crate) fn convert_test_model_to_project_model_v1(test_model: TestProjectMode }) .collect(), ), + conditional: None, }; ProjectModel { diff --git a/crates/pixi_build_backend/tests/integration/protocol.rs b/crates/pixi_build_backend/tests/integration/protocol.rs index 8e074e90a1..d2f38baab5 100644 --- a/crates/pixi_build_backend/tests/integration/protocol.rs +++ b/crates/pixi_build_backend/tests/integration/protocol.rs @@ -275,6 +275,7 @@ async fn test_conda_outputs_extra_dependencies() { ..Target::default() }), targets: Some(platform_targets), + conditional: None, }), ..ProjectModel::default() }; diff --git a/crates/pixi_build_backend_passthrough/src/lib.rs b/crates/pixi_build_backend_passthrough/src/lib.rs index 1d25612bb4..384ffe427c 100644 --- a/crates/pixi_build_backend_passthrough/src/lib.rs +++ b/crates/pixi_build_backend_passthrough/src/lib.rs @@ -310,6 +310,8 @@ fn generate_variant_outputs( package_run_exports: Option<&RunExportsJson>, config: &PassthroughBackendConfig, ) -> Vec { + reject_conditional_targets(project_model); + // Check if we have variant configurations and dependencies with "*" let variant_keys = find_variant_keys(project_model, params); @@ -909,6 +911,18 @@ fn matches_target_selector(selector: &TargetSelector, platform: Platform) -> boo } } +/// The passthrough backend has no jinja evaluator and therefore cannot decide +/// whether an `if(...)` conditional applies. Panic rather than silently dropping +/// the conditional dependencies; a real backend evaluates these via +/// rattler-build. +fn reject_conditional_targets(project_model: &ProjectModel) { + if let Some(targets) = &project_model.targets + && targets.conditional.as_ref().is_some_and(|c| !c.is_empty()) + { + unimplemented!("passthrough backend cannot evaluate if(...) conditional dependencies") + } +} + /// An implementation of the [`InMemoryBackendInstantiator`] that creates a /// [`PassthroughBackend`]. #[derive(Default)] @@ -1202,7 +1216,7 @@ where #[cfg(test)] mod tests { - use pixi_build_types::{BinaryPackageSpec, PackageSpec}; + use pixi_build_types::{BinaryPackageSpec, ConditionalExpression, PackageSpec}; use rattler_conda_types::{ParseStrictness, VersionSpec}; use super::*; @@ -1236,6 +1250,27 @@ mod tests { assert!(is_star_requirement(&spec)); } + #[test] + #[should_panic(expected = "passthrough backend cannot evaluate if(")] + fn test_passthrough_rejects_conditional_dependencies() { + // The passthrough backend has no jinja evaluator, so conditional + // `if(...)` dependencies must fail loudly rather than being silently + // dropped. + let mut conditional = OrderMap::new(); + conditional.insert( + ConditionalExpression::new("host_platform != build_platform"), + Target::default(), + ); + let project_model = ProjectModel { + targets: Some(Targets { + conditional: Some(conditional), + ..Targets::default() + }), + ..ProjectModel::default() + }; + reject_conditional_targets(&project_model); + } + #[test] fn test_generate_variant_combinations_empty() { let variants = generate_variant_combinations(&[]); diff --git a/crates/pixi_build_rattler_build/src/protocol.rs b/crates/pixi_build_rattler_build/src/protocol.rs index b9433e98b2..e8b296f80b 100644 --- a/crates/pixi_build_rattler_build/src/protocol.rs +++ b/crates/pixi_build_rattler_build/src/protocol.rs @@ -712,6 +712,12 @@ impl ProtocolInstantiator for RattlerBuildBackendInstantiator { extract_workspace_deps(target, &mut workspace_dependencies)?; } } + + if let Some(conditional) = target.conditional { + for (_, target) in conditional { + extract_workspace_deps(target, &mut workspace_dependencies)?; + } + } } let mut instance = RattlerBuildBackend::new( diff --git a/crates/pixi_build_type_conversions/src/project_model.rs b/crates/pixi_build_type_conversions/src/project_model.rs index 968622b978..83ecbb641c 100644 --- a/crates/pixi_build_type_conversions/src/project_model.rs +++ b/crates/pixi_build_type_conversions/src/project_model.rs @@ -11,7 +11,7 @@ use ordermap::OrderMap; // different types use pixi_build_types::{self as pbt}; -use pixi_manifest::{PackageManifest, PackageTarget, TargetSelector, Targets}; +use pixi_manifest::{PackageManifest, PackageTarget, TargetSelector}; use pixi_spec::{GitReference, MatchspecFields, PixiSpec, SourceLocationSpec, SpecConversionError}; use rattler_conda_types::{ChannelConfig, NamelessMatchSpec, PackageName}; @@ -209,10 +209,11 @@ pub fn to_target_selector_v1(selector: &TargetSelector) -> pbt::TargetSelector { } fn to_targets_v1( - targets: &Targets, + manifest: &PackageManifest, channel_config: &ChannelConfig, ) -> Result { - let selected_targets = targets + let selected_targets = manifest + .targets .iter() .filter_map(|(k, v)| { v.map(|selector| { @@ -222,9 +223,21 @@ fn to_targets_v1( }) .collect::, _>>()?; + // Conditional `if(...)` dependencies are not platform selectors; they are + // carried separately and passed through to rattler-build, which evaluates + // the expression. + let conditional = manifest + .conditional_dependencies + .iter() + .map(|(expression, target)| { + to_target_v1(target, channel_config).map(|target| (expression.clone(), target)) + }) + .collect::, _>>()?; + Ok(pbt::Targets { - default_target: Some(to_target_v1(targets.default(), channel_config)?), + default_target: Some(to_target_v1(manifest.targets.default(), channel_config)?), targets: Some(selected_targets), + conditional: (!conditional.is_empty()).then_some(conditional), }) } @@ -247,7 +260,7 @@ pub fn to_project_model_v1( homepage: manifest.package.homepage.clone(), repository: manifest.package.repository.clone(), documentation: manifest.package.documentation.clone(), - targets: Some(to_targets_v1(&manifest.targets, channel_config)?), + targets: Some(to_targets_v1(manifest, channel_config)?), secrets: manifest.build.secrets.clone(), }; Ok(project) diff --git a/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_examples@conditional-dependencies.snap b/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_examples@conditional-dependencies.snap new file mode 100644 index 0000000000..38f9371054 --- /dev/null +++ b/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_examples@conditional-dependencies.snap @@ -0,0 +1,70 @@ +--- +source: crates/pixi_build_type_conversions/src/project_model.rs +expression: project_model +--- +{ + "name": "cuda_probe", + "buildStringPrefix": null, + "buildNumber": null, + "version": "0.1.0", + "description": "A C++ executable that demonstrates if(...) conditional dependencies", + "authors": null, + "license": null, + "licenseFile": null, + "readme": null, + "homepage": null, + "repository": null, + "documentation": null, + "targets": { + "defaultTarget": { + "hostDependencies": {}, + "buildDependencies": {}, + "runDependencies": {}, + "runConstraints": {} + }, + "targets": {}, + "conditional": { + "linux or win": { + "hostDependencies": {}, + "buildDependencies": {}, + "runDependencies": { + "cuda-version": { + "binary": { + "version": "12.*", + "build": null, + "buildNumber": null, + "fileName": null, + "extras": null, + "flags": null, + "channel": null, + "subdir": null, + "md5": null, + "sha256": null, + "url": null, + "license": null, + "condition": null + } + }, + "cuda-nvcc": { + "binary": { + "version": "12.*", + "build": null, + "buildNumber": null, + "fileName": null, + "extras": null, + "flags": null, + "channel": null, + "subdir": null, + "md5": null, + "sha256": null, + "url": null, + "license": null, + "condition": null + } + } + }, + "runConstraints": {} + } + } + } +} diff --git a/crates/pixi_build_types/src/lib.rs b/crates/pixi_build_types/src/lib.rs index 6d6abede38..81cabd1980 100644 --- a/crates/pixi_build_types/src/lib.rs +++ b/crates/pixi_build_types/src/lib.rs @@ -16,9 +16,10 @@ pub use conda_package_metadata::CondaPackageMetadata; pub use extra_group_name::{ExtraGroupName, InvalidExtraGroupName, MAX_EXTRA_GROUP_NAME_LEN}; pub use input_glob_set::InputGlobSet; pub use project_model::{ - BinaryPackageSpec, ConstraintSpec, GitReference, GitSpec, NamedSpec, PackageSpec, PathSpec, - PinBound, PinCompatibleSpec, PinExpression, ProjectModel, SourcePackageLocationSpec, - SourcePackageName, SourcePackageSpec, Target, TargetSelector, Targets, UrlSpec, + BinaryPackageSpec, ConditionalExpression, ConstraintSpec, GitReference, GitSpec, NamedSpec, + PackageSpec, PathSpec, PinBound, PinCompatibleSpec, PinExpression, ProjectModel, + SourcePackageLocationSpec, SourcePackageName, SourcePackageSpec, Target, TargetSelector, + Targets, UrlSpec, }; use rattler_conda_types::{ GenericVirtualPackage, PackageName, Platform, Version, VersionSpec, @@ -32,7 +33,10 @@ pub use variant::VariantValue; // Version 2: Name in project models can be `None`. // Version 3: Outputs with the same name must have unique variants. // Version 4: (BREAKING) Add matchspec fields to source record, cleanup types, remove version from project model and streamline use of directory vs dir. -// Version 5: (BREAKING) Serialize match specs in `conda/build_v1` as structured objects instead of strings and add extra dependency groups. +// Version 5: (BREAKING) Serialize match specs in `conda/build_v1` as +// structured objects instead of strings, add extra dependency groups, +// and add `if()` target selectors that are passed through +// to rattler-build. Older backends would silently mishandle them. /// The constraint for the pixi build api version package /// Adding this constraint when solving a pixi build backend environment ensures diff --git a/crates/pixi_build_types/src/project_model.rs b/crates/pixi_build_types/src/project_model.rs index 8f574fd700..7e43144d6b 100644 --- a/crates/pixi_build_types/src/project_model.rs +++ b/crates/pixi_build_types/src/project_model.rs @@ -91,8 +91,51 @@ impl IsDefault for ProjectModel { } } -/// Represents a target selector. Currently, we only support explicit platform -/// selection. +/// A free-form conditional selector expression that is passed through to +/// rattler-build, e.g. `host_platform == build_platform`. This is the bare +/// inner text of an `if()` selector key, without the wrapper. +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] +#[serde(transparent)] +pub struct ConditionalExpression(String); + +impl ConditionalExpression { + /// Creates a new conditional expression from its bare inner text. + pub fn new(expression: impl Into) -> Self { + Self(expression.into()) + } + + /// Returns the bare inner expression without the `if(...)` wrapper. + pub fn as_str(&self) -> &str { + &self.0 + } + + /// Consumes the expression and returns the inner string. + pub fn into_inner(self) -> String { + self.0 + } +} + +impl Display for ConditionalExpression { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} + +impl From for ConditionalExpression { + fn from(value: String) -> Self { + Self(value) + } +} + +/// Represents a platform-based target selector. +/// +/// # Deprecated +/// +/// Platform target selectors correspond to the deprecated +/// `[package.target.]` tables and will be removed in a future version. +/// Use conditional `if()` dependencies instead, which are carried +/// separately in [`Targets::conditional`]. #[derive(Debug, Clone, DeserializeFromStr, SerializeDisplay, Eq, PartialEq)] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub enum TargetSelector { @@ -103,7 +146,6 @@ pub enum TargetSelector { MacOs, Subdir(String), Platform(String), - // TODO: Add minijinja coolness here. } impl Display for TargetSelector { @@ -147,6 +189,14 @@ impl FromStr for TargetSelector { pub struct Targets { pub default_target: Option, + /// Platform-specific targets. + /// + /// # Deprecated + /// + /// These correspond to the deprecated `[package.target.]` tables + /// and will be removed in a future version. Use [`Targets::conditional`] + /// (`if()` dependencies) instead. + /// /// We use an [`OrderMap`] to preserve the order in which the items where /// defined in the manifest. #[cfg_attr( @@ -154,6 +204,16 @@ pub struct Targets { schemars(with = "Option>") )] pub targets: Option>, + + /// Conditional `if()` dependencies. The expression is passed + /// through to rattler-build, which evaluates it; pixi does not. Keyed by the + /// bare inner expression without the `if(...)` wrapper. + #[serde(default, skip_serializing_if = "Option::is_none")] + #[cfg_attr( + feature = "schemars", + schemars(with = "Option>") + )] + pub conditional: Option>, } impl Targets { @@ -163,8 +223,9 @@ impl Targets { let has_meaningless_default_target = self.default_target.as_ref().is_none_or(|t| t.is_empty()); let has_only_empty_targets = self.targets.as_ref().is_none_or(|t| t.is_empty()); + let has_only_empty_conditional = self.conditional.as_ref().is_none_or(|t| t.is_empty()); - has_meaningless_default_target && has_only_empty_targets + has_meaningless_default_target && has_only_empty_targets && has_only_empty_conditional } } @@ -678,11 +739,13 @@ impl Hash for Targets { let Targets { default_target, targets, + conditional, } = self; StableHashBuilder::::new() .field("default_target", default_target) .field("targets", targets) + .field("conditional", conditional) .finish(state); } } @@ -943,6 +1006,29 @@ mod tests { hasher.finish() } + #[test] + fn test_target_selector_roundtrip() { + // Platform families and concrete platforms round-trip through their + // string form. + for (text, selector) in [ + ("unix", TargetSelector::Unix), + ("linux", TargetSelector::Linux), + ("linux-64", TargetSelector::Subdir("linux-64".to_string())), + ] { + assert_eq!(selector.to_string(), text); + assert_eq!(text.parse::().unwrap(), selector); + } + } + + #[test] + fn test_conditional_expression_roundtrip() { + // A conditional expression carries its bare inner text and displays it + // verbatim. + let expression = ConditionalExpression::new("host_platform == build_platform"); + assert_eq!(expression.to_string(), "host_platform == build_platform"); + assert_eq!(expression.as_str(), "host_platform == build_platform"); + } + #[test] fn test_hash_stability_with_default_values() { // Create a minimal ProjectModelV1 instance @@ -972,6 +1058,7 @@ mod tests { project_model.targets = Some(Targets { default_target: None, targets: Some(OrderMap::new()), + conditional: None, }); let hash2 = calculate_hash(&project_model); @@ -986,6 +1073,7 @@ mod tests { project_model.targets = Some(Targets { default_target: Some(empty_target), targets: Some(OrderMap::new()), + conditional: None, }); let hash3 = calculate_hash(&project_model); @@ -1049,6 +1137,7 @@ mod tests { project_model.targets = Some(Targets { default_target: Some(target_with_deps), targets: Some(OrderMap::new()), + conditional: None, }); let hash3 = calculate_hash(&project_model); @@ -1166,6 +1255,7 @@ mod tests { let targets = Targets { default_target: Some(create_sample_target_v1()), targets: None, + conditional: None, }; let serialized = serde_json::to_string(&targets).unwrap(); @@ -1204,6 +1294,7 @@ mod tests { }) .collect(), ), + conditional: None, }; let serialized = serde_json::to_string(&targets).unwrap(); @@ -1369,11 +1460,13 @@ mod tests { let targets1 = Targets { default_target: Some(target1), targets: None, + conditional: None, }; let targets2 = Targets { default_target: Some(target2), targets: None, + conditional: None, }; let targets_hash1 = calculate_hash(&targets1); diff --git a/crates/pixi_manifest/src/manifests/package.rs b/crates/pixi_manifest/src/manifests/package.rs index 2b606d56d8..9d5f46a6ed 100644 --- a/crates/pixi_manifest/src/manifests/package.rs +++ b/crates/pixi_manifest/src/manifests/package.rs @@ -1,3 +1,6 @@ +use indexmap::IndexMap; +use pixi_build_types::ConditionalExpression; + use crate::target::PackageTarget; use crate::{PackageBuild, Targets, package::Package}; @@ -11,6 +14,17 @@ pub struct PackageManifest { /// Information about the build system for the package pub build: PackageBuild, - /// Defines the dependencies of the package + /// Defines the platform-specific dependencies of the package. + /// + /// # Deprecated + /// + /// These come from the deprecated `[package.target.]` tables and + /// will be removed in a future version. Use [`Self::conditional_dependencies`] + /// (`if()` dependencies) instead. pub targets: Targets, + + /// Dependencies guarded by an `if()` conditional. These are not + /// platform selectors; the expression is passed through to rattler-build, + /// which decides whether the dependencies apply. + pub conditional_dependencies: IndexMap, } diff --git a/crates/pixi_manifest/src/target.rs b/crates/pixi_manifest/src/target.rs index 090642413a..aec952abdb 100644 --- a/crates/pixi_manifest/src/target.rs +++ b/crates/pixi_manifest/src/target.rs @@ -446,8 +446,12 @@ impl PackageTarget { } } -/// Represents a target selector. Currently we only support explicit platform -/// selection. +/// Represents a target selector. +/// +/// Target selectors choose a configuration based on the platform. `if(...)` +/// conditional dependencies are not platform selectors; they are modelled +/// separately as [`pixi_build_types::ConditionalExpression`] and only exist on +/// the package manifest. #[derive(Debug, Clone, Eq, PartialEq, Hash)] pub enum TargetSelector { // Platform specific configuration @@ -457,7 +461,6 @@ pub enum TargetSelector { Linux, Win, MacOs, - // TODO: Add minijinja coolness here. } impl TargetSelector { @@ -509,10 +512,29 @@ impl From for TargetSelector { } } +/// Error returned when a target selector key cannot be parsed. +#[derive(Debug, thiserror::Error)] +pub enum ParseTargetSelectorError { + #[error(transparent)] + Platform(#[from] ParsePlatformError), + + /// The key looks like an `if(...)` expression selector, which is only valid + /// in the `[package]` dependency tables. + #[error( + "`{0}` is not a valid target selector. Expression selectors (`if(...)`) are only supported inside the `[package]` dependency tables (e.g. `[package.build-dependencies.\"if(host_platform == 'linux-64')\"]`); `[target.*]` accepts platform names only" + )] + Expression(String), +} + impl FromStr for TargetSelector { - type Err = ParsePlatformError; + type Err = ParseTargetSelectorError; fn from_str(s: &str) -> Result { + // `(` cannot appear in a platform or family name, so a key containing it + // is an attempt at an expression selector, which is package-only. + if key_looks_conditional(s) { + return Err(ParseTargetSelectorError::Expression(s.to_string())); + } if let Some(selector) = family_name_to_selector(s) { return Ok(selector); } @@ -522,7 +544,8 @@ impl FromStr for TargetSelector { let Ok(platform) = PixiPlatformName::try_from(s) else { return Err(ParsePlatformError { string: s.to_string(), - }); + } + .into()); }; Ok(TargetSelector::Platform(platform)) } @@ -541,6 +564,25 @@ pub(crate) fn family_name_to_selector(s: &str) -> Option { } } +/// If `key` is a well-formed `if()` wrapper, return the trimmed +/// inner expression. Returns `None` when the key is not wrapped or the +/// expression is empty. +/// +/// `(` is not a valid character in a package name, platform, or family, so a +/// key containing `(` is always intended as a conditional selector; callers +/// use [`key_looks_conditional`] to detect that case and report a malformed +/// expression when this function returns `None`. +pub(crate) fn parse_if_expression(key: &str) -> Option<&str> { + let inner = key.strip_prefix("if(")?.strip_suffix(')')?.trim(); + (!inner.is_empty()).then_some(inner) +} + +/// Returns true when `key` is intended as a conditional selector, i.e. it +/// contains a `(`. Such keys must be a well-formed `if()`. +pub(crate) fn key_looks_conditional(key: &str) -> bool { + key.contains('(') +} + /// A collect of targets including a default target. #[derive(Debug, Clone, Default)] pub struct Targets { diff --git a/crates/pixi_manifest/src/toml/manifest.rs b/crates/pixi_manifest/src/toml/manifest.rs index cff5f236f3..de558b1e5d 100644 --- a/crates/pixi_manifest/src/toml/manifest.rs +++ b/crates/pixi_manifest/src/toml/manifest.rs @@ -1573,6 +1573,33 @@ mod test { )); } + #[test] + fn test_expression_selector_rejected_in_workspace_target() { + // `if(...)` expression selectors are only valid inside the `[package]` + // dependency tables; in a workspace `[target.*]` they must be rejected + // with a hint pointing users at the package dependency tables. + assert_snapshot!(expect_parse_failure( + r#" + [workspace] + name = "test" + channels = [] + platforms = ['linux-64'] + + [target."if(host_platform == build_platform)".dependencies] + foo = "*" + "#, + ), @r###" + × `if(host_platform == build_platform)` is not a valid target selector. Expression selectors (`if(...)`) are only supported inside the `[package]` dependency tables (e.g. `[package.build- + │ dependencies."if(host_platform == 'linux-64')"]`); `[target.*]` accepts platform names only + ╭─[pixi.toml:7:18] + 6 │ + 7 │ [target."if(host_platform == build_platform)".dependencies] + · ─────────────────────────────────── + 8 │ foo = "*" + ╰──── + "###); + } + #[test] fn test_unknown_feature() { assert_snapshot!(expect_parse_failure( diff --git a/crates/pixi_manifest/src/toml/package.rs b/crates/pixi_manifest/src/toml/package.rs index 1e19d6af5d..80801dc5cc 100644 --- a/crates/pixi_manifest/src/toml/package.rs +++ b/crates/pixi_manifest/src/toml/package.rs @@ -1,6 +1,7 @@ use std::path::{Path, PathBuf}; use indexmap::IndexMap; +use pixi_build_types::ConditionalExpression; use pixi_spec::TomlSpec; pub use pixi_toml::TomlFromStr; use pixi_toml::{DeserializeAs, Same, TomlIndexMap, TomlWith}; @@ -13,10 +14,17 @@ use crate::{ PackageManifest, Preview, TargetSelector, Targets, TomlError, WithWarnings, error::GenericError, package::Package, + target::PackageTarget, toml::{ TomlPackageBuild, manifest::ExternalWorkspaceProperties, package_target::TomlPackageTarget, }, - utils::{PixiSpanned, inheritable_package_map::InheritablePackageMap}, + utils::{ + PixiSpanned, + inheritable_package_map::{ + ConditionalInheritablePackageMap, ConditionalSpecs, InheritablePackageMap, + }, + }, + warning::Deprecation, }; /// Represents a field that can either have a direct value or inherit from @@ -133,11 +141,12 @@ pub struct TomlPackage { // Fields that are package-specific and cannot be inherited pub build: TomlPackageBuild, - pub host_dependencies: Option>, - pub build_dependencies: Option>, - pub run_dependencies: Option>, - pub extra_dependencies: IndexMap, PixiSpanned>, - pub run_constraints: Option>, + pub host_dependencies: Option>, + pub build_dependencies: Option>, + pub run_dependencies: Option>, + pub extra_dependencies: + IndexMap, PixiSpanned>, + pub run_constraints: Option>, pub target: IndexMap, TomlPackageTarget>, pub span: Span, @@ -359,23 +368,107 @@ impl TomlPackage { "version", )?; + // Split each package-level dependency table into its unconditional + // entries and any `if()` sub-tables. + let (run_unconditional, run_conditional) = split_section(self.run_dependencies); + let (constraints_unconditional, constraints_conditional) = + split_section(self.run_constraints); + let (host_unconditional, host_conditional) = split_section(self.host_dependencies); + let (build_unconditional, build_conditional) = split_section(self.build_dependencies); + + let mut extra_unconditional: IndexMap< + PixiSpanned, + PixiSpanned, + > = IndexMap::new(); + let mut extra_conditional: Vec<(PixiSpanned, ConditionalSpecs)> = Vec::new(); + for (group, PixiSpanned { value, span }) in self.extra_dependencies { + let (unconditional, conditional) = value.into_parts(); + if !unconditional.is_empty() { + extra_unconditional.insert( + group.clone(), + PixiSpanned { + value: unconditional, + span, + }, + ); + } + for spec in conditional { + extra_conditional.push((group.clone(), spec)); + } + } + + // Unconditional entries form the default target. let default_package_target = TomlPackageTarget { - run_dependencies: self.run_dependencies, - run_constraints: self.run_constraints, - host_dependencies: self.host_dependencies, - build_dependencies: self.build_dependencies, - extra_dependencies: self.extra_dependencies, + run_dependencies: run_unconditional, + run_constraints: constraints_unconditional, + host_dependencies: host_unconditional, + build_dependencies: build_unconditional, + extra_dependencies: extra_unconditional, } .into_package_target(preview, &workspace_dependencies)?; - let targets = self - .target - .into_iter() - .map(|(selector, target)| { - let target = target.into_package_target(preview, &workspace_dependencies)?; - Ok::<_, TomlError>((selector, target)) - }) - .collect::>()?; + // Fold the conditional sub-tables into one `TomlPackageTarget` per + // distinct expression, merging across the dependency sections. + type SectionField = + fn(&mut TomlPackageTarget) -> &mut Option>; + let sections: [(Vec, SectionField); 4] = [ + (run_conditional, |target| &mut target.run_dependencies), + (constraints_conditional, |target| { + &mut target.run_constraints + }), + (host_conditional, |target| &mut target.host_dependencies), + (build_conditional, |target| &mut target.build_dependencies), + ]; + let mut conditional_targets: IndexMap = IndexMap::new(); + for (specs, field) in sections { + for spec in specs { + *field(conditional_targets.entry(spec.expression).or_default()) = + Some(PixiSpanned { + value: spec.specs, + span: Some(spec.value_span), + }); + } + } + for (group, spec) in extra_conditional { + conditional_targets + .entry(spec.expression) + .or_default() + .extra_dependencies + .insert( + group, + PixiSpanned { + value: spec.specs, + span: Some(spec.value_span), + }, + ); + } + + // `if(...)` conditionals are not platform selectors; they are kept + // separate and passed through to rattler-build, which evaluates the + // expression. + let mut conditional_dependencies: IndexMap = + IndexMap::new(); + for (expression, toml_target) in conditional_targets { + let target = toml_target.into_package_target(preview, &workspace_dependencies)?; + conditional_dependencies.insert(ConditionalExpression::new(expression), target); + } + + let mut targets: IndexMap, PackageTarget> = IndexMap::new(); + + // The legacy `[package.target.PLATFORM]` syntax is deprecated but still + // supported. Emit a deprecation warning with a tailored suggestion for + // the equivalent conditional dependency tables. + for (selector, toml_target) in self.target { + warnings.push( + Deprecation::package_target( + package_target_replacement_help(&selector.value, &toml_target), + selector.span.clone(), + ) + .into(), + ); + let target = toml_target.into_package_target(preview, &workspace_dependencies)?; + targets.insert(selector, target); + } if let Some(WorkspaceInheritableField::Value(Spanned { value: license, @@ -507,11 +600,79 @@ impl TomlPackage { }, build: build_result.value, targets: Targets::from_default_and_user_defined(default_package_target, targets), + conditional_dependencies, }) .with_warnings(warnings)) } } +/// Build the tailored `help` text suggesting the conditional dependency tables +/// that replace a deprecated `[package.target.SELECTOR]` entry. +/// +/// Platform selectors map to `host_platform == ''` (the behavior the +/// legacy syntax already had); family selectors (`unix`/`linux`/`win`/`osx`) +/// map to the bare rattler-build boolean. +fn package_target_replacement_help( + selector: &TargetSelector, + toml_target: &TomlPackageTarget, +) -> String { + let expression = match selector { + TargetSelector::Platform(_) | TargetSelector::Subdir(_) => { + format!("host_platform == '{selector}'") + } + other => other.to_string(), + }; + + let mut lines = Vec::new(); + let mut push_line = |section: &str| { + lines.push(format!(" [package.{section}.\"if({expression})\"]")); + }; + if toml_target.build_dependencies.is_some() { + push_line("build-dependencies"); + } + if toml_target.host_dependencies.is_some() { + push_line("host-dependencies"); + } + if toml_target.run_dependencies.is_some() { + push_line("run-dependencies"); + } + if toml_target.run_constraints.is_some() { + push_line("run-constraints"); + } + if !toml_target.extra_dependencies.is_empty() { + lines.push(format!( + " [package.extra-dependencies..\"if({expression})\"]" + )); + } + + format!( + "Move the dependencies under a conditional dependency table instead:\n{}", + lines.join("\n") + ) +} + +/// Split a package-level dependency table into its unconditional entries (which +/// belong to the default target) and the list of `if()` sub-tables. +/// Returns `None` for the unconditional part when it is empty. +fn split_section( + field: Option>, +) -> ( + Option>, + Vec, +) { + match field { + None => (None, Vec::new()), + Some(PixiSpanned { value, span }) => { + let (unconditional, conditional) = value.into_parts(); + let unconditional = (!unconditional.is_empty()).then_some(PixiSpanned { + value: unconditional, + span, + }); + (unconditional, conditional) + } + } +} + fn workspace_cannot_be_false() -> GenericError { GenericError::new("`workspace` cannot be false") .with_help("By default no fields are inherited from the workspace") @@ -558,6 +719,7 @@ mod test { use super::*; use crate::{KnownPreviewFeature, SpecType, TargetSelector, toml::FromTomlStr}; + use pixi_build_types::ConditionalExpression; /// Parses a manifest using only `Preview::default()` and asserts it succeeds. fn parse_package(input: &str) -> PackageManifest { @@ -1357,6 +1519,168 @@ mod test { ); } + #[test] + fn test_package_conditional_dependencies() { + // `if()` keys inside the package dependency tables become + // `Expression` targets; plain entries stay on the default target. + let input = r#" + name = "pkg" + version = "1.0" + + [build] + backend = { name = "bla", version = "1.0" } + + [run-dependencies] + shared = "==1.0" + + [build-dependencies."if(host_platform != build_platform)"] + cross-tool = "==2.0" + + [host-dependencies."if(host_platform == 'linux-64')"] + libgl = "==3.0" + "#; + + let manifest = parse_package(input); + + // Plain entry stays on the default target. + assert_single_version( + &manifest.targets.default().dependencies, + SpecType::Run, + "shared", + "==1.0", + ); + + // Each `if(...)` block produces a conditional target with only the + // matching dependency bucket populated. + let cross = manifest + .conditional_dependencies + .get(&ConditionalExpression::new( + "host_platform != build_platform", + )) + .expect("conditional target should exist"); + assert_single_version(&cross.dependencies, SpecType::Build, "cross-tool", "==2.0"); + + let linux = manifest + .conditional_dependencies + .get(&ConditionalExpression::new("host_platform == 'linux-64'")) + .expect("conditional target should exist"); + assert_single_version(&linux.dependencies, SpecType::Host, "libgl", "==3.0"); + } + + #[test] + fn test_package_conditional_merges_same_expression() { + // The same expression used across sections folds into a single target. + let input = r#" + name = "pkg" + version = "1.0" + + [build] + backend = { name = "bla", version = "1.0" } + + [build-dependencies."if(host_platform == 'linux-64')"] + build-only = "==1.0" + + [run-dependencies."if(host_platform == 'linux-64')"] + run-only = "==2.0" + "#; + + let manifest = parse_package(input); + assert_eq!( + manifest.conditional_dependencies.len(), + 1, + "the two sections must merge into one target" + ); + + let target = manifest + .conditional_dependencies + .get(&ConditionalExpression::new("host_platform == 'linux-64'")) + .expect("conditional target should exist"); + assert_single_version(&target.dependencies, SpecType::Build, "build-only", "==1.0"); + assert_single_version(&target.dependencies, SpecType::Run, "run-only", "==2.0"); + } + + #[test] + fn test_package_conditional_malformed_expression() { + // A key containing `(` that is not a well-formed `if(...)` is rejected. + assert_snapshot!(expect_parse_failure( + r#" + name = "pkg" + version = "1.0" + + [build] + backend = { name = "bla", version = "1.0" } + + [build-dependencies."matches(python, '>=3.10')"] + foo = "*" + "#, + ), @r###" + × `matches(python, '>=3.10')` is not a valid selector. Wrap the expression in `if(...)`, e.g. `if(host_platform == 'linux-64')` + ╭─[pixi.toml:8:30] + 7 │ + 8 │ [build-dependencies."matches(python, '>=3.10')"] + · ───────────────────────── + 9 │ foo = "*" + ╰──── + "###); + } + + #[test] + fn test_package_target_emits_deprecation_warning() { + // The legacy `[package.target.*]` syntax still parses, but produces a + // deprecation warning suggesting the conditional form. + let input = r#" + name = "pkg" + version = "1.0" + + [build] + backend = { name = "bla", version = "1.0" } + + [target.linux-64.build-dependencies] + foo = "==1.0" + "#; + + let mut parsed = TomlPackage::from_toml_str(input) + .and_then(|w| { + w.into_manifest( + WorkspacePackageProperties::default(), + PackageDefaults::default(), + &Preview::default(), + Path::new(""), + ) + }) + .expect("legacy target syntax must still parse"); + + assert!( + !parsed.warnings.is_empty(), + "legacy target syntax must emit a deprecation warning" + ); + // The rendered warning names the deprecated table and spells out the + // exact conditional syntax to use instead. + assert_snapshot!( + format_parse_error(input, parsed.warnings.remove(0)), + @r#" + ⚠ the `[package.target]` tables are deprecated in favor of conditional dependencies + ╭─[pixi.toml:8:17] + 7 │ + 8 │ [target.linux-64.build-dependencies] + · ────┬─── + · ╰── deprecated target selector + 9 │ foo = "==1.0" + ╰──── + help: Move the dependencies under a conditional dependency table instead: + [package.build-dependencies."if(host_platform == 'linux-64')"] + "# + ); + + // The legacy target still works: the dependency lands on the platform target. + let linux = parsed + .value + .targets + .for_target(&TargetSelector::Subdir(Platform::Linux64)) + .expect("linux-64 target should exist"); + assert_single_version(&linux.dependencies, SpecType::Build, "foo", "==1.0"); + } + #[test] fn test_run_constraints_source_spec_requires_pixi_build() { // Source specs in [package.run-constraints] must be rejected unless the diff --git a/crates/pixi_manifest/src/utils/inheritable_package_map.rs b/crates/pixi_manifest/src/utils/inheritable_package_map.rs index faa3058d24..23be547daf 100644 --- a/crates/pixi_manifest/src/utils/inheritable_package_map.rs +++ b/crates/pixi_manifest/src/utils/inheritable_package_map.rs @@ -10,7 +10,12 @@ use toml_span::{ value::{Table, ValueInner}, }; -use crate::{TomlError, error::GenericError, utils::package_map::UniquePackageMap}; +use crate::{ + TomlError, + error::GenericError, + target::{key_looks_conditional, parse_if_expression}, + utils::package_map::UniquePackageMap, +}; /// Entry in a `[package.*-dependencies]` table that may inherit from /// `[workspace.dependencies]`. @@ -208,6 +213,109 @@ impl<'de> toml_span::Deserialize<'de> for InheritablePackageMap { } } +/// A single `if()` sub-table inside a package dependency table. +#[derive(Debug)] +pub struct ConditionalSpecs { + /// The bare inner expression, without the `if(...)` wrapper. + pub expression: String, + /// Span of the sub-table value. + pub value_span: Range, + /// The dependencies declared under this condition. + pub specs: InheritablePackageMap, +} + +/// A package dependency table that, in addition to plain `name = spec` entries, +/// may contain conditional sub-tables keyed by `if()`. Plain +/// entries land in `unconditional`; each `if(...)` sub-table becomes a +/// [`ConditionalSpecs`] in source order. +/// +/// Keys are routed by `key_looks_conditional`: +/// a key containing `(` must be a well-formed `if()` or it is +/// reported as an error. +#[derive(Default, Debug)] +pub struct ConditionalInheritablePackageMap { + pub unconditional: InheritablePackageMap, + pub conditional: Vec, +} + +impl ConditionalInheritablePackageMap { + /// Split into the unconditional map and the list of conditional sub-tables. + pub fn into_parts(self) -> (InheritablePackageMap, Vec) { + (self.unconditional, self.conditional) + } +} + +impl<'de> toml_span::Deserialize<'de> for ConditionalInheritablePackageMap { + fn deserialize(value: &mut Value<'de>) -> Result { + let span = value.span; + let table = match value.take() { + ValueInner::Table(table) => table, + inner => return Err(expected("a table", inner, span).into()), + }; + + let mut errors = DeserError { errors: vec![] }; + let mut plain: Table<'de> = Table::new(); + let mut conditional = Vec::new(); + + for (key, mut entry_value) in table.into_iter().sorted_by_key(|(k, _)| k.span.start) { + if key_looks_conditional(&key.name) { + match parse_if_expression(&key.name) { + Some(expression) => { + let value_span = entry_value.span; + match InheritablePackageMap::deserialize(&mut entry_value) { + Ok(specs) => conditional.push(ConditionalSpecs { + expression: expression.to_string(), + value_span: value_span.start..value_span.end, + specs, + }), + Err(e) => errors.merge(e), + } + } + None => { + errors.errors.push(toml_span::Error { + kind: toml_span::ErrorKind::Custom( + format!( + "`{}` is not a valid selector. Wrap the expression in `if(...)`, e.g. `if(host_platform == 'linux-64')`", + key.name + ) + .into(), + ), + span: key.span, + line_info: None, + }); + } + } + } else { + plain.insert(key, entry_value); + } + } + + // Delegate the plain entries to `InheritablePackageMap` so name parsing, + // duplicate detection and spec parsing stay in one place. + let unconditional = if plain.is_empty() { + InheritablePackageMap::default() + } else { + let mut tmp = Value::with_span(ValueInner::Table(plain), span); + match InheritablePackageMap::deserialize(&mut tmp) { + Ok(map) => map, + Err(e) => { + errors.merge(e); + InheritablePackageMap::default() + } + } + }; + + if errors.errors.is_empty() { + Ok(Self { + unconditional, + conditional, + }) + } else { + Err(errors) + } + } +} + fn parse_inheritable_entry(value: &mut Value<'_>) -> Result { let outer_span = value.span; match value.take() { diff --git a/crates/pixi_manifest/src/warning/deprecation.rs b/crates/pixi_manifest/src/warning/deprecation.rs index 6350040cd8..485eca7cc9 100644 --- a/crates/pixi_manifest/src/warning/deprecation.rs +++ b/crates/pixi_manifest/src/warning/deprecation.rs @@ -1,4 +1,4 @@ -use std::{borrow::Cow, fmt::Display}; +use std::{borrow::Cow, fmt::Display, ops::Range}; use miette::{Diagnostic, LabeledSpan, Severity, SourceSpan}; use thiserror::Error; @@ -25,6 +25,27 @@ impl Deprecation { help: None, } } + + /// Deprecation of the legacy `[package.target.*]` dependency tables in + /// favor of `if()` conditional dependency tables. `help` carries + /// the tailored replacement suggestion. + pub fn package_target(help: String, span: Option>) -> Self { + let labels = span + .map(|span| { + vec![LabeledSpan::new_primary_with_span( + Some("deprecated target selector".to_string()), + SourceSpan::new(span.start.into(), span.end - span.start), + )] + }) + .unwrap_or_default(); + Self { + message: + "the `[package.target]` tables are deprecated in favor of conditional dependencies" + .into(), + labels, + help: Some(help.into()), + } + } } impl Diagnostic for Deprecation { diff --git a/docs/build/dependency_types.md b/docs/build/dependency_types.md index dba8e21ac2..cc6bf72bec 100644 --- a/docs/build/dependency_types.md +++ b/docs/build/dependency_types.md @@ -12,6 +12,9 @@ Each dependency is used at a different step of the package building process. Let's delve deeper into the various types of package dependencies and their specific roles in the build process. +!!! note "pixi-build-rattler-build" + The `pixi-build-rattler-build` backend only regards dependencies defined in the `recipe.yaml` + ### [Build Dependencies](../reference/pixi_manifest.md#build-dependencies) !!! note "pixi-build-cmake" When using the `pixi-build-cmake` backend you do not need to specify `cmake` or the compiler as a dependency. @@ -150,6 +153,41 @@ They never cause a package to be installed on their own. To do that, use run-dep This corresponds to conda's `run_constrained` package metadata. +## Conditional Dependencies + +Any of the dependency tables above can hold dependencies that only apply when a condition holds. +Write the condition as an `if()` key inside the dependency table: + +```toml +# Only needed when cross-compiling (host platform differs from build platform). +[package.build-dependencies."if(host_platform != build_platform)"] +cross-python = "*" + +# Only on Linux. +[package.host-dependencies."if(host_platform == 'linux-64')"] +libgl-devel = ">=1.7.0,<2" + +# Based on a build variant. +[package.host-dependencies."if(matches(python, '>=3.10'))"] +exceptiongroup = "*" +``` + +The expression is passed through verbatim to the build-backend. +At the time of this writing all build backends are backed by [rattler-build](https://rattler.build), so any selector it understands works, including the boolean operators `and`, `or` and `not`. +Three platform variables are available: + +- `build_platform`: the platform the build runs on. +- `host_platform`: the platform the package is built for. + Differs from `build_platform` when cross-compiling. +- `target_platform`: the run platform. + Differs from `host_platform` for `noarch` packages. + +The platform families `unix`, `linux`, `win` and `osx` are also available as bare booleans, e.g. `if(unix)`. + +!!! note + `if(...)` conditions are only available in the `[package]` dependency tables. + The workspace `[target.*]` tables continue to accept platform names only. + ## Inheriting Versions From the Workspace When several packages in the same workspace share dependency versions you can diff --git a/schema/examples/invalid/package_target_removed.toml b/schema/examples/invalid/package_target_removed.toml new file mode 100644 index 0000000000..20df59edca --- /dev/null +++ b/schema/examples/invalid/package_target_removed.toml @@ -0,0 +1,19 @@ +#:schema ./../../schema.json +[project] +channels = ["conda-forge"] +name = "project" +platforms = ["linux-64"] +preview = ["pixi-build"] + +[package] +name = "project" +version = "0.1.0" + +[package.build.backend] +name = "pixi-build-python" +version = "*" + +# The `[package.target.*]` syntax has been removed from the schema in favor of +# `[package.
."if(...)"]` conditional dependency tables. +[package.target.linux-64.host-dependencies] +foo = "*" diff --git a/schema/examples/valid/full.toml b/schema/examples/valid/full.toml index 46e32c6aab..604c9aaf6d 100644 --- a/schema/examples/valid/full.toml +++ b/schema/examples/valid/full.toml @@ -98,13 +98,13 @@ test1 = "*" [package.run-dependencies] test1 = "*" -[package.target.osx-64.host-dependencies] +[package.host-dependencies."if(host_platform == 'osx-64')"] package1 = { version = ">=1.2.3", build = "py34_0" } pytorch-cpu = { version = "~=1.1", channel = "pytorch" } test = "*" test1 = "*" -[package.target.linux-64.run-dependencies] +[package.run-dependencies."if(host_platform == 'linux-64')"] test = "*" [tasks] diff --git a/schema/model.py b/schema/model.py index 868eeb33ef..4282562f6a 100644 --- a/schema/model.py +++ b/schema/model.py @@ -593,6 +593,21 @@ class PyPIVersion(_PyPIRequirement): InheritableDependencies = dict[CondaPackageName, InheritableMatchSpec] | None ExtraDependencies = dict[ExtraName, dict[CondaPackageName, MatchSpec]] | None +# Package dependency tables additionally accept conditional sub-tables keyed by +# `if()`, whose value is a nested dependency map. The expression is +# passed through to rattler-build. Package names cannot contain `(`, so the two +# forms never collide. +ConditionalInheritableDependencies = ( + dict[ + CondaPackageName, + InheritableMatchSpec | dict[CondaPackageName, InheritableMatchSpec], + ] + | None +) +ConditionalExtraDependencies = ( + dict[ExtraName, dict[CondaPackageName, MatchSpec | dict[CondaPackageName, MatchSpec]]] | None +) + ################ # Task section # @@ -1026,21 +1041,15 @@ class Package(StrictBaseModel): build: Build = Field(..., description="The build configuration of the package") - host_dependencies: InheritableDependencies = HostDependenciesField - build_dependencies: InheritableDependencies = BuildDependenciesField - run_dependencies: InheritableDependencies = RunDependenciesField - extra_dependencies: ExtraDependencies = Field( + host_dependencies: ConditionalInheritableDependencies = HostDependenciesField + build_dependencies: ConditionalInheritableDependencies = BuildDependenciesField + run_dependencies: ConditionalInheritableDependencies = RunDependenciesField + extra_dependencies: ConditionalExtraDependencies = Field( None, description="Extra groups that can be requested through MatchSpec extras. Each group uses the same conda package specification syntax as run-dependencies.", examples=[{"test": {"pytest": ">=8", "hypothesis": "*"}}], ) - run_constraints: InheritableDependencies = RunConstraintsField - - target: dict[TargetName, PackageTarget] | None = Field( - None, - description="Machine-specific aspects of the package", - examples=[{"linux": {"host-dependencies": {"python": "3.8"}}}], - ) + run_constraints: ConditionalInheritableDependencies = RunConstraintsField class BuildTarget(StrictBaseModel): @@ -1135,18 +1144,6 @@ class BuildBackend(BinaryMatchspecTable): ) -class PackageTarget(StrictBaseModel): - run_dependencies: InheritableDependencies = RunDependenciesField - run_constraints: InheritableDependencies = RunConstraintsField - host_dependencies: InheritableDependencies = HostDependenciesField - build_dependencies: InheritableDependencies = BuildDependenciesField - extra_dependencies: ExtraDependencies = Field( - None, - description="Extra groups for this target. Same shape as the top-level `extra-dependencies`, but scoped to the matching platform selector.", - examples=[{"test": {"pytest": ">=8"}}], - ) - - ####################### # The Manifest itself # ####################### diff --git a/schema/pixi_build_api.json b/schema/pixi_build_api.json index b92c985771..5b8713f081 100644 --- a/schema/pixi_build_api.json +++ b/schema/pixi_build_api.json @@ -141,7 +141,17 @@ ] }, "targets": { - "description": "We use an [`OrderMap`] to preserve the order in which the items where\ndefined in the manifest.", + "description": "Platform-specific targets.\n\n# Deprecated\n\nThese correspond to the deprecated `[package.target.]` tables\nand will be removed in a future version. Use [`Targets::conditional`]\n(`if()` dependencies) instead.\n\nWe use an [`OrderMap`] to preserve the order in which the items where\ndefined in the manifest.", + "type": [ + "object", + "null" + ], + "additionalProperties": { + "$ref": "#/$defs/Target" + } + }, + "conditional": { + "description": "Conditional `if()` dependencies. The expression is passed\nthrough to rattler-build, which evaluates it; pixi does not. Keyed by the\nbare inner expression without the `if(...)` wrapper.", "type": [ "object", "null" diff --git a/schema/pyproject/partial-pixi.json b/schema/pyproject/partial-pixi.json index b2a487ecf2..f3c2b1b7c2 100644 --- a/schema/pyproject/partial-pixi.json +++ b/schema/pyproject/partial-pixi.json @@ -1431,6 +1431,23 @@ }, { "$ref": "#/$defs/InheritableMatchspecTable" + }, + { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string", + "minLength": 1 + }, + { + "$ref": "#/$defs/InheritableMatchspecTable" + } + ] + }, + "propertyNames": { + "minLength": 1 + } } ] }, @@ -1480,6 +1497,23 @@ }, { "$ref": "#/$defs/MatchspecTable" + }, + { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string", + "minLength": 1 + }, + { + "$ref": "#/$defs/MatchspecTable" + } + ] + }, + "propertyNames": { + "minLength": 1 + } } ] }, @@ -1523,6 +1557,23 @@ }, { "$ref": "#/$defs/InheritableMatchspecTable" + }, + { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string", + "minLength": 1 + }, + { + "$ref": "#/$defs/InheritableMatchspecTable" + } + ] + }, + "propertyNames": { + "minLength": 1 + } } ] }, @@ -1613,6 +1664,23 @@ }, { "$ref": "#/$defs/InheritableMatchspecTable" + }, + { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string", + "minLength": 1 + }, + { + "$ref": "#/$defs/InheritableMatchspecTable" + } + ] + }, + "propertyNames": { + "minLength": 1 + } } ] }, @@ -1632,6 +1700,23 @@ }, { "$ref": "#/$defs/InheritableMatchspecTable" + }, + { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string", + "minLength": 1 + }, + { + "$ref": "#/$defs/InheritableMatchspecTable" + } + ] + }, + "propertyNames": { + "minLength": 1 + } } ] }, @@ -1639,26 +1724,6 @@ "minLength": 1 } }, - "target": { - "title": "Target", - "description": "Machine-specific aspects of the package", - "type": "object", - "additionalProperties": { - "$ref": "#/$defs/PackageTarget" - }, - "propertyNames": { - "minLength": 1 - }, - "examples": [ - { - "linux": { - "host-dependencies": { - "python": "3.8" - } - } - } - ] - }, "version": { "title": "Version", "description": "The version of the project; we advise use of [SemVer](https://semver.org). Can be a string or { workspace = true } to inherit from workspace", @@ -1680,125 +1745,6 @@ } } }, - "PackageTarget": { - "title": "PackageTarget", - "type": "object", - "additionalProperties": false, - "properties": { - "build-dependencies": { - "title": "Build-Dependencies", - "description": "The build `conda` dependencies, used in the build process. See https://pixi.sh/latest/build/dependency_types/ for more information.", - "type": "object", - "additionalProperties": { - "anyOf": [ - { - "type": "string", - "minLength": 1 - }, - { - "$ref": "#/$defs/InheritableMatchspecTable" - } - ] - }, - "propertyNames": { - "minLength": 1 - } - }, - "extra-dependencies": { - "title": "Extra-Dependencies", - "description": "Extra groups for this target. Same shape as the top-level `extra-dependencies`, but scoped to the matching platform selector.", - "type": "object", - "patternProperties": { - "^[a-z0-9._+-]{1,64}$": { - "type": "object", - "additionalProperties": { - "anyOf": [ - { - "type": "string", - "minLength": 1 - }, - { - "$ref": "#/$defs/MatchspecTable" - } - ] - }, - "propertyNames": { - "minLength": 1 - } - } - }, - "examples": [ - { - "test": { - "pytest": ">=8" - } - } - ] - }, - "host-dependencies": { - "title": "Host-Dependencies", - "description": "The host `conda` dependencies, used in the build process. See https://pixi.sh/latest/build/dependency_types/ for more information.", - "type": "object", - "additionalProperties": { - "anyOf": [ - { - "type": "string", - "minLength": 1 - }, - { - "$ref": "#/$defs/InheritableMatchspecTable" - } - ] - }, - "propertyNames": { - "minLength": 1 - }, - "examples": [ - { - "python": ">=3.8" - } - ] - }, - "run-constraints": { - "title": "Run-Constraints", - "description": "The `conda` run-time version constraints. These constrain the versions of packages that may be installed in the run environment without explicitly requiring them. If the package is installed as a dependency of another package, it must satisfy these constraints. See https://pixi.sh/latest/build/dependency_types/ for more information.", - "type": "object", - "additionalProperties": { - "anyOf": [ - { - "type": "string", - "minLength": 1 - }, - { - "$ref": "#/$defs/InheritableMatchspecTable" - } - ] - }, - "propertyNames": { - "minLength": 1 - } - }, - "run-dependencies": { - "title": "Run-Dependencies", - "description": "The `conda` dependencies required at runtime. See https://pixi.sh/latest/build/dependency_types/ for more information.", - "type": "object", - "additionalProperties": { - "anyOf": [ - { - "type": "string", - "minLength": 1 - }, - { - "$ref": "#/$defs/InheritableMatchspecTable" - } - ] - }, - "propertyNames": { - "minLength": 1 - } - } - } - }, "Platform": { "title": "Platform", "description": "A supported operating system and processor architecture pair.", diff --git a/schema/pyproject/schema.json b/schema/pyproject/schema.json index d105b79001..4fc68bf1a3 100644 --- a/schema/pyproject/schema.json +++ b/schema/pyproject/schema.json @@ -1174,6 +1174,23 @@ }, { "$ref": "#/$defs/InheritableMatchspecTable" + }, + { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string", + "minLength": 1 + }, + { + "$ref": "#/$defs/InheritableMatchspecTable" + } + ] + }, + "propertyNames": { + "minLength": 1 + } } ] }, @@ -1223,6 +1240,23 @@ }, { "$ref": "#/$defs/MatchspecTable" + }, + { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string", + "minLength": 1 + }, + { + "$ref": "#/$defs/MatchspecTable" + } + ] + }, + "propertyNames": { + "minLength": 1 + } } ] }, @@ -1266,6 +1300,23 @@ }, { "$ref": "#/$defs/InheritableMatchspecTable" + }, + { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string", + "minLength": 1 + }, + { + "$ref": "#/$defs/InheritableMatchspecTable" + } + ] + }, + "propertyNames": { + "minLength": 1 + } } ] }, @@ -1356,6 +1407,23 @@ }, { "$ref": "#/$defs/InheritableMatchspecTable" + }, + { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string", + "minLength": 1 + }, + { + "$ref": "#/$defs/InheritableMatchspecTable" + } + ] + }, + "propertyNames": { + "minLength": 1 + } } ] }, @@ -1375,6 +1443,23 @@ }, { "$ref": "#/$defs/InheritableMatchspecTable" + }, + { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string", + "minLength": 1 + }, + { + "$ref": "#/$defs/InheritableMatchspecTable" + } + ] + }, + "propertyNames": { + "minLength": 1 + } } ] }, @@ -1382,26 +1467,6 @@ "minLength": 1 } }, - "target": { - "title": "Target", - "description": "Machine-specific aspects of the package", - "type": "object", - "additionalProperties": { - "$ref": "#/$defs/PackageTarget" - }, - "propertyNames": { - "minLength": 1 - }, - "examples": [ - { - "linux": { - "host-dependencies": { - "python": "3.8" - } - } - } - ] - }, "version": { "title": "Version", "description": "The version of the project; we advise use of [SemVer](https://semver.org). Can be a string or { workspace = true } to inherit from workspace", @@ -1423,125 +1488,6 @@ } } }, - "PackageTarget": { - "title": "PackageTarget", - "type": "object", - "additionalProperties": false, - "properties": { - "build-dependencies": { - "title": "Build-Dependencies", - "description": "The build `conda` dependencies, used in the build process. See https://pixi.sh/latest/build/dependency_types/ for more information.", - "type": "object", - "additionalProperties": { - "anyOf": [ - { - "type": "string", - "minLength": 1 - }, - { - "$ref": "#/$defs/InheritableMatchspecTable" - } - ] - }, - "propertyNames": { - "minLength": 1 - } - }, - "extra-dependencies": { - "title": "Extra-Dependencies", - "description": "Extra groups for this target. Same shape as the top-level `extra-dependencies`, but scoped to the matching platform selector.", - "type": "object", - "patternProperties": { - "^[a-z0-9._+-]{1,64}$": { - "type": "object", - "additionalProperties": { - "anyOf": [ - { - "type": "string", - "minLength": 1 - }, - { - "$ref": "#/$defs/MatchspecTable" - } - ] - }, - "propertyNames": { - "minLength": 1 - } - } - }, - "examples": [ - { - "test": { - "pytest": ">=8" - } - } - ] - }, - "host-dependencies": { - "title": "Host-Dependencies", - "description": "The host `conda` dependencies, used in the build process. See https://pixi.sh/latest/build/dependency_types/ for more information.", - "type": "object", - "additionalProperties": { - "anyOf": [ - { - "type": "string", - "minLength": 1 - }, - { - "$ref": "#/$defs/InheritableMatchspecTable" - } - ] - }, - "propertyNames": { - "minLength": 1 - }, - "examples": [ - { - "python": ">=3.8" - } - ] - }, - "run-constraints": { - "title": "Run-Constraints", - "description": "The `conda` run-time version constraints. These constrain the versions of packages that may be installed in the run environment without explicitly requiring them. If the package is installed as a dependency of another package, it must satisfy these constraints. See https://pixi.sh/latest/build/dependency_types/ for more information.", - "type": "object", - "additionalProperties": { - "anyOf": [ - { - "type": "string", - "minLength": 1 - }, - { - "$ref": "#/$defs/InheritableMatchspecTable" - } - ] - }, - "propertyNames": { - "minLength": 1 - } - }, - "run-dependencies": { - "title": "Run-Dependencies", - "description": "The `conda` dependencies required at runtime. See https://pixi.sh/latest/build/dependency_types/ for more information.", - "type": "object", - "additionalProperties": { - "anyOf": [ - { - "type": "string", - "minLength": 1 - }, - { - "$ref": "#/$defs/InheritableMatchspecTable" - } - ] - }, - "propertyNames": { - "minLength": 1 - } - } - } - }, "Platform": { "title": "Platform", "description": "A supported operating system and processor architecture pair.", diff --git a/schema/schema.json b/schema/schema.json index 07fe92b5c6..ae1ce6e22f 100644 --- a/schema/schema.json +++ b/schema/schema.json @@ -1455,6 +1455,23 @@ }, { "$ref": "#/$defs/InheritableMatchspecTable" + }, + { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string", + "minLength": 1 + }, + { + "$ref": "#/$defs/InheritableMatchspecTable" + } + ] + }, + "propertyNames": { + "minLength": 1 + } } ] }, @@ -1504,6 +1521,23 @@ }, { "$ref": "#/$defs/MatchspecTable" + }, + { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string", + "minLength": 1 + }, + { + "$ref": "#/$defs/MatchspecTable" + } + ] + }, + "propertyNames": { + "minLength": 1 + } } ] }, @@ -1547,6 +1581,23 @@ }, { "$ref": "#/$defs/InheritableMatchspecTable" + }, + { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string", + "minLength": 1 + }, + { + "$ref": "#/$defs/InheritableMatchspecTable" + } + ] + }, + "propertyNames": { + "minLength": 1 + } } ] }, @@ -1637,6 +1688,23 @@ }, { "$ref": "#/$defs/InheritableMatchspecTable" + }, + { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string", + "minLength": 1 + }, + { + "$ref": "#/$defs/InheritableMatchspecTable" + } + ] + }, + "propertyNames": { + "minLength": 1 + } } ] }, @@ -1656,6 +1724,23 @@ }, { "$ref": "#/$defs/InheritableMatchspecTable" + }, + { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string", + "minLength": 1 + }, + { + "$ref": "#/$defs/InheritableMatchspecTable" + } + ] + }, + "propertyNames": { + "minLength": 1 + } } ] }, @@ -1663,26 +1748,6 @@ "minLength": 1 } }, - "target": { - "title": "Target", - "description": "Machine-specific aspects of the package", - "type": "object", - "additionalProperties": { - "$ref": "#/$defs/PackageTarget" - }, - "propertyNames": { - "minLength": 1 - }, - "examples": [ - { - "linux": { - "host-dependencies": { - "python": "3.8" - } - } - } - ] - }, "version": { "title": "Version", "description": "The version of the project; we advise use of [SemVer](https://semver.org). Can be a string or { workspace = true } to inherit from workspace", @@ -1704,125 +1769,6 @@ } } }, - "PackageTarget": { - "title": "PackageTarget", - "type": "object", - "additionalProperties": false, - "properties": { - "build-dependencies": { - "title": "Build-Dependencies", - "description": "The build `conda` dependencies, used in the build process. See https://pixi.sh/latest/build/dependency_types/ for more information.", - "type": "object", - "additionalProperties": { - "anyOf": [ - { - "type": "string", - "minLength": 1 - }, - { - "$ref": "#/$defs/InheritableMatchspecTable" - } - ] - }, - "propertyNames": { - "minLength": 1 - } - }, - "extra-dependencies": { - "title": "Extra-Dependencies", - "description": "Extra groups for this target. Same shape as the top-level `extra-dependencies`, but scoped to the matching platform selector.", - "type": "object", - "patternProperties": { - "^[a-z0-9._+-]{1,64}$": { - "type": "object", - "additionalProperties": { - "anyOf": [ - { - "type": "string", - "minLength": 1 - }, - { - "$ref": "#/$defs/MatchspecTable" - } - ] - }, - "propertyNames": { - "minLength": 1 - } - } - }, - "examples": [ - { - "test": { - "pytest": ">=8" - } - } - ] - }, - "host-dependencies": { - "title": "Host-Dependencies", - "description": "The host `conda` dependencies, used in the build process. See https://pixi.sh/latest/build/dependency_types/ for more information.", - "type": "object", - "additionalProperties": { - "anyOf": [ - { - "type": "string", - "minLength": 1 - }, - { - "$ref": "#/$defs/InheritableMatchspecTable" - } - ] - }, - "propertyNames": { - "minLength": 1 - }, - "examples": [ - { - "python": ">=3.8" - } - ] - }, - "run-constraints": { - "title": "Run-Constraints", - "description": "The `conda` run-time version constraints. These constrain the versions of packages that may be installed in the run environment without explicitly requiring them. If the package is installed as a dependency of another package, it must satisfy these constraints. See https://pixi.sh/latest/build/dependency_types/ for more information.", - "type": "object", - "additionalProperties": { - "anyOf": [ - { - "type": "string", - "minLength": 1 - }, - { - "$ref": "#/$defs/InheritableMatchspecTable" - } - ] - }, - "propertyNames": { - "minLength": 1 - } - }, - "run-dependencies": { - "title": "Run-Dependencies", - "description": "The `conda` dependencies required at runtime. See https://pixi.sh/latest/build/dependency_types/ for more information.", - "type": "object", - "additionalProperties": { - "anyOf": [ - { - "type": "string", - "minLength": 1 - }, - { - "$ref": "#/$defs/InheritableMatchspecTable" - } - ] - }, - "propertyNames": { - "minLength": 1 - } - } - } - }, "Platform": { "title": "Platform", "description": "A supported operating system and processor architecture pair.", diff --git a/tests/data/pixi-build/rattler-build-backend/smokey2/pixi.toml b/tests/data/pixi-build/rattler-build-backend/smokey2/pixi.toml index 8235351bc5..db963d9060 100644 --- a/tests/data/pixi-build/rattler-build-backend/smokey2/pixi.toml +++ b/tests/data/pixi-build/rattler-build-backend/smokey2/pixi.toml @@ -21,5 +21,5 @@ name = "pixi-build-rattler-build" version = "*" # No deps for default target, but dep for linux64 target -[package.target.linux-64.host-dependencies] +[package.host-dependencies."if(host_platform == 'linux-64')"] hatchling = "*" diff --git a/tests/data/pixi-build/target-specific/pixi.toml b/tests/data/pixi-build/target-specific/pixi.toml index 1c6422d105..a5064b9181 100644 --- a/tests/data/pixi-build/target-specific/pixi.toml +++ b/tests/data/pixi-build/target-specific/pixi.toml @@ -19,8 +19,8 @@ version = "*" hatchling = "*" # Add packages that would be unavailable for the wrong target -[package.target.unix.host-dependencies] +[package.host-dependencies."if(unix)"] package-unix = "*" -[package.target.win-64.host-dependencies] +[package.host-dependencies."if(host_platform == 'win-64')"] package-windows = "*" From e54e64663e797009df562705bf2f7d83d24ee748 Mon Sep 17 00:00:00 2001 From: Ruben Arts Date: Mon, 8 Jun 2026 17:07:31 +0200 Subject: [PATCH 2/4] feat: add cuda_probe example with conditional dependencies --- .../conditional-dependencies/.gitattributes | 2 + .../conditional-dependencies/.gitignore | 3 + .../conditional-dependencies/CMakeLists.txt | 25 + .../conditional-dependencies/README.md | 34 + .../conditional-dependencies/pixi.lock | 2912 +++++++++++++++++ .../conditional-dependencies/pixi.toml | 33 + .../conditional-dependencies/src/main.cc | 35 + 7 files changed, 3044 insertions(+) create mode 100644 examples/pixi-build/conditional-dependencies/.gitattributes create mode 100644 examples/pixi-build/conditional-dependencies/.gitignore create mode 100644 examples/pixi-build/conditional-dependencies/CMakeLists.txt create mode 100644 examples/pixi-build/conditional-dependencies/README.md create mode 100644 examples/pixi-build/conditional-dependencies/pixi.lock create mode 100644 examples/pixi-build/conditional-dependencies/pixi.toml create mode 100644 examples/pixi-build/conditional-dependencies/src/main.cc diff --git a/examples/pixi-build/conditional-dependencies/.gitattributes b/examples/pixi-build/conditional-dependencies/.gitattributes new file mode 100644 index 0000000000..997504b465 --- /dev/null +++ b/examples/pixi-build/conditional-dependencies/.gitattributes @@ -0,0 +1,2 @@ +# SCM syntax highlighting & preventing 3-way merges +pixi.lock merge=binary linguist-language=YAML linguist-generated=true -diff diff --git a/examples/pixi-build/conditional-dependencies/.gitignore b/examples/pixi-build/conditional-dependencies/.gitignore new file mode 100644 index 0000000000..ae849e65b8 --- /dev/null +++ b/examples/pixi-build/conditional-dependencies/.gitignore @@ -0,0 +1,3 @@ +# pixi environments +.pixi/* +!.pixi/config.toml diff --git a/examples/pixi-build/conditional-dependencies/CMakeLists.txt b/examples/pixi-build/conditional-dependencies/CMakeLists.txt new file mode 100644 index 0000000000..20f17563d9 --- /dev/null +++ b/examples/pixi-build/conditional-dependencies/CMakeLists.txt @@ -0,0 +1,25 @@ +cmake_minimum_required(VERSION 3.18) +project(cuda_probe LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") + +add_executable(cuda_probe src/main.cc) + +# The CUDA runtime is only pulled in as a host-dependency on platforms where +# conda-forge ships it (see the `if(...)` block in pixi.toml). When it is +# present we light up the CUDA code path; otherwise we build a CPU-only binary +# from the exact same sources. +find_package(CUDAToolkit QUIET) +if(CUDAToolkit_FOUND) + message(STATUS "CUDA toolkit ${CUDAToolkit_VERSION} found, enabling CUDA support") + target_compile_definitions(cuda_probe PRIVATE + HAS_CUDA + CUDA_VERSION_STRING="${CUDAToolkit_VERSION}") + target_link_libraries(cuda_probe PRIVATE CUDA::cudart) +else() + message(STATUS "No CUDA toolkit found, building CPU-only") +endif() + +include(GNUInstallDirs) +install(TARGETS cuda_probe RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/examples/pixi-build/conditional-dependencies/README.md b/examples/pixi-build/conditional-dependencies/README.md new file mode 100644 index 0000000000..5c87c27097 --- /dev/null +++ b/examples/pixi-build/conditional-dependencies/README.md @@ -0,0 +1,34 @@ +# Conditional dependencies + +A minimal C++ package that shows off `if(...)` conditional dependencies in a +Pixi `[package]` section. + +`cuda_probe` is a tiny executable that reports which compiler built it and +whether it was compiled with CUDA support. The CUDA runtime is only available +on conda-forge for Linux and Windows, so the manifest asks for it only there: + +```toml +[package.host-dependencies."if(linux or win)"] +cuda-version = "12.*" +cuda-cudart-dev = "12.*" +``` + +On Linux/Windows the build links against the CUDA runtime and the program +queries the visible device count. On macOS the block is skipped entirely and +the very same sources build a CPU-only binary. + +## Run it + +```bash +pixi run start +``` + +On a machine without conditional-dependency support you would instead see the +old `[package.target.*]` tables. The `if()` form accepts anything +rattler-build understands (`and`, `or`, `not`, `matches(...)`, ...) and exposes +these variables: + +- `build_platform` the platform the build runs on +- `host_platform` the platform the package is built for (differs when cross-compiling) +- `target_platform` the run platform (differs from `host_platform` for `noarch`) +- the bare booleans `unix`, `linux`, `win` and `osx` diff --git a/examples/pixi-build/conditional-dependencies/pixi.lock b/examples/pixi-build/conditional-dependencies/pixi.lock new file mode 100644 index 0000000000..75939b8de1 --- /dev/null +++ b/examples/pixi-build/conditional-dependencies/pixi.lock @@ -0,0 +1,2912 @@ +version: 7 +platforms: +- name: linux-64 +- name: osx-64 +- name: osx-arm64 +- name: win-64 +environments: + default: + channels: + - url: https://prefix.dev/pixi-build-backends/ + - url: https://prefix.dev/conda-forge/ + packages: + linux-64: + - conda: https://prefix.dev/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda + - conda: https://prefix.dev/conda-forge/linux-64/binutils_impl_linux-64-2.45.1-default_hfdba357_102.conda + - conda: https://prefix.dev/conda-forge/linux-64/binutils_linux-64-2.45.1-default_h4852527_102.conda + - conda: https://prefix.dev/conda-forge/linux-64/cuda-crt-tools-12.9.86-ha770c72_2.conda + - conda: https://prefix.dev/conda-forge/linux-64/cuda-cudart-12.9.79-h5888daf_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/cuda-cudart-dev-12.9.79-h5888daf_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/cuda-cudart-static-12.9.79-h5888daf_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/cuda-nvcc-12.9.86-hcdd1206_6.conda + - conda: https://prefix.dev/conda-forge/linux-64/cuda-nvcc-impl-12.9.86-h85509e4_2.conda + - conda: https://prefix.dev/conda-forge/linux-64/cuda-nvcc-tools-12.9.86-he02047a_2.conda + - conda: https://prefix.dev/conda-forge/linux-64/cuda-nvcc_linux-64-12.9.86-he0b4e1d_6.conda + - conda: https://prefix.dev/conda-forge/linux-64/cuda-nvvm-impl-12.9.86-h4bc722e_2.conda + - conda: https://prefix.dev/conda-forge/linux-64/cuda-nvvm-tools-12.9.86-h4bc722e_2.conda + - conda: https://prefix.dev/conda-forge/linux-64/gcc_impl_linux-64-14.3.0-h235f0fe_19.conda + - conda: https://prefix.dev/conda-forge/linux-64/gcc_linux-64-14.3.0-h50e9bb6_25.conda + - conda: https://prefix.dev/conda-forge/linux-64/gxx_impl_linux-64-14.3.0-h2185e75_19.conda + - conda: https://prefix.dev/conda-forge/linux-64/gxx_linux-64-14.3.0-h72ca5df_25.conda + - conda: https://prefix.dev/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_102.conda + - conda: https://prefix.dev/conda-forge/linux-64/libgcc-15.2.0-he0feb66_19.conda + - conda: https://prefix.dev/conda-forge/linux-64/libgomp-15.2.0-he0feb66_19.conda + - conda: https://prefix.dev/conda-forge/linux-64/libnvptxcompiler-dev-12.9.86-ha770c72_2.conda + - conda: https://prefix.dev/conda-forge/linux-64/libsanitizer-14.3.0-h8f1669f_19.conda + - conda: https://prefix.dev/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_19.conda + - conda: https://prefix.dev/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_2.conda + - conda: https://prefix.dev/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda + - conda: https://prefix.dev/conda-forge/noarch/cuda-cccl_linux-64-12.9.27-ha770c72_0.conda + - conda: https://prefix.dev/conda-forge/noarch/cuda-crt-dev_linux-64-12.9.86-ha770c72_2.conda + - conda: https://prefix.dev/conda-forge/noarch/cuda-cudart-dev_linux-64-12.9.79-h3f2d84a_0.conda + - conda: https://prefix.dev/conda-forge/noarch/cuda-cudart-static_linux-64-12.9.79-h3f2d84a_0.conda + - conda: https://prefix.dev/conda-forge/noarch/cuda-cudart_linux-64-12.9.79-h3f2d84a_0.conda + - conda: https://prefix.dev/conda-forge/noarch/cuda-driver-dev_linux-64-12.9.79-h3f2d84a_0.conda + - conda: https://prefix.dev/conda-forge/noarch/cuda-nvcc-dev_linux-64-12.9.86-he91c749_2.conda + - conda: https://prefix.dev/conda-forge/noarch/cuda-nvvm-dev_linux-64-12.9.86-ha770c72_2.conda + - conda: https://prefix.dev/conda-forge/noarch/cuda-version-12.9-h4f385c5_3.conda + - conda: https://prefix.dev/conda-forge/noarch/kernel-headers_linux-64-4.18.0-he073ed8_9.conda + - conda: https://prefix.dev/conda-forge/noarch/libgcc-devel_linux-64-14.3.0-hf649bbc_119.conda + - conda: https://prefix.dev/conda-forge/noarch/libnvptxcompiler-dev_linux-64-12.9.86-ha770c72_2.conda + - conda: https://prefix.dev/conda-forge/noarch/libstdcxx-devel_linux-64-14.3.0-h9f08a49_119.conda + - conda: https://prefix.dev/conda-forge/noarch/sysroot_linux-64-2.28-h4ee821c_9.conda + - conda: https://prefix.dev/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + - conda_source: cuda_probe[139d67dc] @ . + osx-64: + - conda: https://prefix.dev/conda-forge/osx-64/libcxx-22.1.7-h19cb2f5_0.conda + - conda_source: cuda_probe[d2e722fe] @ . + osx-arm64: + - conda: https://prefix.dev/conda-forge/osx-arm64/libcxx-22.1.7-h55c6f16_0.conda + - conda_source: cuda_probe[b008fffd] @ . + win-64: + - conda: https://prefix.dev/conda-forge/noarch/cuda-cccl_win-64-12.9.27-h57928b3_0.conda + - conda: https://prefix.dev/conda-forge/noarch/cuda-crt-dev_win-64-12.9.86-h57928b3_2.conda + - conda: https://prefix.dev/conda-forge/noarch/cuda-cudart-dev_win-64-12.9.79-he0c23c2_0.conda + - conda: https://prefix.dev/conda-forge/noarch/cuda-cudart-static_win-64-12.9.79-he0c23c2_0.conda + - conda: https://prefix.dev/conda-forge/noarch/cuda-cudart_win-64-12.9.79-he0c23c2_0.conda + - conda: https://prefix.dev/conda-forge/noarch/cuda-nvcc-dev_win-64-12.9.86-h36c15f3_2.conda + - conda: https://prefix.dev/conda-forge/noarch/cuda-nvvm-dev_win-64-12.9.86-h57928b3_2.conda + - conda: https://prefix.dev/conda-forge/noarch/cuda-version-12.9-h4f385c5_3.conda + - conda: https://prefix.dev/conda-forge/noarch/libnvptxcompiler-dev_win-64-12.9.86-h57928b3_2.conda + - conda: https://prefix.dev/conda-forge/noarch/vswhere-3.1.7-h40126e0_1.conda + - conda: https://prefix.dev/conda-forge/win-64/cuda-crt-tools-12.9.86-h57928b3_2.conda + - conda: https://prefix.dev/conda-forge/win-64/cuda-cudart-12.9.79-he0c23c2_0.conda + - conda: https://prefix.dev/conda-forge/win-64/cuda-cudart-dev-12.9.79-he0c23c2_0.conda + - conda: https://prefix.dev/conda-forge/win-64/cuda-cudart-static-12.9.79-he0c23c2_0.conda + - conda: https://prefix.dev/conda-forge/win-64/cuda-nvcc-12.9.86-h8f04d04_6.conda + - conda: https://prefix.dev/conda-forge/win-64/cuda-nvcc-impl-12.9.86-h53cbb54_2.conda + - conda: https://prefix.dev/conda-forge/win-64/cuda-nvcc-tools-12.9.86-he0c23c2_2.conda + - conda: https://prefix.dev/conda-forge/win-64/cuda-nvcc_win-64-12.9.86-hd70436c_6.conda + - conda: https://prefix.dev/conda-forge/win-64/cuda-nvvm-impl-12.9.86-h2466b09_2.conda + - conda: https://prefix.dev/conda-forge/win-64/cuda-nvvm-tools-12.9.86-h2466b09_2.conda + - conda: https://prefix.dev/conda-forge/win-64/libnvptxcompiler-dev-12.9.86-h57928b3_2.conda + - conda: https://prefix.dev/conda-forge/win-64/ucrt-10.0.26100.0-h57928b3_0.conda + - conda: https://prefix.dev/conda-forge/win-64/vc-14.5-h1b7c187_38.conda + - conda: https://prefix.dev/conda-forge/win-64/vc14_runtime-14.51.36231-h1b9f54f_38.conda + - conda: https://prefix.dev/conda-forge/win-64/vcomp14-14.51.36231-h1b9f54f_38.conda + - conda: https://prefix.dev/conda-forge/win-64/vs2019_win-64-19.29.30139-h7dcff83_38.conda + - conda_source: cuda_probe[239c2f87] @ . +packages: +- conda: https://prefix.dev/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda + build_number: 20 + sha256: 1dd3fffd892081df9726d7eb7e0dea6198962ba775bd88842135a4ddb4deb3c9 + md5: a9f577daf3de00bca7c3c76c0ecbd1de + depends: + - __glibc >=2.17,<3.0.a0 + - libgomp >=7.5.0 + constrains: + - openmp_impl <0.0a0 + license: BSD-3-Clause + license_family: BSD + run_exports: + strong: + - _openmp_mutex >=4.5 + size: 28948 + timestamp: 1770939786096 +- conda: https://prefix.dev/conda-forge/linux-64/binutils_impl_linux-64-2.45.1-default_hfdba357_102.conda + sha256: 0a7d405064f53b9d91d92515f1460f7906ee5e8523f3cd8973430e81219f4917 + md5: 8165352fdce2d2025bf884dc0ee85700 + depends: + - ld_impl_linux-64 2.45.1 default_hbd61a6d_102 + - sysroot_linux-64 + - zstd >=1.5.7,<1.6.0a0 + license: GPL-3.0-only + license_family: GPL + run_exports: {} + size: 3661455 + timestamp: 1774197460085 +- conda: https://prefix.dev/conda-forge/linux-64/binutils_linux-64-2.45.1-default_h4852527_102.conda + sha256: 78a58d523d072b7f8e591b8f8572822e044b31764ed7e8d170392e7bc6d58339 + md5: 2a307a17309d358c9b42afdd3199ddcc + depends: + - binutils_impl_linux-64 2.45.1 default_hfdba357_102 + license: GPL-3.0-only + license_family: GPL + run_exports: {} + size: 36304 + timestamp: 1774197485247 +- conda: https://prefix.dev/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda + sha256: 0b75d45f0bba3e95dc693336fa51f40ea28c980131fec438afb7ce6118ed05f6 + md5: d2ffd7602c02f2b316fd921d39876885 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + license: bzip2-1.0.6 + license_family: BSD + run_exports: + weak: + - bzip2 >=1.0.8,<2.0a0 + size: 260182 + timestamp: 1771350215188 +- conda: https://prefix.dev/conda-forge/linux-64/c-ares-1.34.6-hb03c661_0.conda + sha256: cc9accf72fa028d31c2a038460787751127317dcfa991f8d1f1babf216bb454e + md5: 920bb03579f15389b9e512095ad995b7 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + license: MIT + license_family: MIT + run_exports: + weak: + - c-ares >=1.34.6,<2.0a0 + size: 207882 + timestamp: 1765214722852 +- conda: https://prefix.dev/conda-forge/linux-64/cmake-4.3.3-hc85cc9f_0.conda + sha256: 796276f96ea27acaba1f25755977f6c12dfbc886fd1db713263c795184168f59 + md5: 30a266b5d91bc45fccbcc45588b2db79 + depends: + - __glibc >=2.17,<3.0.a0 + - bzip2 >=1.0.8,<2.0a0 + - libcurl >=8.20.0,<9.0a0 + - libexpat >=2.8.1,<3.0a0 + - libgcc >=14 + - liblzma >=5.8.3,<6.0a0 + - libstdcxx >=14 + - libuv >=1.51.0,<2.0a0 + - libzlib >=1.3.2,<2.0a0 + - ncurses >=6.6,<7.0a0 + - rhash >=1.4.6,<2.0a0 + - zstd >=1.5.7,<1.6.0a0 + license: BSD-3-Clause + license_family: BSD + run_exports: {} + size: 23085721 + timestamp: 1779398000620 +- conda: https://prefix.dev/conda-forge/linux-64/cuda-crt-tools-12.9.86-ha770c72_2.conda + sha256: 2da9964591af14ba11b2379bed01d56e7185260ee0998d1a939add7fb752db45 + md5: 503a94e20d2690d534d676a764a1852c + depends: + - cuda-version >=12.9,<12.10.0a0 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: {} + size: 29138 + timestamp: 1753975252445 +- conda: https://prefix.dev/conda-forge/linux-64/cuda-cudart-12.9.79-h5888daf_0.conda + sha256: 57d1294ecfaf9dc8cdb5fc4be3e63ebc7614538bddb5de53cfd9b1b7de43aed5 + md5: cb15315d19b58bd9cd424084e58ad081 + depends: + - __glibc >=2.17,<3.0.a0 + - cuda-cudart_linux-64 12.9.79 h3f2d84a_0 + - cuda-version >=12.9,<12.10.0a0 + - libgcc >=13 + - libstdcxx >=13 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: {} + size: 23242 + timestamp: 1749218416505 +- conda: https://prefix.dev/conda-forge/linux-64/cuda-cudart-dev-12.9.79-h5888daf_0.conda + sha256: 04d8235cb3cb3510c0492c3515a9d1a6053b50ef39be42b60cafb05044b5f4c6 + md5: ba38a7c3b4c14625de45784b773f0c71 + depends: + - __glibc >=2.17,<3.0.a0 + - cuda-cudart 12.9.79 h5888daf_0 + - cuda-cudart-dev_linux-64 12.9.79 h3f2d84a_0 + - cuda-cudart-static 12.9.79 h5888daf_0 + - cuda-version >=12.9,<12.10.0a0 + - libgcc >=13 + - libstdcxx >=13 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: + weak: + - cuda-cudart >=12.9.79,<13.0a0 + size: 23687 + timestamp: 1749218464010 +- conda: https://prefix.dev/conda-forge/linux-64/cuda-cudart-static-12.9.79-h5888daf_0.conda + sha256: 6261e1d9af80e1ec308e3e5e2ff825d189ef922d24093beaf6efca12e67ce060 + md5: d3c4ac48f4967f09dd910d9c15d40c81 + depends: + - __glibc >=2.17,<3.0.a0 + - cuda-cudart-static_linux-64 12.9.79 h3f2d84a_0 + - cuda-version >=12.9,<12.10.0a0 + - libgcc >=13 + - libstdcxx >=13 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: {} + size: 23283 + timestamp: 1749218442382 +- conda: https://prefix.dev/conda-forge/linux-64/cuda-nvcc-12.9.86-hcdd1206_6.conda + sha256: f7c5de6b1f0f463f73c78cc73439027cdd5cb94fb4ce099116969812973cabcb + md5: 02289b10ac97bac35ad1add086c5072a + depends: + - cuda-nvcc_linux-64 12.9.86.* + - gcc_linux-64 + - gxx_linux-64 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: {} + size: 25472 + timestamp: 1771619493470 +- conda: https://prefix.dev/conda-forge/linux-64/cuda-nvcc-impl-12.9.86-h85509e4_2.conda + sha256: 961cf20d411b7685cd744e6c6ed35efea547d095c62151d6f3053d9931bb994d + md5: 67458d2685e7503933efa550f3ee40f3 + depends: + - cuda-cudart >=12.9.79,<13.0a0 + - cuda-cudart-dev + - cuda-nvcc-dev_linux-64 12.9.86 he91c749_2 + - cuda-nvcc-tools 12.9.86 he02047a_2 + - cuda-nvvm-impl 12.9.86 h4bc722e_2 + - cuda-version >=12.9,<12.10.0a0 + - libnvptxcompiler-dev 12.9.86 ha770c72_2 + constrains: + - gcc_impl_linux-64 >=6,<15.0a0 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: {} + size: 27215 + timestamp: 1753975546846 +- conda: https://prefix.dev/conda-forge/linux-64/cuda-nvcc-tools-12.9.86-he02047a_2.conda + sha256: 0e849be7b5e4832ca218ec2c48a9ba3a15a984f629e2e54f38a53f4f57220341 + md5: dc256c9864c2e8e9c817fbca1c84a4bc + depends: + - __glibc >=2.17,<3.0.a0 + - cuda-crt-tools 12.9.86 ha770c72_2 + - cuda-nvvm-tools 12.9.86 h4bc722e_2 + - cuda-version >=12.9,<12.10.0a0 + - libgcc >=12 + - libstdcxx >=12 + constrains: + - gcc_impl_linux-64 >=6,<15.0a0 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: {} + size: 27380012 + timestamp: 1753975454194 +- conda: https://prefix.dev/conda-forge/linux-64/cuda-nvcc_linux-64-12.9.86-he0b4e1d_6.conda + sha256: c506221dafb7cfd081f7d12d01d8e8ab9b29adfcc7d69d61fedd3232174e4016 + md5: 359d05bc3ec5d3a467eb558e3844aea2 + depends: + - __glibc >=2.17,<3.0.a0 + - cuda-cudart-dev_linux-64 12.9.* + - cuda-driver-dev_linux-64 12.9.* + - cuda-nvcc-dev_linux-64 12.9.86.* + - cuda-nvcc-impl 12.9.86.* + - cuda-nvcc-tools 12.9.86.* + - sysroot_linux-64 >=2.17,<3.0a0 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: + strong: + - cuda-version >=12.9,<13 + size: 27575 + timestamp: 1771619492974 +- conda: https://prefix.dev/conda-forge/linux-64/cuda-nvvm-impl-12.9.86-h4bc722e_2.conda + sha256: f4d34556174e4faa9d374ba2244707082870e1bbc1bb441ad3d9d2cea37da6af + md5: 82125dd3c0c4aa009faa00e2829b93d8 + depends: + - __glibc >=2.17,<3.0.a0 + - cuda-version >=12.9,<12.10.0a0 + - libgcc >=12 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: {} + size: 21425520 + timestamp: 1753975283188 +- conda: https://prefix.dev/conda-forge/linux-64/cuda-nvvm-tools-12.9.86-h4bc722e_2.conda + sha256: 45f5e881ed0d973132a5475a0b5c066db6e748ef3a831a14dba8374b252e0067 + md5: f9af26e4079adcd72688a8e8dbecb229 + depends: + - __glibc >=2.17,<3.0.a0 + - cuda-version >=12.9,<12.10.0a0 + - libgcc >=12 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: {} + size: 24246736 + timestamp: 1753975332907 +- conda: https://prefix.dev/conda-forge/linux-64/gcc_impl_linux-64-14.3.0-h235f0fe_19.conda + sha256: 1e2500ca976d4831c953d1c6db7b238d2e6806910b930e3eb631b79ba5c3ba41 + md5: 99936dc616b7ce97b0468759b8a7c64e + depends: + - binutils_impl_linux-64 >=2.45 + - libgcc >=14.3.0 + - libgcc-devel_linux-64 14.3.0 hf649bbc_119 + - libgomp >=14.3.0 + - libsanitizer 14.3.0 h8f1669f_19 + - libstdcxx >=14.3.0 + - libstdcxx-devel_linux-64 14.3.0 h9f08a49_119 + - sysroot_linux-64 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + run_exports: {} + size: 77667192 + timestamp: 1778268558509 +- conda: https://prefix.dev/conda-forge/linux-64/gcc_impl_linux-64-15.2.0-he0086c7_19.conda + sha256: a48400ec4b73369c1c59babe4ad35821b63a88bba0ec40a80cea5f8c53a26b83 + md5: e3be72048d3c4a78b8e27ec48ba06252 + depends: + - binutils_impl_linux-64 >=2.45 + - libgcc >=15.2.0 + - libgcc-devel_linux-64 15.2.0 hcc6f6b0_119 + - libgomp >=15.2.0 + - libsanitizer 15.2.0 h90f66d4_19 + - libstdcxx >=15.2.0 + - libstdcxx-devel_linux-64 15.2.0 hd446a21_119 + - sysroot_linux-64 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + run_exports: {} + size: 81180457 + timestamp: 1778269124617 +- conda: https://prefix.dev/conda-forge/linux-64/gcc_linux-64-14.3.0-h50e9bb6_25.conda + sha256: 95d22db25f0b8875febe63073f809c0c64f4026cc9e6aa0cca7130de51e4d044 + md5: 0a9089d9eeeeb23313a9ce670fb89052 + depends: + - gcc_impl_linux-64 14.3.0.* + - binutils_linux-64 + - sysroot_linux-64 + license: BSD-3-Clause + license_family: BSD + run_exports: + strong: + - libgcc >=14 + size: 29191 + timestamp: 1779371710532 +- conda: https://prefix.dev/conda-forge/linux-64/gcc_linux-64-15.2.0-h7be306e_25.conda + sha256: 3fbe01ebb16418d9f1971a283f969dc0f0e1071119f24164f4293057c79dc58c + md5: 46ca2358101b2477cb098c4248795d12 + depends: + - gcc_impl_linux-64 15.2.0.* + - binutils_linux-64 + - sysroot_linux-64 + license: BSD-3-Clause + license_family: BSD + run_exports: + strong: + - libgcc >=15 + size: 29190 + timestamp: 1779371750402 +- conda: https://prefix.dev/conda-forge/linux-64/gxx_impl_linux-64-14.3.0-h2185e75_19.conda + sha256: a31694c26d6a525d44f81130ebf7b9abe18771b7eaecb2cf93630c0b8b8fb936 + md5: 8b867d053ed89743eeac52c3a50f112d + depends: + - gcc_impl_linux-64 14.3.0 h235f0fe_19 + - libstdcxx-devel_linux-64 14.3.0 h9f08a49_119 + - sysroot_linux-64 + - tzdata + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + run_exports: {} + size: 15235650 + timestamp: 1778268773535 +- conda: https://prefix.dev/conda-forge/linux-64/gxx_impl_linux-64-15.2.0-hda75c37_19.conda + sha256: 3f5288346b9fe233352443b3c2e31f1fde845e39d3e96475fc05ec2e782af158 + md5: 9d41f3899b512199af0a4bb939b83e21 + depends: + - gcc_impl_linux-64 15.2.0 he0086c7_19 + - libstdcxx-devel_linux-64 15.2.0 hd446a21_119 + - sysroot_linux-64 + - tzdata + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + run_exports: {} + size: 16356816 + timestamp: 1778269332159 +- conda: https://prefix.dev/conda-forge/linux-64/gxx_linux-64-14.3.0-h72ca5df_25.conda + sha256: 369abc77d74a8275c734f9ca2375892b86d3163a541b1f5a2de946083a9e3ab0 + md5: 4718c7fefd927621bad46a8bcc6387d6 + depends: + - gxx_impl_linux-64 14.3.0.* + - gcc_linux-64 ==14.3.0 h50e9bb6_25 + - binutils_linux-64 + - sysroot_linux-64 + license: BSD-3-Clause + license_family: BSD + run_exports: + strong: + - libstdcxx >=14 + - libgcc >=14 + size: 27696 + timestamp: 1779371710532 +- conda: https://prefix.dev/conda-forge/linux-64/gxx_linux-64-15.2.0-h1b0a0b8_25.conda + sha256: 24bc169bc881759107d5ad8c4e3c4ce259ea8542ae97f2e79ebc3a7214d34b1d + md5: 77a6c6a8ad55a302e7f407d37b4c451a + depends: + - gxx_impl_linux-64 15.2.0.* + - gcc_linux-64 ==15.2.0 h7be306e_25 + - binutils_linux-64 + - sysroot_linux-64 + license: BSD-3-Clause + license_family: BSD + run_exports: + strong: + - libstdcxx >=15 + - libgcc >=15 + size: 27702 + timestamp: 1779371750402 +- conda: https://prefix.dev/conda-forge/linux-64/keyutils-1.6.3-hb9d3cd8_0.conda + sha256: 0960d06048a7185d3542d850986d807c6e37ca2e644342dd0c72feefcf26c2a4 + md5: b38117a3c920364aff79f870c984b4a3 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + license: LGPL-2.1-or-later + run_exports: + weak: + - keyutils >=1.6.3,<2.0a0 + size: 134088 + timestamp: 1754905959823 +- conda: https://prefix.dev/conda-forge/linux-64/krb5-1.22.2-ha1258a1_0.conda + sha256: 3e307628ca3527448dd1cb14ad7bb9d04d1d28c7d4c5f97ba196ae984571dd25 + md5: fb53fb07ce46a575c5d004bbc96032c2 + depends: + - __glibc >=2.17,<3.0.a0 + - keyutils >=1.6.3,<2.0a0 + - libedit >=3.1.20250104,<3.2.0a0 + - libedit >=3.1.20250104,<4.0a0 + - libgcc >=14 + - libstdcxx >=14 + - openssl >=3.5.5,<4.0a0 + license: MIT + license_family: MIT + run_exports: + weak: + - krb5 >=1.22.2,<1.23.0a0 + size: 1386730 + timestamp: 1769769569681 +- conda: https://prefix.dev/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_102.conda + sha256: 3d584956604909ff5df353767f3a2a2f60e07d070b328d109f30ac40cd62df6c + md5: 18335a698559cdbcd86150a48bf54ba6 + depends: + - __glibc >=2.17,<3.0.a0 + - zstd >=1.5.7,<1.6.0a0 + constrains: + - binutils_impl_linux-64 2.45.1 + license: GPL-3.0-only + license_family: GPL + run_exports: {} + size: 728002 + timestamp: 1774197446916 +- conda: https://prefix.dev/conda-forge/linux-64/libcurl-8.20.0-hcf29cc6_0.conda + sha256: 75963a5dd913311f59a35dbd307592f4fa754c4808aff9c33edb430c415e38eb + md5: c3cc2864f82a944bc90a7beb4d3b0e88 + depends: + - __glibc >=2.17,<3.0.a0 + - krb5 >=1.22.2,<1.23.0a0 + - libgcc >=14 + - libnghttp2 >=1.68.1,<2.0a0 + - libssh2 >=1.11.1,<2.0a0 + - libzlib >=1.3.2,<2.0a0 + - openssl >=3.5.6,<4.0a0 + - zstd >=1.5.7,<1.6.0a0 + license: curl + license_family: MIT + run_exports: + weak: + - libcurl >=8.20.0,<9.0a0 + size: 468706 + timestamp: 1777461492876 +- conda: https://prefix.dev/conda-forge/linux-64/libedit-3.1.20250104-pl5321h7949ede_0.conda + sha256: d789471216e7aba3c184cd054ed61ce3f6dac6f87a50ec69291b9297f8c18724 + md5: c277e0a4d549b03ac1e9d6cbbe3d017b + depends: + - ncurses + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - ncurses >=6.5,<7.0a0 + license: BSD-2-Clause + license_family: BSD + run_exports: + weak: + - libedit >=3.1.20250104,<3.2.0a0 + size: 134676 + timestamp: 1738479519902 +- conda: https://prefix.dev/conda-forge/linux-64/libev-4.33-hd590300_2.conda + sha256: 1cd6048169fa0395af74ed5d8f1716e22c19a81a8a36f934c110ca3ad4dd27b4 + md5: 172bf1cd1ff8629f2b1179945ed45055 + depends: + - libgcc-ng >=12 + license: BSD-2-Clause + license_family: BSD + run_exports: + weak: + - libev >=4.33,<4.34.0a0 + size: 112766 + timestamp: 1702146165126 +- conda: https://prefix.dev/conda-forge/linux-64/libexpat-2.8.1-hecca717_0.conda + sha256: 363018b25fdb5534c79783d912bd4b685a3547f4fc5996357ad548899b0ee8e7 + md5: 93764a5ca80616e9c10106cdaec92f74 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + constrains: + - expat 2.8.1.* + license: MIT + license_family: MIT + run_exports: {} + size: 77294 + timestamp: 1779278686680 +- conda: https://prefix.dev/conda-forge/linux-64/libgcc-15.2.0-he0feb66_19.conda + sha256: 8e0a3b5e41272e5678499b5dfc4cddb673f9e935de01eb0767ce857001229f46 + md5: 57736f29cc2b0ec0b6c2952d3f101b6a + depends: + - __glibc >=2.17,<3.0.a0 + - _openmp_mutex >=4.5 + constrains: + - libgcc-ng ==15.2.0=*_19 + - libgomp 15.2.0 he0feb66_19 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + run_exports: {} + size: 1041084 + timestamp: 1778269013026 +- conda: https://prefix.dev/conda-forge/linux-64/libgcc-ng-15.2.0-h69a702a_19.conda + sha256: 9dcf54adfaa5e861123c2da4f2f0451a685464ea7e5a41ad91cf67b31d658d98 + md5: 331ee9b72b9dff570d56b1302c5ab37d + depends: + - libgcc 15.2.0 he0feb66_19 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + run_exports: + strong: + - libgcc + size: 27694 + timestamp: 1778269016987 +- conda: https://prefix.dev/conda-forge/linux-64/libgomp-15.2.0-he0feb66_19.conda + sha256: 5abe4ab9d93f6c9757d654f1969ae2267d4505315c1f2f8fe705fd60af084f1b + md5: faac990cb7aedc7f3a2224f2c9b0c26c + depends: + - __glibc >=2.17,<3.0.a0 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + run_exports: + strong: + - _openmp_mutex >=4.5 + size: 603817 + timestamp: 1778268942614 +- conda: https://prefix.dev/conda-forge/linux-64/liblzma-5.8.3-hb03c661_0.conda + sha256: ec30e52a3c1bf7d0425380a189d209a52baa03f22fb66dd3eb587acaa765bd6d + md5: b88d90cad08e6bc8ad540cb310a761fb + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + constrains: + - xz 5.8.3.* + license: 0BSD + run_exports: + weak: + - liblzma >=5.8.3,<6.0a0 + size: 113478 + timestamp: 1775825492909 +- conda: https://prefix.dev/conda-forge/linux-64/libnghttp2-1.68.1-h877daf1_0.conda + sha256: 663444d77a42f2265f54fb8b48c5450bfff4388d9c0f8253dd7855f0d993153f + md5: 2a45e7f8af083626f009645a6481f12d + depends: + - __glibc >=2.17,<3.0.a0 + - c-ares >=1.34.6,<2.0a0 + - libev >=4.33,<4.34.0a0 + - libev >=4.33,<5.0a0 + - libgcc >=14 + - libstdcxx >=14 + - libzlib >=1.3.1,<2.0a0 + - openssl >=3.5.5,<4.0a0 + license: MIT + license_family: MIT + run_exports: + weak: + - libnghttp2 >=1.68.1,<2.0a0 + size: 663344 + timestamp: 1773854035739 +- conda: https://prefix.dev/conda-forge/linux-64/libnvptxcompiler-dev-12.9.86-ha770c72_2.conda + sha256: 1e7a7b34f8639a5feb75ba864127059e4d83edfe1a516547f0dbb9941e7b8f8b + md5: 3fd926c321c6dbf386aa14bd8b125bfb + depends: + - cuda-version >=12.9,<12.10.0a0 + - libnvptxcompiler-dev_linux-64 12.9.86 ha770c72_2 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: {} + size: 27046 + timestamp: 1753975516342 +- conda: https://prefix.dev/conda-forge/linux-64/libsanitizer-14.3.0-h8f1669f_19.conda + sha256: 8766de5423b0a510e2b1bdd1963d0554bdad2119f3e31d8fbd4189af434235ca + md5: 007796e5a595bbc7df4a5e1580d72e1a + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14.3.0 + - libstdcxx >=14.3.0 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + run_exports: + weak: + - libsanitizer 14.3.0 + size: 7947790 + timestamp: 1778268494844 +- conda: https://prefix.dev/conda-forge/linux-64/libsanitizer-15.2.0-h90f66d4_19.conda + sha256: 7a58892a52739ce4c0f7109de9e91b4353104748eb04fc6441d88e8af444ba99 + md5: 67eef12ce33f7ff99900c212d7076fc2 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=15.2.0 + - libstdcxx >=15.2.0 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + run_exports: + weak: + - libsanitizer 15.2.0 + size: 7930689 + timestamp: 1778269054623 +- conda: https://prefix.dev/conda-forge/linux-64/libssh2-1.11.1-hcf80075_0.conda + sha256: fa39bfd69228a13e553bd24601332b7cfeb30ca11a3ca50bb028108fe90a7661 + md5: eecce068c7e4eddeb169591baac20ac4 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - libzlib >=1.3.1,<2.0a0 + - openssl >=3.5.0,<4.0a0 + license: BSD-3-Clause + license_family: BSD + run_exports: + weak: + - libssh2 >=1.11.1,<2.0a0 + size: 304790 + timestamp: 1745608545575 +- conda: https://prefix.dev/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_19.conda + sha256: dff1058c76ec6b8759e41cefa2508162d00e4a5e6721aa68ec3fd10094e702dc + md5: 5794b3bdc38177caf969dabd3af08549 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc 15.2.0 he0feb66_19 + constrains: + - libstdcxx-ng ==15.2.0=*_19 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + run_exports: {} + size: 5852044 + timestamp: 1778269036376 +- conda: https://prefix.dev/conda-forge/linux-64/libuv-1.52.1-h280c20c_0.conda + sha256: e28e4519223f78b3163599ca89c3f2d80bfb53e907e7fc74e806e60d1efa578b + md5: 4e33d49bf4fc853855a3b00643aa5484 + depends: + - libgcc >=14 + - __glibc >=2.17,<3.0.a0 + license: MIT + license_family: MIT + run_exports: + weak: + - libuv >=1.52.1,<2.0a0 + size: 419935 + timestamp: 1779396012261 +- conda: https://prefix.dev/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_2.conda + sha256: 55044c403570f0dc26e6364de4dc5368e5f3fc7ff103e867c487e2b5ab2bcda9 + md5: d87ff7921124eccd67248aa483c23fec + depends: + - __glibc >=2.17,<3.0.a0 + constrains: + - zlib 1.3.2 *_2 + license: Zlib + license_family: Other + run_exports: + weak: + - libzlib >=1.3.2,<2.0a0 + size: 63629 + timestamp: 1774072609062 +- conda: https://prefix.dev/conda-forge/linux-64/ncurses-6.6-hdb14827_0.conda + sha256: fc89f74bbe362fb29fa3c037697a89bec140b346a2469a90f7936d1d7ea4d8a3 + md5: fc21868a1a5aacc937e7a18747acb8a5 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + license: X11 AND BSD-3-Clause + run_exports: + weak: + - ncurses >=6.6,<7.0a0 + size: 918956 + timestamp: 1777422145199 +- conda: https://prefix.dev/conda-forge/linux-64/ninja-1.13.2-h171cf75_0.conda + sha256: 6f7d59dbec0a7b00bf5d103a4306e8886678b796ff2151b62452d4582b2a53fb + md5: b518e9e92493721281a60fa975bddc65 + depends: + - libstdcxx >=14 + - libgcc >=14 + - __glibc >=2.17,<3.0.a0 + license: Apache-2.0 + license_family: APACHE + run_exports: {} + size: 186323 + timestamp: 1763688260928 +- conda: https://prefix.dev/conda-forge/linux-64/openssl-3.6.2-h35e630c_0.conda + sha256: c0ef482280e38c71a08ad6d71448194b719630345b0c9c60744a2010e8a8e0cb + md5: da1b85b6a87e141f5140bb9924cecab0 + depends: + - __glibc >=2.17,<3.0.a0 + - ca-certificates + - libgcc >=14 + license: Apache-2.0 + license_family: Apache + run_exports: + weak: + - openssl >=3.6.2,<4.0a0 + size: 3167099 + timestamp: 1775587756857 +- conda: https://prefix.dev/conda-forge/linux-64/rhash-1.4.6-hb9d3cd8_1.conda + sha256: d5c73079c1dd2c2a313c3bfd81c73dbd066b7eb08d213778c8bff520091ae894 + md5: c1c9b02933fdb2cfb791d936c20e887e + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + license: MIT + license_family: MIT + run_exports: + weak: + - rhash >=1.4.6,<2.0a0 + size: 193775 + timestamp: 1748644872902 +- conda: https://prefix.dev/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda + sha256: 68f0206ca6e98fea941e5717cec780ed2873ffabc0e1ed34428c061e2c6268c7 + md5: 4a13eeac0b5c8e5b8ab496e6c4ddd829 + depends: + - __glibc >=2.17,<3.0.a0 + - libzlib >=1.3.1,<2.0a0 + license: BSD-3-Clause + license_family: BSD + run_exports: + weak: + - zstd >=1.5.7,<1.6.0a0 + size: 601375 + timestamp: 1764777111296 +- conda: https://prefix.dev/conda-forge/noarch/ca-certificates-2026.5.20-h4c7d964_0.conda + sha256: 86981d764e4ea1883409d30447ff9da46127426d31a63df08315aaded768e652 + md5: c9b86eece2f944541b86441c94117ab3 + depends: + - __win + license: ISC + run_exports: {} + size: 130182 + timestamp: 1779289939595 +- conda: https://prefix.dev/conda-forge/noarch/ca-certificates-2026.5.20-hbd8a1cb_0.conda + sha256: 9812a303a1395e1dafbd92e5bc8a1ff6013bcbba0a09c7f03a8d23e43560aa9b + md5: 489b8e97e666c93f68fdb35c3c9b957f + depends: + - __unix + license: ISC + run_exports: {} + size: 129868 + timestamp: 1779289852439 +- conda: https://prefix.dev/conda-forge/noarch/compiler-rt22_osx-64-22.1.7-hcf80936_0.conda + sha256: 87c48a861f8c06c2be4f8ad7e7b774e2c6d4891e617dc6461d9c670bae17b790 + md5: 9829c9c1cd2b57757ccb80aa1f5ab019 + constrains: + - compiler-rt >=9.0.1 + license: Apache-2.0 WITH LLVM-exception + license_family: APACHE + run_exports: {} + size: 10910520 + timestamp: 1780458666064 +- conda: https://prefix.dev/conda-forge/noarch/compiler-rt22_osx-arm64-22.1.7-h7e67a1e_0.conda + sha256: f3d32eba79cd7815b20277c5a0dc0b265d7f5ca0eabad9daa6fd68be87fb8af7 + md5: 08a65a1a0cf1ca2053c7179e534b685e + constrains: + - compiler-rt >=9.0.1 + license: Apache-2.0 WITH LLVM-exception + license_family: APACHE + run_exports: {} + size: 10727649 + timestamp: 1780457616663 +- conda: https://prefix.dev/conda-forge/noarch/compiler-rt_osx-64-22.1.7-h694c41f_0.conda + sha256: a5118bf285946d0a04e0d5bf989b729340d72b317a6b115d6c41e8dfe959081e + md5: c6e2bd3d209f0bf87ad5bc3a8046fef4 + depends: + - compiler-rt22_osx-64 22.1.7 hcf80936_0 + constrains: + - clang 22.1.7 + license: Apache-2.0 WITH LLVM-exception + license_family: APACHE + run_exports: {} + size: 16809 + timestamp: 1780458741409 +- conda: https://prefix.dev/conda-forge/noarch/compiler-rt_osx-arm64-22.1.7-hce30654_0.conda + sha256: fc9f7f6322088f2efc014dac83219cd00e42583dc6502c7314c98183b6554c3d + md5: c49b5fb0d1b3d9a4c6e2dff11fdf51fd + depends: + - compiler-rt22_osx-arm64 22.1.7 h7e67a1e_0 + constrains: + - clang 22.1.7 + license: Apache-2.0 WITH LLVM-exception + license_family: APACHE + run_exports: {} + size: 16797 + timestamp: 1780457650249 +- conda: https://prefix.dev/conda-forge/noarch/cuda-cccl_linux-64-12.9.27-ha770c72_0.conda + sha256: 2ee3b9564ca326226e5cda41d11b251482df8e7c757e333d28ec75213c75d126 + md5: 87ff6381e33b76e5b9b179a2cdd005ec + depends: + - cuda-version >=12.9,<12.10.0a0 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: {} + size: 1150650 + timestamp: 1746189825236 +- conda: https://prefix.dev/conda-forge/noarch/cuda-cccl_win-64-12.9.27-h57928b3_0.conda + sha256: 681eb1d9afd596e04329a82b04734c0e37c6ecb94b3380f3a378d61983e2a8cc + md5: 8f897dca7111f3bb4ded97ba6947b186 + depends: + - cuda-version >=12.9,<12.10.0a0 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: {} + size: 1139649 + timestamp: 1746189858434 +- conda: https://prefix.dev/conda-forge/noarch/cuda-crt-dev_linux-64-12.9.86-ha770c72_2.conda + sha256: e6257534c4b4b6b8a1192f84191c34906ab9968c92680fa09f639e7846a87304 + md5: 79d280de61e18010df5997daea4743df + depends: + - cuda-version >=12.9,<12.10.0a0 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: {} + size: 94239 + timestamp: 1753975242354 +- conda: https://prefix.dev/conda-forge/noarch/cuda-crt-dev_win-64-12.9.86-h57928b3_2.conda + sha256: 2fccde18cafec3cdb6697f37c576567ac623dc69531e2a81bbc83d8a86a82d1f + md5: 569c55bd368307e48191a2ed54c64428 + depends: + - cuda-version >=12.9,<12.10.0a0 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: {} + size: 95452 + timestamp: 1753975640812 +- conda: https://prefix.dev/conda-forge/noarch/cuda-cudart-dev_linux-64-12.9.79-h3f2d84a_0.conda + sha256: ffe86ed0144315b276f18020d836c8ef05bf971054cf7c3eb167af92494080d5 + md5: 86e40eb67d83f1a58bdafdd44e5a77c6 + depends: + - cuda-cccl_linux-64 + - cuda-cudart-static_linux-64 + - cuda-cudart_linux-64 + - cuda-version >=12.9,<12.10.0a0 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: + weak: + - cuda-cudart >=12.9.79,<13.0a0 + size: 389140 + timestamp: 1749218427266 +- conda: https://prefix.dev/conda-forge/noarch/cuda-cudart-dev_win-64-12.9.79-he0c23c2_0.conda + sha256: e022d36a333420130faf6473c49f8dab54bf976cf320577ffb06db0a0797b734 + md5: 3c3e2f6b5455783fd332a072d632ea78 + depends: + - cuda-cccl_win-64 + - cuda-cudart-static_win-64 + - cuda-cudart_win-64 + - cuda-version >=12.9,<12.10.0a0 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: + weak: + - cuda-cudart >=12.9.79,<13.0a0 + size: 1190184 + timestamp: 1749218971019 +- conda: https://prefix.dev/conda-forge/noarch/cuda-cudart-static_linux-64-12.9.79-h3f2d84a_0.conda + sha256: d435f8a19b59b52ce460ee3a6bfd877288a0d1d645119a6ba60f1c3627dc5032 + md5: b87bf315d81218dd63eb46cc1eaef775 + depends: + - cuda-version >=12.9,<12.10.0a0 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: {} + size: 1148889 + timestamp: 1749218381225 +- conda: https://prefix.dev/conda-forge/noarch/cuda-cudart-static_win-64-12.9.79-he0c23c2_0.conda + sha256: 6a3410cd7ce07955cb705801055ef129ebee1cd6390c6fe9e5f607b67c3dba36 + md5: 0dd152a1493d90356037604a865f050f + depends: + - cuda-version >=12.9,<12.10.0a0 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: {} + size: 354611 + timestamp: 1749218544740 +- conda: https://prefix.dev/conda-forge/noarch/cuda-cudart_linux-64-12.9.79-h3f2d84a_0.conda + sha256: 6cde0ace2b995b49d0db2eefb7bc30bf00ffc06bb98ef7113632dec8f8907475 + md5: 64508631775fbbf9eca83c84b1df0cae + depends: + - cuda-version >=12.9,<12.10.0a0 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: {} + size: 197249 + timestamp: 1749218394213 +- conda: https://prefix.dev/conda-forge/noarch/cuda-cudart_win-64-12.9.79-he0c23c2_0.conda + sha256: 6a89a53cdbcfafa0bb55abee1b58492c6a9a28e688abe04f48f0d01649c5f3e4 + md5: 71c9c2ab52226f990f268164381d8494 + depends: + - cuda-version >=12.9,<12.10.0a0 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: {} + size: 23260 + timestamp: 1749218569458 +- conda: https://prefix.dev/conda-forge/noarch/cuda-driver-dev_linux-64-12.9.79-h3f2d84a_0.conda + sha256: a15574d966e73135a79d5e6570c87e13accdb44bd432449b5deea71644ad442c + md5: d411828daa36ac84eab210ba3bbe5a64 + depends: + - cuda-version >=12.9,<12.10.0a0 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: {} + size: 37714 + timestamp: 1749218405324 +- conda: https://prefix.dev/conda-forge/noarch/cuda-nvcc-dev_linux-64-12.9.86-he91c749_2.conda + sha256: a1672a34439a72869de9e011e935d41b62fc8dfb1a2700e85ed8a7a129b79981 + md5: 19d4e090217f0ea89d30bedb7461c048 + depends: + - cuda-crt-dev_linux-64 12.9.86 ha770c72_2 + - cuda-nvvm-dev_linux-64 12.9.86 ha770c72_2 + - cuda-version >=12.9,<12.10.0a0 + - libgcc >=6 + - libnvptxcompiler-dev_linux-64 12.9.86 ha770c72_2 + constrains: + - gcc_impl_linux-64 >=6,<15.0a0 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: {} + size: 28121 + timestamp: 1753975535813 +- conda: https://prefix.dev/conda-forge/noarch/cuda-nvcc-dev_win-64-12.9.86-h36c15f3_2.conda + sha256: e50255fe30f60135414e8b657c4ffdb12938af06463c959280eceb7166f69eb5 + md5: 20c8a059c5175ab804e7fc94213eb464 + depends: + - cuda-crt-dev_win-64 12.9.86 h57928b3_2 + - cuda-nvvm-dev_win-64 12.9.86 h57928b3_2 + - cuda-version >=12.9,<12.10.0a0 + - libnvptxcompiler-dev_win-64 12.9.86 h57928b3_2 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: {} + size: 23452957 + timestamp: 1753976361068 +- conda: https://prefix.dev/conda-forge/noarch/cuda-nvvm-dev_linux-64-12.9.86-ha770c72_2.conda + sha256: 522722dcaffd133e0c7500c69dc70e21ac34d6762dcbaabfe847439f944028f0 + md5: 7b386291414c7eea113d25ac28a33772 + depends: + - cuda-version >=12.9,<12.10.0a0 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: {} + size: 27096 + timestamp: 1753975261562 +- conda: https://prefix.dev/conda-forge/noarch/cuda-nvvm-dev_win-64-12.9.86-h57928b3_2.conda + sha256: 455dbf0ec81efdbd40c0387d82c77689721f6d34b6e7694ca0d51bad9392eddc + md5: 23f7e70c03eabd2139b5e659c8e188b4 + depends: + - cuda-version >=12.9,<12.10.0a0 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: {} + size: 27284 + timestamp: 1753975714790 +- conda: https://prefix.dev/conda-forge/noarch/cuda-version-12.9-h4f385c5_3.conda + sha256: 5f5f428031933f117ff9f7fcc650e6ea1b3fef5936cf84aa24af79167513b656 + md5: b6d5d7f1c171cbd228ea06b556cfa859 + constrains: + - cudatoolkit 12.9|12.9.* + - __cuda >=12 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: {} + size: 21578 + timestamp: 1746134436166 +- conda: https://prefix.dev/conda-forge/noarch/kernel-headers_linux-64-4.18.0-he073ed8_9.conda + sha256: 41557eeadf641de6aeae49486cef30d02a6912d8da98585d687894afd65b356a + md5: 86d9cba083cd041bfbf242a01a7a1999 + constrains: + - sysroot_linux-64 ==2.28 + license: LGPL-2.0-or-later AND LGPL-2.0-or-later WITH exceptions AND GPL-2.0-or-later + license_family: GPL + run_exports: {} + size: 1278712 + timestamp: 1765578681495 +- conda: https://prefix.dev/conda-forge/noarch/libcxx-headers-22.1.7-h707e725_0.conda + sha256: 06368b93aa7936d52854e8ee05845736f225c960d93cfd17ec8062ec3d2b55ed + md5: b0952b7a26c0f00cb78b9dc04f99dec7 + depends: + - __unix + constrains: + - libcxx-devel 22.1.7 + - clangxx >=19 + - gxx_osx-64 >=14 + - gxx_linux-64 >=14 + - gxx_osx-arm64 >=14 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + run_exports: {} + size: 1149765 + timestamp: 1780441705384 +- conda: https://prefix.dev/conda-forge/noarch/libgcc-devel_linux-64-14.3.0-hf649bbc_119.conda + sha256: e1815bb11d5abe886979e95889d84310d83d078d36a3567ca67cbf57a3876d88 + md5: 7d517e32d656a8880d98c0e4fc8ddc2c + depends: + - __unix + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + run_exports: {} + size: 3091520 + timestamp: 1778268364856 +- conda: https://prefix.dev/conda-forge/noarch/libgcc-devel_linux-64-15.2.0-hcc6f6b0_119.conda + sha256: 38a557eba305468ac1f90ac85e50d8defd76141cb0b8a43b2fc1aca71dd5d5f2 + md5: 683fcb168e1df9a21fa80d5aa2d9330b + depends: + - __unix + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + run_exports: {} + size: 3095909 + timestamp: 1778268932148 +- conda: https://prefix.dev/conda-forge/noarch/libnvptxcompiler-dev_linux-64-12.9.86-ha770c72_2.conda + sha256: 17952c32eac197a59c119fdf3fb6f08c6a29c225a80bae141ac904ad212b87dd + md5: a66a909acf08924aced622903832a937 + depends: + - cuda-version >=12.9,<12.10.0a0 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: {} + size: 14422867 + timestamp: 1753975387297 +- conda: https://prefix.dev/conda-forge/noarch/libnvptxcompiler-dev_win-64-12.9.86-h57928b3_2.conda + sha256: 9858bc91d01ab6d3a21039f37c8e22e3cb59542b7d308098b10bbe2b12be0aaa + md5: 77baf6d1c6916a86ab99ce4e83282e4f + depends: + - cuda-version >=12.9,<12.10.0a0 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: {} + size: 31818844 + timestamp: 1753976049670 +- conda: https://prefix.dev/conda-forge/noarch/libstdcxx-devel_linux-64-14.3.0-h9f08a49_119.conda + sha256: 1b4263aa5d8c8c659e8e38b66868f42867347e0c8941513ee77269afc00a5186 + md5: d1a866495b9654ccfef5392b8541dc58 + depends: + - __unix + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + run_exports: {} + size: 20199810 + timestamp: 1778268389428 +- conda: https://prefix.dev/conda-forge/noarch/libstdcxx-devel_linux-64-15.2.0-hd446a21_119.conda + sha256: a2385f3611d5cd25378f9cf2367183320731709c067ddd08d43330d3170f15b8 + md5: bcfe7eae40158c3e355d2f9d3ed41230 + depends: + - __unix + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + run_exports: {} + size: 20765069 + timestamp: 1778268963689 +- conda: https://prefix.dev/conda-forge/noarch/sdkroot_env_osx-64-26.0-h62b880e_7.conda + sha256: 7e7e2556978bc9bd9628c6e39138c684082320014d708fbca0c9050df98c0968 + md5: 68a978f77c0ba6ca10ce55e188a21857 + license: BSD-3-Clause + license_family: BSD + run_exports: {} + size: 4948 + timestamp: 1771434185960 +- conda: https://prefix.dev/conda-forge/noarch/sdkroot_env_osx-arm64-26.0-ha3f98da_7.conda + sha256: fabfe031ede99898cb2b0b805f6c0d64fcc24ecdb444de3a83002d8135bf4804 + md5: 5f0ebbfea12d8e5bddff157e271fdb2f + license: BSD-3-Clause + license_family: BSD + run_exports: {} + size: 4971 + timestamp: 1771434195389 +- conda: https://prefix.dev/conda-forge/noarch/sysroot_linux-64-2.28-h4ee821c_9.conda + sha256: c47299fe37aebb0fcf674b3be588e67e4afb86225be4b0d452c7eb75c086b851 + md5: 13dc3adbc692664cd3beabd216434749 + depends: + - __glibc >=2.28 + - kernel-headers_linux-64 4.18.0 he073ed8_9 + - tzdata + license: LGPL-2.0-or-later AND LGPL-2.0-or-later WITH exceptions AND GPL-2.0-or-later + license_family: GPL + run_exports: + strong: + - __glibc >=2.28,<3.0.a0 + size: 24008591 + timestamp: 1765578833462 +- conda: https://prefix.dev/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + sha256: 1d30098909076af33a35017eed6f2953af1c769e273a0626a04722ac4acaba3c + md5: ad659d0a2b3e47e38d829aa8cad2d610 + license: LicenseRef-Public-Domain + run_exports: {} + size: 119135 + timestamp: 1767016325805 +- conda: https://prefix.dev/conda-forge/noarch/vswhere-3.1.7-h40126e0_1.conda + sha256: b72270395326dc56de9bd6ca82f63791b3c8c9e2b98e25242a9869a4ca821895 + md5: f622897afff347b715d046178ad745a5 + depends: + - __win + license: MIT + license_family: MIT + run_exports: {} + size: 238764 + timestamp: 1745560912727 +- conda: https://prefix.dev/conda-forge/osx-64/bzip2-1.0.8-h500dc9f_9.conda + sha256: 9f242f13537ef1ce195f93f0cc162965d6cc79da578568d6d8e50f70dd025c42 + md5: 4173ac3b19ec0a4f400b4f782910368b + depends: + - __osx >=10.13 + license: bzip2-1.0.6 + license_family: BSD + run_exports: + weak: + - bzip2 >=1.0.8,<2.0a0 + size: 133427 + timestamp: 1771350680709 +- conda: https://prefix.dev/conda-forge/osx-64/c-ares-1.34.6-hb5e19a0_0.conda + sha256: 2f5bc0292d595399df0d168355b4e9820affc8036792d6984bd751fdda2bcaea + md5: fc9a153c57c9f070bebaa7eef30a8f17 + depends: + - __osx >=10.13 + license: MIT + license_family: MIT + run_exports: + weak: + - c-ares >=1.34.6,<2.0a0 + size: 186122 + timestamp: 1765215100384 +- conda: https://prefix.dev/conda-forge/osx-64/cctools_impl_osx-64-1030.6.3-llvm22_1_h8fe25a2_4.conda + sha256: 9e003c254b6c1880e6c8f2d777b20d837db2b7aff161454d857693692fd862dd + md5: 5d0b3b0b085354afc3b53c424e40121b + depends: + - __osx >=11.0 + - ld64_osx-64 >=956.6,<956.7.0a0 + - libcxx + - libllvm22 >=22.1.0,<22.2.0a0 + - libzlib >=1.3.1,<2.0a0 + - llvm-tools 22.1.* + - sigtool-codesign + constrains: + - clang 22.1.* + - cctools 1030.6.3.* + - ld64 956.6.* + license: APSL-2.0 + license_family: Other + run_exports: {} + size: 744001 + timestamp: 1772019049683 +- conda: https://prefix.dev/conda-forge/osx-64/cctools_osx-64-1030.6.3-llvm22_1_h0a1bb1c_4.conda + sha256: e0eefd2d7b4c8434b1b97ddf51780601e4ea5c964bb053775213868412367bbe + md5: d97b4a7d3a90d1cd45ff42ee353efadc + depends: + - cctools_impl_osx-64 1030.6.3 llvm22_1_h8fe25a2_4 + - ld64_osx-64 956.6 llvm22_1_h163eae7_4 + constrains: + - cctools 1030.6.3.* + license: APSL-2.0 + license_family: Other + run_exports: {} + size: 23441 + timestamp: 1772019105060 +- conda: https://prefix.dev/conda-forge/osx-64/clang-22-22.1.7-default_h3b8fe2e_1.conda + sha256: 8acd160b174fe02c61efd926b574d0bce11fc800ab1b8882817461f7940b2561 + md5: a0c754cdc84949d979bc15462df8c0ee + depends: + - __osx >=11.0 + - compiler-rt22 22.1.7.* + - libclang-cpp22.1 22.1.7 default_h9399c5b_1 + - libcxx >=22.1.7 + - libllvm22 >=22.1.7,<22.2.0a0 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + run_exports: {} + size: 826158 + timestamp: 1780524355900 +- conda: https://prefix.dev/conda-forge/osx-64/clang-scan-deps-22.1.7-default_h9399c5b_1.conda + sha256: aa12e6e62ac9845a9cc342c94f36970edb95350f53db67465ba2372221931bad + md5: 6f587e560f651de770491081a8ee3f03 + depends: + - __osx >=11.0 + - libclang-cpp22.1 >=22.1.7,<22.2.0a0 + - libclang13 >=22.1.7 + - libcxx >=22.1.7 + - libllvm22 >=22.1.7,<22.2.0a0 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + run_exports: {} + size: 110985 + timestamp: 1780524880282 +- conda: https://prefix.dev/conda-forge/osx-64/clang_impl_osx-64-22.1.7-default_hb18168d_1.conda + sha256: f9a91571fc4c63030e79a8e7aad11a0a42e451f3fc624bb893a7189141a2ffad + md5: cded0f2d26fa6d3163451cb64840d3ee + depends: + - cctools_impl_osx-64 + - clang-22 22.1.7 default_h3b8fe2e_1 + - compiler-rt 22.1.7.* + - compiler-rt_osx-64 + - ld64_osx-64 * llvm22_1_* + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + run_exports: {} + size: 29139 + timestamp: 1780524488866 +- conda: https://prefix.dev/conda-forge/osx-64/clang_osx-64-22.1.7-hb0d1528_32.conda + sha256: 719d2bda314068a6446fde8673a931764e43dec2f8017b66d51232fd1898aeec + md5: 443550581ad436305c85b7b11ec7d908 + depends: + - cctools_osx-64 + - clang_impl_osx-64 22.1.7.* + - sdkroot_env_osx-64 + license: BSD-3-Clause + license_family: BSD + run_exports: {} + size: 21209 + timestamp: 1780546451340 +- conda: https://prefix.dev/conda-forge/osx-64/clangxx_impl_osx-64-22.1.7-default_hb18168d_1.conda + sha256: 8429fdd3216fe5625045413b71134ac5d253714bfff78c5fffa6d609fd37c08c + md5: add2be2d94e8e2bc1a015134e2ffbc32 + depends: + - clang-22 22.1.7 default_h3b8fe2e_1 + - clang-scan-deps 22.1.7 default_h9399c5b_1 + - clang_impl_osx-64 22.1.7 default_hb18168d_1 + - libcxx-devel 22.1.* + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + run_exports: {} + size: 29064 + timestamp: 1780524906511 +- conda: https://prefix.dev/conda-forge/osx-64/clangxx_osx-64-22.1.7-hb0d1528_32.conda + sha256: 23e6caad7a9677d517119467ee74214aa553876230f0c7b20be9396fd032ec57 + md5: 7e37c3a1cc4224ed4861ee310b8daae9 + depends: + - cctools_osx-64 + - clang_osx-64 22.1.7 hb0d1528_32 + - clangxx_impl_osx-64 22.1.7.* + - sdkroot_env_osx-64 + license: BSD-3-Clause + license_family: BSD + run_exports: + strong: + - libcxx >=22 + size: 20033 + timestamp: 1780546460416 +- conda: https://prefix.dev/conda-forge/osx-64/cmake-4.3.3-h2426fb6_0.conda + sha256: be84ff61332b844c24c5996f48b85be5600bf30715ce9d21090f7ea964f65f38 + md5: 4349fad6b55a5ed7b572f750678eba79 + depends: + - __osx >=11.0 + - bzip2 >=1.0.8,<2.0a0 + - libcurl >=8.20.0,<9.0a0 + - libcxx >=19 + - libexpat >=2.8.1,<3.0a0 + - liblzma >=5.8.3,<6.0a0 + - libuv >=1.51.0,<2.0a0 + - libzlib >=1.3.2,<2.0a0 + - ncurses >=6.6,<7.0a0 + - rhash >=1.4.6,<2.0a0 + - zstd >=1.5.7,<1.6.0a0 + license: BSD-3-Clause + license_family: BSD + run_exports: {} + size: 19487980 + timestamp: 1779399784343 +- conda: https://prefix.dev/conda-forge/osx-64/compiler-rt-22.1.7-h694c41f_0.conda + sha256: 057879f1f517b25a2394639fcedfc04005f6bbf63ab003182bc479e641db2b2c + md5: d3834d21abeff2613f6c806ff41a3059 + depends: + - compiler-rt22 22.1.7 h1637cdf_0 + - libcompiler-rt 22.1.7 h1637cdf_0 + constrains: + - clang 22.1.7 + license: Apache-2.0 WITH LLVM-exception + license_family: APACHE + run_exports: {} + size: 16675 + timestamp: 1780458743280 +- conda: https://prefix.dev/conda-forge/osx-64/compiler-rt22-22.1.7-h1637cdf_0.conda + sha256: f67af723c48fa4c789d1b3cdcde618d7479622fd410cb51f9457f0b70dc8c13d + md5: 1366301c61cad16bcdbf00c9f43576cf + depends: + - __osx >=11.0 + - compiler-rt22_osx-64 22.1.7.* + license: Apache-2.0 WITH LLVM-exception + license_family: APACHE + run_exports: {} + size: 99264 + timestamp: 1780458739013 +- conda: https://prefix.dev/conda-forge/osx-64/krb5-1.22.2-h207b36a_0.conda + sha256: df009385e8262c234c0dae9016540b86dad3d299f0d9366d08e327e8e7731634 + md5: e66e2c52d2fdddcf314ad750fb4ebb4a + depends: + - __osx >=10.13 + - libcxx >=19 + - libedit >=3.1.20250104,<3.2.0a0 + - libedit >=3.1.20250104,<4.0a0 + - openssl >=3.5.5,<4.0a0 + license: MIT + license_family: MIT + run_exports: + weak: + - krb5 >=1.22.2,<1.23.0a0 + size: 1193620 + timestamp: 1769770267475 +- conda: https://prefix.dev/conda-forge/osx-64/ld64_osx-64-956.6-llvm22_1_h163eae7_4.conda + sha256: e49272192003e0e30edd6877197db3c220bb374a78d5b255d18c7a029cd33c1e + md5: 9e6646598daf11bd8ebc60d690162ebd + depends: + - __osx >=11.0 + - libcxx + - libllvm22 >=22.1.0,<22.2.0a0 + - sigtool-codesign + - tapi >=1600.0.11.8,<1601.0a0 + constrains: + - clang 22.1.* + - cctools 1030.6.3.* + - cctools_impl_osx-64 1030.6.3.* + - ld64 956.6.* + license: APSL-2.0 + license_family: Other + run_exports: {} + size: 1110951 + timestamp: 1772018988810 +- conda: https://prefix.dev/conda-forge/osx-64/libclang-cpp22.1-22.1.7-default_h9399c5b_1.conda + sha256: f354e26f811a31427ff4cc4695a6773187bb2ac9ad9197eebf41da470e637968 + md5: 135131fca92856cfe4e32af9ffbfc9c2 + depends: + - __osx >=11.0 + - libcxx >=22.1.7 + - libllvm22 >=22.1.7,<22.2.0a0 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + run_exports: + weak: + - libclang-cpp22.1 >=22.1.7,<22.2.0a0 + size: 15007643 + timestamp: 1780524215578 +- conda: https://prefix.dev/conda-forge/osx-64/libclang13-22.1.7-default_h2429e1b_1.conda + sha256: a9c032f78b73c702948230c3ba8afed31f54213316bf5beb767303500973b585 + md5: 366d0c7b1675b6af6bad3ec17be9fe2a + depends: + - __osx >=11.0 + - libcxx >=22.1.7 + - libllvm22 >=22.1.7,<22.2.0a0 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + run_exports: + weak: + - libclang13 >=22.1.7 + size: 9464895 + timestamp: 1780524651031 +- conda: https://prefix.dev/conda-forge/osx-64/libcompiler-rt-22.1.7-h1637cdf_0.conda + sha256: d0ef06b0c7d1312e572f3726b867f81e22eed158e6255b66e58448ede7647b49 + md5: 45d588315fef679cd57cf06ccbc1a6ab + depends: + - __osx >=11.0 + constrains: + - compiler-rt >=9.0.1 + license: Apache-2.0 WITH LLVM-exception + license_family: APACHE + run_exports: + weak: + - libcompiler-rt >=22.1.7 + size: 1374021 + timestamp: 1780458717254 +- conda: https://prefix.dev/conda-forge/osx-64/libcurl-8.20.0-h8f0b9e4_0.conda + sha256: 5d3d8a82ca43347e96f1d79048921f3a7c25e32514bc7feb53ed2a040dcca54d + md5: 4a0085ccf90dc514f0fc0909a874045e + depends: + - __osx >=11.0 + - krb5 >=1.22.2,<1.23.0a0 + - libnghttp2 >=1.68.1,<2.0a0 + - libssh2 >=1.11.1,<2.0a0 + - libzlib >=1.3.2,<2.0a0 + - openssl >=3.5.6,<4.0a0 + - zstd >=1.5.7,<1.6.0a0 + license: curl + license_family: MIT + run_exports: + weak: + - libcurl >=8.20.0,<9.0a0 + size: 419676 + timestamp: 1777462238769 +- conda: https://prefix.dev/conda-forge/osx-64/libcxx-22.1.7-h19cb2f5_0.conda + sha256: c03c298355dea54b729ed6c5f1e6dbd0e2426906039eba8aa2ba1254d005b7d8 + md5: 423373b842c3861da6cfa8c8915798ce + depends: + - __osx >=11.0 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + run_exports: {} + size: 564939 + timestamp: 1780442565078 +- conda: https://prefix.dev/conda-forge/osx-64/libcxx-devel-22.1.7-h7c275be_0.conda + sha256: 0edb65123ffe6cd42a600c00a2cb5788159e684fd8c8722597a4dd11ccc1a974 + md5: a33b3177fcd572fb864e074bb317c44f + depends: + - libcxx >=22.1.7 + - libcxx-headers >=22.1.7,<22.1.8.0a0 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + run_exports: {} + size: 22337 + timestamp: 1780442600081 +- conda: https://prefix.dev/conda-forge/osx-64/libedit-3.1.20250104-pl5321ha958ccf_0.conda + sha256: 6cc49785940a99e6a6b8c6edbb15f44c2dd6c789d9c283e5ee7bdfedd50b4cd6 + md5: 1f4ed31220402fcddc083b4bff406868 + depends: + - ncurses + - __osx >=10.13 + - ncurses >=6.5,<7.0a0 + license: BSD-2-Clause + license_family: BSD + run_exports: + weak: + - libedit >=3.1.20250104,<3.2.0a0 + size: 115563 + timestamp: 1738479554273 +- conda: https://prefix.dev/conda-forge/osx-64/libev-4.33-h10d778d_2.conda + sha256: 0d238488564a7992942aa165ff994eca540f687753b4f0998b29b4e4d030ff43 + md5: 899db79329439820b7e8f8de41bca902 + license: BSD-2-Clause + license_family: BSD + run_exports: + weak: + - libev >=4.33,<4.34.0a0 + size: 106663 + timestamp: 1702146352558 +- conda: https://prefix.dev/conda-forge/osx-64/libexpat-2.8.1-hcc62823_0.conda + sha256: 460afe7ba0882e6d2fcc0ad1568dce27025110ec09c2b9ce9e3b49d61e52ce6b + md5: f95dc08366f2a452005062b5bcceac51 + depends: + - __osx >=11.0 + constrains: + - expat 2.8.1.* + license: MIT + license_family: MIT + run_exports: {} + size: 75654 + timestamp: 1779279058576 +- conda: https://prefix.dev/conda-forge/osx-64/libiconv-1.18-h57a12c2_2.conda + sha256: a1c8cecdf9966921e13f0ae921309a1f415dfbd2b791f2117cf7e8f5e61a48b6 + md5: 210a85a1119f97ea7887188d176db135 + depends: + - __osx >=10.13 + license: LGPL-2.1-only + run_exports: + weak: + - libiconv >=1.18,<2.0a0 + size: 737846 + timestamp: 1754908900138 +- conda: https://prefix.dev/conda-forge/osx-64/libllvm22-22.1.7-hab754da_0.conda + sha256: 9ef76e7c6a078cbead8a462af85cfae4f8fe2a9480ec0ee483f00332703a02ca + md5: c198bc1edfa11159777da98e194d06f3 + depends: + - __osx >=11.0 + - libcxx >=19 + - libxml2 + - libxml2-16 >=2.14.6 + - libzlib >=1.3.2,<2.0a0 + - zstd >=1.5.7,<1.6.0a0 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + run_exports: + weak: + - libllvm22 >=22.1.7,<22.2.0a0 + size: 31842884 + timestamp: 1780447725513 +- conda: https://prefix.dev/conda-forge/osx-64/liblzma-5.8.3-hbb4bfdb_0.conda + sha256: d9e2006051529aec5578c6efeb13bb6a7200a014b2d5a77a579e83a8049d5f3c + md5: becdfbfe7049fa248e52aa37a9df09e2 + depends: + - __osx >=11.0 + constrains: + - xz 5.8.3.* + license: 0BSD + run_exports: + weak: + - liblzma >=5.8.3,<6.0a0 + size: 105724 + timestamp: 1775826029494 +- conda: https://prefix.dev/conda-forge/osx-64/libnghttp2-1.68.1-h70048d4_0.conda + sha256: 899551e16aac9dfb85bfc2fd98b655f4d1b7fea45720ec04ccb93d95b4d24798 + md5: dba4c95e2fe24adcae4b77ebf33559ae + depends: + - __osx >=11.0 + - c-ares >=1.34.6,<2.0a0 + - libcxx >=19 + - libev >=4.33,<4.34.0a0 + - libev >=4.33,<5.0a0 + - libzlib >=1.3.1,<2.0a0 + - openssl >=3.5.5,<4.0a0 + license: MIT + license_family: MIT + run_exports: + weak: + - libnghttp2 >=1.68.1,<2.0a0 + size: 606749 + timestamp: 1773854765508 +- conda: https://prefix.dev/conda-forge/osx-64/libsigtool-0.1.3-hc0f2934_0.conda + sha256: f87b743d5ab11c1a8ddd800dd9357fc0fabe47686068232ddc1d1eed0d7321ec + md5: 3576aba85ce5e9ab15aa0ea376ab864b + depends: + - __osx >=10.13 + - openssl >=3.5.4,<4.0a0 + license: MIT + license_family: MIT + run_exports: {} + size: 38085 + timestamp: 1767044977731 +- conda: https://prefix.dev/conda-forge/osx-64/libssh2-1.11.1-hed3591d_0.conda + sha256: 00654ba9e5f73aa1f75c1f69db34a19029e970a4aeb0fa8615934d8e9c369c3c + md5: a6cb15db1c2dc4d3a5f6cf3772e09e81 + depends: + - __osx >=10.13 + - libzlib >=1.3.1,<2.0a0 + - openssl >=3.5.0,<4.0a0 + license: BSD-3-Clause + license_family: BSD + run_exports: + weak: + - libssh2 >=1.11.1,<2.0a0 + size: 284216 + timestamp: 1745608575796 +- conda: https://prefix.dev/conda-forge/osx-64/libuv-1.52.1-ha3d0635_0.conda + sha256: a77c3832a82b26afe8da3f4bbacca58a943cc62f2a5680547913650527a51299 + md5: 703303067839cd1da659528a84b3c0cc + depends: + - __osx >=11.0 + license: MIT + license_family: MIT + run_exports: + weak: + - libuv >=1.52.1,<2.0a0 + size: 128150 + timestamp: 1779396112490 +- conda: https://prefix.dev/conda-forge/osx-64/libxml2-16-2.15.3-h0d7f165_0.conda + sha256: daa69a1dd887b2dbac44327bc5af73a4d41fa63bc6dc609782fdda9aec187895 + md5: 5eb194ed01ed3f5a64b6fcec1b399d96 + depends: + - __osx >=11.0 + - libiconv >=1.18,<2.0a0 + - liblzma >=5.8.3,<6.0a0 + - libzlib >=1.3.2,<2.0a0 + constrains: + - icu <0.0a0 + - libxml2 2.15.3 + license: MIT + license_family: MIT + run_exports: {} + size: 495267 + timestamp: 1776377547505 +- conda: https://prefix.dev/conda-forge/osx-64/libxml2-2.15.3-h0712280_0.conda + sha256: caf6e73fa53c3dec3227ea67de231b0f7009544252684e816c6f2f414aeb55c9 + md5: 81ac54c8b2eb51fceb94eb0817b93cf3 + depends: + - __osx >=11.0 + - libiconv >=1.18,<2.0a0 + - liblzma >=5.8.3,<6.0a0 + - libxml2-16 2.15.3 h0d7f165_0 + - libzlib >=1.3.2,<2.0a0 + constrains: + - icu <0.0a0 + license: MIT + license_family: MIT + run_exports: + weak: + - libxml2 + - libxml2-16 >=2.15.3 + size: 40803 + timestamp: 1776377589058 +- conda: https://prefix.dev/conda-forge/osx-64/libzlib-1.3.2-hbb4bfdb_2.conda + sha256: 4c6da089952b2d70150c74234679d6f7ac04f4a98f9432dec724968f912691e7 + md5: 30439ff30578e504ee5e0b390afc8c65 + depends: + - __osx >=11.0 + constrains: + - zlib 1.3.2 *_2 + license: Zlib + license_family: Other + run_exports: + weak: + - libzlib >=1.3.2,<2.0a0 + size: 59000 + timestamp: 1774073052242 +- conda: https://prefix.dev/conda-forge/osx-64/llvm-tools-22-22.1.7-hc181bea_0.conda + sha256: 86158dd6e99018e83c4ecd0d504511efd284d242d891723b6fc7edab1fd41b44 + md5: 7b43a01695fe09c7786a99907312c588 + depends: + - __osx >=11.0 + - libcxx >=19 + - libllvm22 22.1.7 hab754da_0 + - libzlib >=1.3.2,<2.0a0 + - zstd >=1.5.7,<1.6.0a0 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + run_exports: {} + size: 18996311 + timestamp: 1780447964134 +- conda: https://prefix.dev/conda-forge/osx-64/llvm-tools-22.1.7-h1637cdf_0.conda + sha256: 432f04a68a18e487f4339d89bf8cea1054850fb92d0e3397605c219382892666 + md5: 40a7058aac858d574e37265a03b49777 + depends: + - __osx >=11.0 + - libllvm22 22.1.7 hab754da_0 + - llvm-tools-22 22.1.7 hc181bea_0 + constrains: + - llvm 22.1.7 + - clang-tools 22.1.7 + - clang 22.1.7 + - llvmdev 22.1.7 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + run_exports: {} + size: 52128 + timestamp: 1780448062183 +- conda: https://prefix.dev/conda-forge/osx-64/ncurses-6.6-hcc0dc9a_0.conda + sha256: f5f7e006ff4271305ab4cc08eedd855c67a571793c3d18aff73f645f088a8cae + md5: 31b8740cf1b2588d4e61c81191004061 + depends: + - __osx >=11.0 + license: X11 AND BSD-3-Clause + run_exports: + weak: + - ncurses >=6.6,<7.0a0 + size: 831711 + timestamp: 1777423052277 +- conda: https://prefix.dev/conda-forge/osx-64/ninja-1.13.2-hfc0b2d5_0.conda + sha256: 1646832e3c2389595569ab9a6234c119a4dedf6f4e55532a8bf07edab7f8037d + md5: afda563484aa0017278866707807a335 + depends: + - libcxx >=19 + - __osx >=10.13 + license: Apache-2.0 + license_family: APACHE + run_exports: {} + size: 178071 + timestamp: 1763688235442 +- conda: https://prefix.dev/conda-forge/osx-64/openssl-3.6.2-hc881268_0.conda + sha256: 334fd49ea31b99114f5afb1ec44555dc8c90640648302a4f8f838ee345d1ec50 + md5: 5cf0ece4375c73d7a5765e83565a69c7 + depends: + - __osx >=11.0 + - ca-certificates + license: Apache-2.0 + license_family: Apache + run_exports: + weak: + - openssl >=3.6.2,<4.0a0 + size: 2776564 + timestamp: 1775589970694 +- conda: https://prefix.dev/conda-forge/osx-64/rhash-1.4.6-h6e16a3a_1.conda + sha256: 65c946fc5a9bb71772a7ac9bad64ff08ac07f7d5311306c2dcc1647157b96706 + md5: d0fcaaeff83dd4b6fb035c2f36df198b + depends: + - __osx >=10.13 + license: MIT + license_family: MIT + run_exports: + weak: + - rhash >=1.4.6,<2.0a0 + size: 185180 + timestamp: 1748644989546 +- conda: https://prefix.dev/conda-forge/osx-64/sigtool-codesign-0.1.3-hc0f2934_0.conda + sha256: b89d89d0b62e0a84093205607d071932cca228d4d6982a5b073eec7e765b146d + md5: 1261fc730f1d8af7eeea8a0024b23493 + depends: + - __osx >=10.13 + - libsigtool 0.1.3 hc0f2934_0 + - openssl >=3.5.4,<4.0a0 + license: MIT + license_family: MIT + run_exports: {} + size: 123083 + timestamp: 1767045007433 +- conda: https://prefix.dev/conda-forge/osx-64/tapi-1600.0.11.8-h8d8e812_2.conda + sha256: 0e814730160c8e214eadd7905e3659d8f52af86fd37d85fd287060748948a2b8 + md5: 524528dee57e42d77b1af677137de5a5 + depends: + - libcxx >=19.0.0.a0 + - __osx >=10.13 + - ncurses >=6.5,<7.0a0 + license: NCSA + run_exports: {} + size: 213790 + timestamp: 1775657389876 +- conda: https://prefix.dev/conda-forge/osx-64/zstd-1.5.7-h3eecb57_6.conda + sha256: 47101a4055a70a4876ffc87b750ab2287b67eca793f21c8224be5e1ee6394d3f + md5: 727109b184d680772e3122f40136d5ca + depends: + - __osx >=10.13 + - libzlib >=1.3.1,<2.0a0 + license: BSD-3-Clause + license_family: BSD + run_exports: + weak: + - zstd >=1.5.7,<1.6.0a0 + size: 528148 + timestamp: 1764777156963 +- conda: https://prefix.dev/conda-forge/osx-arm64/bzip2-1.0.8-hd037594_9.conda + sha256: 540fe54be35fac0c17feefbdc3e29725cce05d7367ffedfaaa1bdda234b019df + md5: 620b85a3f45526a8bc4d23fd78fc22f0 + depends: + - __osx >=11.0 + license: bzip2-1.0.6 + license_family: BSD + run_exports: + weak: + - bzip2 >=1.0.8,<2.0a0 + size: 124834 + timestamp: 1771350416561 +- conda: https://prefix.dev/conda-forge/osx-arm64/c-ares-1.34.6-hc919400_0.conda + sha256: 2995f2aed4e53725e5efbc28199b46bf311c3cab2648fc4f10c2227d6d5fa196 + md5: bcb3cba70cf1eec964a03b4ba7775f01 + depends: + - __osx >=11.0 + license: MIT + license_family: MIT + run_exports: + weak: + - c-ares >=1.34.6,<2.0a0 + size: 180327 + timestamp: 1765215064054 +- conda: https://prefix.dev/conda-forge/osx-arm64/cctools_impl_osx-arm64-1030.6.3-llvm22_1_hb5e89dc_4.conda + sha256: 97075a1afeac8a7a4dca258ac10efb70638e3c734cbf5a6328ca1e0718e09c41 + md5: 97768bb89683757d7e535f9b7dcba39d + depends: + - __osx >=11.0 + - ld64_osx-arm64 >=956.6,<956.7.0a0 + - libcxx + - libllvm22 >=22.1.0,<22.2.0a0 + - libzlib >=1.3.1,<2.0a0 + - llvm-tools 22.1.* + - sigtool-codesign + constrains: + - clang 22.1.* + - ld64 956.6.* + - cctools 1030.6.3.* + license: APSL-2.0 + license_family: Other + run_exports: {} + size: 749166 + timestamp: 1772019681419 +- conda: https://prefix.dev/conda-forge/osx-arm64/cctools_osx-arm64-1030.6.3-llvm22_1_hbe26303_4.conda + sha256: c90c927dd77afb7d8115a3777b567d9ab84169ab797436d79789d75d0bd1a399 + md5: a08c9f61e81b5d4a0a653495545ec2b8 + depends: + - cctools_impl_osx-arm64 1030.6.3 llvm22_1_hb5e89dc_4 + - ld64_osx-arm64 956.6 llvm22_1_h692d5aa_4 + constrains: + - cctools 1030.6.3.* + license: APSL-2.0 + license_family: Other + run_exports: {} + size: 23468 + timestamp: 1772019757885 +- conda: https://prefix.dev/conda-forge/osx-arm64/clang-22-22.1.7-default_hd632d02_1.conda + sha256: 3a438c7a27c86ef14a41c991b8688ef53efe92ad1db8ae930f27fce410ca843a + md5: 36f28e96e3bff9566e44cc625b87408c + depends: + - __osx >=11.0 + - compiler-rt22 22.1.7.* + - libclang-cpp22.1 22.1.7 default_h8e162e0_1 + - libcxx >=22.1.7 + - libllvm22 >=22.1.7,<22.2.0a0 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + run_exports: {} + size: 830975 + timestamp: 1780519560746 +- conda: https://prefix.dev/conda-forge/osx-arm64/clang-scan-deps-22.1.7-default_h8e162e0_1.conda + sha256: e74079f18114767f34cf04bdae1fc682298de8cb18ea1257a40b2b4353e8f444 + md5: 8f7f50694d61c2575ff4c3b5fc670f11 + depends: + - __osx >=11.0 + - libclang-cpp22.1 >=22.1.7,<22.2.0a0 + - libclang13 >=22.1.7 + - libcxx >=22.1.7 + - libllvm22 >=22.1.7,<22.2.0a0 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + run_exports: {} + size: 103797 + timestamp: 1780519799318 +- conda: https://prefix.dev/conda-forge/osx-arm64/clang_impl_osx-arm64-22.1.7-default_h17d1ed9_1.conda + sha256: 09a6fa56849653389f4db79e548832dda874fa9255740a292adec0941a6b8902 + md5: 87567b36faebd1d3423321f5122096ae + depends: + - cctools_impl_osx-arm64 + - clang-22 22.1.7 default_hd632d02_1 + - compiler-rt 22.1.7.* + - compiler-rt_osx-arm64 + - ld64_osx-arm64 * llvm22_1_* + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + run_exports: {} + size: 29007 + timestamp: 1780519625415 +- conda: https://prefix.dev/conda-forge/osx-arm64/clang_osx-arm64-22.1.7-hf119d2b_32.conda + sha256: a14407fdd92a35b3410796b20f209abbe53f59ea6417c66bf900730a1efdf203 + md5: 75afaa2f7151ace4f1fff9b676db4d2e + depends: + - cctools_osx-arm64 + - clang_impl_osx-arm64 22.1.7.* + - sdkroot_env_osx-arm64 + license: BSD-3-Clause + license_family: BSD + run_exports: {} + size: 21218 + timestamp: 1780546185093 +- conda: https://prefix.dev/conda-forge/osx-arm64/clangxx_impl_osx-arm64-22.1.7-default_h17d1ed9_1.conda + sha256: 67decf053bc8af5988df69da7fe72ea6347969695eb34866e483514a03f2535e + md5: b102716463b3dfb518abcede39b8d44a + depends: + - clang-22 22.1.7 default_hd632d02_1 + - clang-scan-deps 22.1.7 default_h8e162e0_1 + - clang_impl_osx-arm64 22.1.7 default_h17d1ed9_1 + - libcxx-devel 22.1.* + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + run_exports: {} + size: 29025 + timestamp: 1780519815159 +- conda: https://prefix.dev/conda-forge/osx-arm64/clangxx_osx-arm64-22.1.7-hf119d2b_32.conda + sha256: 2da93e46edee5bafeeab737cbeaad6670c699c423caae09ccad81afa31332a4f + md5: ddeb6549d832fae2d6a2cd6a297f17bf + depends: + - cctools_osx-arm64 + - clang_osx-arm64 22.1.7 hf119d2b_32 + - clangxx_impl_osx-arm64 22.1.7.* + - sdkroot_env_osx-arm64 + license: BSD-3-Clause + license_family: BSD + run_exports: + strong: + - libcxx >=22 + size: 20064 + timestamp: 1780546187683 +- conda: https://prefix.dev/conda-forge/osx-arm64/cmake-4.3.3-h8cb302d_0.conda + sha256: 09eab0e2876eeee3f619223e151b788e157771b7150038ee07fa768e8aff8e9e + md5: 7a6a2812529d5c8fa77c2653e303ba4f + depends: + - __osx >=11.0 + - bzip2 >=1.0.8,<2.0a0 + - libcurl >=8.20.0,<9.0a0 + - libcxx >=19 + - libexpat >=2.8.1,<3.0a0 + - liblzma >=5.8.3,<6.0a0 + - libuv >=1.51.0,<2.0a0 + - libzlib >=1.3.2,<2.0a0 + - ncurses >=6.6,<7.0a0 + - rhash >=1.4.6,<2.0a0 + - zstd >=1.5.7,<1.6.0a0 + license: BSD-3-Clause + license_family: BSD + run_exports: {} + size: 18285327 + timestamp: 1779399044060 +- conda: https://prefix.dev/conda-forge/osx-arm64/compiler-rt-22.1.7-hce30654_0.conda + sha256: 721b702d79bf70de4e938e552dbae794ff60590ceb4594bd5dadcaf77fa90c8b + md5: c5bf9cc793f5cab214f90c5c0e1851e6 + depends: + - compiler-rt22 22.1.7 hd34ed20_0 + - libcompiler-rt 22.1.7 hd34ed20_0 + constrains: + - clang 22.1.7 + license: Apache-2.0 WITH LLVM-exception + license_family: APACHE + run_exports: {} + size: 16641 + timestamp: 1780457650764 +- conda: https://prefix.dev/conda-forge/osx-arm64/compiler-rt22-22.1.7-hd34ed20_0.conda + sha256: cfe6a196223f735b49b093586359615e059d9944b3cf049101a20ce135a94300 + md5: 3893c0e24c5f19efb9138762f0eb693c + depends: + - __osx >=11.0 + - compiler-rt22_osx-arm64 22.1.7.* + license: Apache-2.0 WITH LLVM-exception + license_family: APACHE + run_exports: {} + size: 98795 + timestamp: 1780457649475 +- conda: https://prefix.dev/conda-forge/osx-arm64/krb5-1.22.2-h385eeb1_0.conda + sha256: c0a0bf028fe7f3defcdcaa464e536cf1b202d07451e18ad83fdd169d15bef6ed + md5: e446e1822f4da8e5080a9de93474184d + depends: + - __osx >=11.0 + - libcxx >=19 + - libedit >=3.1.20250104,<3.2.0a0 + - libedit >=3.1.20250104,<4.0a0 + - openssl >=3.5.5,<4.0a0 + license: MIT + license_family: MIT + run_exports: + weak: + - krb5 >=1.22.2,<1.23.0a0 + size: 1160828 + timestamp: 1769770119811 +- conda: https://prefix.dev/conda-forge/osx-arm64/ld64_osx-arm64-956.6-llvm22_1_h692d5aa_4.conda + sha256: e4ae2ef85672c094aa3467d466f932ccdc1dda9bd4adac64f4252cc796149091 + md5: 4c2255bf859bff6c52ed38960e3bc963 + depends: + - __osx >=11.0 + - libcxx + - libllvm22 >=22.1.0,<22.2.0a0 + - sigtool-codesign + - tapi >=1600.0.11.8,<1601.0a0 + constrains: + - clang 22.1.* + - ld64 956.6.* + - cctools_impl_osx-arm64 1030.6.3.* + - cctools 1030.6.3.* + license: APSL-2.0 + license_family: Other + run_exports: {} + size: 1038027 + timestamp: 1772019602406 +- conda: https://prefix.dev/conda-forge/osx-arm64/libclang-cpp22.1-22.1.7-default_h8e162e0_1.conda + sha256: 27fe54bb8da8a80793bbd9346324cfbc9609cee498b79d6ae8cbd89e09c197be + md5: 08dd791ea92568bdca26bb174b2c0e3a + depends: + - __osx >=11.0 + - libcxx >=22.1.7 + - libllvm22 >=22.1.7,<22.2.0a0 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + run_exports: + weak: + - libclang-cpp22.1 >=22.1.7,<22.2.0a0 + size: 14193041 + timestamp: 1780519486860 +- conda: https://prefix.dev/conda-forge/osx-arm64/libclang13-22.1.7-default_h6dd9417_1.conda + sha256: ec991f3050b3b43eeee6fc8697f5a25306a38f53d7cfdf80ab4e2587d21032b3 + md5: 3c8a80bf352e08e0d656b0f60a0a2980 + depends: + - __osx >=11.0 + - libcxx >=22.1.7 + - libllvm22 >=22.1.7,<22.2.0a0 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + run_exports: + weak: + - libclang13 >=22.1.7 + size: 8937899 + timestamp: 1780519686958 +- conda: https://prefix.dev/conda-forge/osx-arm64/libcompiler-rt-22.1.7-hd34ed20_0.conda + sha256: 35f6b1f2a1e61e043eb17aab49cccf65234d7cb137f26ed87ea7163f6937ab6b + md5: f5766b2bf9c3630b9bef99319629531d + depends: + - __osx >=11.0 + constrains: + - compiler-rt >=9.0.1 + license: Apache-2.0 WITH LLVM-exception + license_family: APACHE + run_exports: + weak: + - libcompiler-rt >=22.1.7 + size: 1373087 + timestamp: 1780457641235 +- conda: https://prefix.dev/conda-forge/osx-arm64/libcurl-8.20.0-hd5a2499_0.conda + sha256: 38c0bc634b61e542776e97cfd15d5d41edd304d4e47c333004d2d622439b2381 + md5: 2f57b7d0c6adda88957586b7afd78438 + depends: + - __osx >=11.0 + - krb5 >=1.22.2,<1.23.0a0 + - libnghttp2 >=1.68.1,<2.0a0 + - libssh2 >=1.11.1,<2.0a0 + - libzlib >=1.3.2,<2.0a0 + - openssl >=3.5.6,<4.0a0 + - zstd >=1.5.7,<1.6.0a0 + license: curl + license_family: MIT + run_exports: + weak: + - libcurl >=8.20.0,<9.0a0 + size: 400568 + timestamp: 1777462251987 +- conda: https://prefix.dev/conda-forge/osx-arm64/libcxx-22.1.7-h55c6f16_0.conda + sha256: cceb668dc1b71f054b1036dd83eca2e02c0c3a4b2ba3ad28c74a982d819597a3 + md5: 0325fbe13eb6dd39234eb305ac1b3cb8 + depends: + - __osx >=11.0 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + run_exports: {} + size: 568252 + timestamp: 1780441702930 +- conda: https://prefix.dev/conda-forge/osx-arm64/libcxx-devel-22.1.7-h6dc3340_0.conda + sha256: 65eb55a59ba4f5a63d54c91ade942f0cd17a40c1390a390d3b46aec5e3dffbdb + md5: 3b3d6232b366a7d93956320b1b26c871 + depends: + - libcxx >=22.1.7 + - libcxx-headers >=22.1.7,<22.1.8.0a0 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + run_exports: {} + size: 22195 + timestamp: 1780441714190 +- conda: https://prefix.dev/conda-forge/osx-arm64/libedit-3.1.20250104-pl5321hafb1f1b_0.conda + sha256: 66aa216a403de0bb0c1340a88d1a06adaff66bae2cfd196731aa24db9859d631 + md5: 44083d2d2c2025afca315c7a172eab2b + depends: + - ncurses + - __osx >=11.0 + - ncurses >=6.5,<7.0a0 + license: BSD-2-Clause + license_family: BSD + run_exports: + weak: + - libedit >=3.1.20250104,<3.2.0a0 + size: 107691 + timestamp: 1738479560845 +- conda: https://prefix.dev/conda-forge/osx-arm64/libev-4.33-h93a5062_2.conda + sha256: 95cecb3902fbe0399c3a7e67a5bed1db813e5ab0e22f4023a5e0f722f2cc214f + md5: 36d33e440c31857372a72137f78bacf5 + license: BSD-2-Clause + license_family: BSD + run_exports: + weak: + - libev >=4.33,<4.34.0a0 + size: 107458 + timestamp: 1702146414478 +- conda: https://prefix.dev/conda-forge/osx-arm64/libexpat-2.8.1-hf6b4638_0.conda + sha256: 3133fb6bfa871288b92c8b8752696686a841bf4ffe035aa3038033c9e15b738e + md5: ef22e9ab1dc7c2f334252f565f90b3b8 + depends: + - __osx >=11.0 + constrains: + - expat 2.8.1.* + license: MIT + license_family: MIT + run_exports: {} + size: 69110 + timestamp: 1779278728511 +- conda: https://prefix.dev/conda-forge/osx-arm64/libiconv-1.18-h23cfdf5_2.conda + sha256: de0336e800b2af9a40bdd694b03870ac4a848161b35c8a2325704f123f185f03 + md5: 4d5a7445f0b25b6a3ddbb56e790f5251 + depends: + - __osx >=11.0 + license: LGPL-2.1-only + run_exports: + weak: + - libiconv >=1.18,<2.0a0 + size: 750379 + timestamp: 1754909073836 +- conda: https://prefix.dev/conda-forge/osx-arm64/libllvm22-22.1.7-h89af1be_0.conda + sha256: 533929d04a94ee43431c6f7f0916b0f5a387f6b02b5339f06301bbfa9e180c84 + md5: 0525fa45bcc945c301ee8f583a442ce1 + depends: + - __osx >=11.0 + - libcxx >=19 + - libxml2 + - libxml2-16 >=2.14.6 + - libzlib >=1.3.2,<2.0a0 + - zstd >=1.5.7,<1.6.0a0 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + run_exports: + weak: + - libllvm22 >=22.1.7,<22.2.0a0 + size: 30014727 + timestamp: 1780441538232 +- conda: https://prefix.dev/conda-forge/osx-arm64/liblzma-5.8.3-h8088a28_0.conda + sha256: 34878d87275c298f1a732c6806349125cebbf340d24c6c23727268184bba051e + md5: b1fd823b5ae54fbec272cea0811bd8a9 + depends: + - __osx >=11.0 + constrains: + - xz 5.8.3.* + license: 0BSD + run_exports: + weak: + - liblzma >=5.8.3,<6.0a0 + size: 92472 + timestamp: 1775825802659 +- conda: https://prefix.dev/conda-forge/osx-arm64/libnghttp2-1.68.1-h8f3e76b_0.conda + sha256: 2bc7bc3978066f2c274ebcbf711850cc9ab92e023e433b9631958a098d11e10a + md5: 6ea18834adbc3b33df9bd9fb45eaf95b + depends: + - __osx >=11.0 + - c-ares >=1.34.6,<2.0a0 + - libcxx >=19 + - libev >=4.33,<4.34.0a0 + - libev >=4.33,<5.0a0 + - libzlib >=1.3.1,<2.0a0 + - openssl >=3.5.5,<4.0a0 + license: MIT + license_family: MIT + run_exports: + weak: + - libnghttp2 >=1.68.1,<2.0a0 + size: 576526 + timestamp: 1773854624224 +- conda: https://prefix.dev/conda-forge/osx-arm64/libsigtool-0.1.3-h98dc951_0.conda + sha256: 421f7bd7caaa945d9cd5d374cc3f01e75637ca7372a32d5e7695c825a48a30d1 + md5: c08557d00807785decafb932b5be7ef5 + depends: + - __osx >=11.0 + - openssl >=3.5.4,<4.0a0 + license: MIT + license_family: MIT + run_exports: {} + size: 36416 + timestamp: 1767045062496 +- conda: https://prefix.dev/conda-forge/osx-arm64/libssh2-1.11.1-h1590b86_0.conda + sha256: 8bfe837221390ffc6f111ecca24fa12d4a6325da0c8d131333d63d6c37f27e0a + md5: b68e8f66b94b44aaa8de4583d3d4cc40 + depends: + - libzlib >=1.3.1,<2.0a0 + - openssl >=3.5.0,<4.0a0 + license: BSD-3-Clause + license_family: BSD + run_exports: + weak: + - libssh2 >=1.11.1,<2.0a0 + size: 279193 + timestamp: 1745608793272 +- conda: https://prefix.dev/conda-forge/osx-arm64/libuv-1.52.1-h1a92334_0.conda + sha256: e23176af832f637693ebbb9bbe7d29c0f4cba662dabd001081d2aa6fc9f7f661 + md5: fa9fef7d9f33724b7c3899c883c25a3e + depends: + - __osx >=11.0 + license: MIT + license_family: MIT + run_exports: + weak: + - libuv >=1.52.1,<2.0a0 + size: 122732 + timestamp: 1779396113397 +- conda: https://prefix.dev/conda-forge/osx-arm64/libxml2-16-2.15.3-h6967ea9_0.conda + sha256: 43895a7517c055b8893531290f9dc48bd751eb04be04f14bbce3b6c71b052be6 + md5: 6c8292c2ee808aeef2406083beaa6da7 + depends: + - __osx >=11.0 + - libiconv >=1.18,<2.0a0 + - liblzma >=5.8.3,<6.0a0 + - libzlib >=1.3.2,<2.0a0 + constrains: + - libxml2 2.15.3 + - icu <0.0a0 + license: MIT + license_family: MIT + run_exports: {} + size: 465820 + timestamp: 1776377317454 +- conda: https://prefix.dev/conda-forge/osx-arm64/libxml2-2.15.3-heed7d32_0.conda + sha256: 4d9c117b2dd222cf891710d5f6a570ebb275479979843a1477ac54ed50907b40 + md5: 0c1fdc80534d8f25fd74722aba81f044 + depends: + - __osx >=11.0 + - libiconv >=1.18,<2.0a0 + - liblzma >=5.8.3,<6.0a0 + - libxml2-16 2.15.3 h6967ea9_0 + - libzlib >=1.3.2,<2.0a0 + constrains: + - icu <0.0a0 + license: MIT + license_family: MIT + run_exports: + weak: + - libxml2 + - libxml2-16 >=2.15.3 + size: 41663 + timestamp: 1776377341241 +- conda: https://prefix.dev/conda-forge/osx-arm64/libzlib-1.3.2-h8088a28_2.conda + sha256: 361415a698514b19a852f5d1123c5da746d4642139904156ddfca7c922d23a05 + md5: bc5a5721b6439f2f62a84f2548136082 + depends: + - __osx >=11.0 + constrains: + - zlib 1.3.2 *_2 + license: Zlib + license_family: Other + run_exports: + weak: + - libzlib >=1.3.2,<2.0a0 + size: 47759 + timestamp: 1774072956767 +- conda: https://prefix.dev/conda-forge/osx-arm64/llvm-tools-22-22.1.7-hb545844_0.conda + sha256: fd44ba14755380db3d89b75485c2e9a9982fefe54e7853d9a91a250948b2c48c + md5: 14e37880dc53c9da027752c005ddb7ec + depends: + - __osx >=11.0 + - libcxx >=19 + - libllvm22 22.1.7 h89af1be_0 + - libzlib >=1.3.2,<2.0a0 + - zstd >=1.5.7,<1.6.0a0 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + run_exports: {} + size: 17845007 + timestamp: 1780441650670 +- conda: https://prefix.dev/conda-forge/osx-arm64/llvm-tools-22.1.7-hd34ed20_0.conda + sha256: eafdac4500c69bed1e5964efc8f6a024a4a70f57a91e5c5e099bc9ed5ff4695b + md5: b0eff8fdd52342dc666a05ba33acf8f8 + depends: + - __osx >=11.0 + - libllvm22 22.1.7 h89af1be_0 + - llvm-tools-22 22.1.7 hb545844_0 + constrains: + - clang-tools 22.1.7 + - llvmdev 22.1.7 + - clang 22.1.7 + - llvm 22.1.7 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + run_exports: {} + size: 52222 + timestamp: 1780441714363 +- conda: https://prefix.dev/conda-forge/osx-arm64/ncurses-6.6-h1d4f5a5_0.conda + sha256: 4ea6c620b87bd1d42bb2ccc2c87cd2483fa2d7f9e905b14c223f11ff3f4c455d + md5: 343d10ed5b44030a2f67193905aea159 + depends: + - __osx >=11.0 + license: X11 AND BSD-3-Clause + run_exports: + weak: + - ncurses >=6.6,<7.0a0 + size: 805509 + timestamp: 1777423252320 +- conda: https://prefix.dev/conda-forge/osx-arm64/ninja-1.13.2-h49c215f_0.conda + sha256: 18d33c17b28d4771fc0b91b7b963c9ce31aca0a9af7dc8e9ee7c974bb207192c + md5: 175809cc57b2c67f27a0f238bd7f069d + depends: + - __osx >=11.0 + - libcxx >=19 + license: Apache-2.0 + license_family: APACHE + run_exports: {} + size: 164450 + timestamp: 1763688228613 +- conda: https://prefix.dev/conda-forge/osx-arm64/openssl-3.6.2-hd24854e_0.conda + sha256: c91bf510c130a1ea1b6ff023e28bac0ccaef869446acd805e2016f69ebdc49ea + md5: 25dcccd4f80f1638428613e0d7c9b4e1 + depends: + - __osx >=11.0 + - ca-certificates + license: Apache-2.0 + license_family: Apache + run_exports: + weak: + - openssl >=3.6.2,<4.0a0 + size: 3106008 + timestamp: 1775587972483 +- conda: https://prefix.dev/conda-forge/osx-arm64/rhash-1.4.6-h5505292_1.conda + sha256: f4957c05f4fbcd99577de8838ca4b5b1ae4b400a44be647a0159c14f85b9bfc0 + md5: 029e812c8ae4e0d4cf6ff4f7d8dc9366 + depends: + - __osx >=11.0 + license: MIT + license_family: MIT + run_exports: + weak: + - rhash >=1.4.6,<2.0a0 + size: 185448 + timestamp: 1748645057503 +- conda: https://prefix.dev/conda-forge/osx-arm64/sigtool-codesign-0.1.3-h98dc951_0.conda + sha256: f3d006e2441f110160a684744d90921bbedbffa247d7599d7e76b5cd048116dc + md5: ade77ad7513177297b1d75e351e136ce + depends: + - __osx >=11.0 + - libsigtool 0.1.3 h98dc951_0 + - openssl >=3.5.4,<4.0a0 + license: MIT + license_family: MIT + run_exports: {} + size: 114331 + timestamp: 1767045086274 +- conda: https://prefix.dev/conda-forge/osx-arm64/tapi-1600.0.11.8-h997e182_2.conda + sha256: de6893e53664e769c1b1c4103a666d436e3d307c0eb6a09a164e749d116e80f7 + md5: 555070ad1e18b72de36e9ee7ed3236b3 + depends: + - libcxx >=19.0.0.a0 + - __osx >=11.0 + - ncurses >=6.5,<7.0a0 + license: NCSA + run_exports: {} + size: 200192 + timestamp: 1775657222120 +- conda: https://prefix.dev/conda-forge/osx-arm64/zstd-1.5.7-hbf9d68e_6.conda + sha256: 9485ba49e8f47d2b597dd399e88f4802e100851b27c21d7525625b0b4025a5d9 + md5: ab136e4c34e97f34fb621d2592a393d8 + depends: + - __osx >=11.0 + - libzlib >=1.3.1,<2.0a0 + license: BSD-3-Clause + license_family: BSD + run_exports: + weak: + - zstd >=1.5.7,<1.6.0a0 + size: 433413 + timestamp: 1764777166076 +- conda: https://prefix.dev/conda-forge/win-64/bzip2-1.0.8-h0ad9c76_9.conda + sha256: 76dfb71df5e8d1c4eded2dbb5ba15bb8fb2e2b0fe42d94145d5eed4c75c35902 + md5: 4cb8e6b48f67de0b018719cdf1136306 + depends: + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: bzip2-1.0.6 + license_family: BSD + run_exports: + weak: + - bzip2 >=1.0.8,<2.0a0 + size: 56115 + timestamp: 1771350256444 +- conda: https://prefix.dev/conda-forge/win-64/cmake-4.3.3-hdcbee5b_0.conda + sha256: c2a97bb9166930d4072a3113317e21cde0d685c74b95a73627b8e2bddaa3f75d + md5: 941d20cd011964387402776ff2b9e32a + depends: + - bzip2 >=1.0.8,<2.0a0 + - libcurl >=8.20.0,<9.0a0 + - libexpat >=2.8.1,<3.0a0 + - liblzma >=5.8.3,<6.0a0 + - libuv >=1.51.0,<2.0a0 + - libzlib >=1.3.2,<2.0a0 + - ucrt >=10.0.20348.0 + - vc14_runtime >=14.44.35208 + - zstd >=1.5.7,<1.6.0a0 + license: BSD-3-Clause + license_family: BSD + run_exports: {} + size: 16394712 + timestamp: 1779399232130 +- conda: https://prefix.dev/conda-forge/win-64/cuda-crt-tools-12.9.86-h57928b3_2.conda + sha256: fb2283a55820eeff84c861b469cfee6a9d0ac9aebe02e82aae480a60068a7659 + md5: d0057a8511cb12745675db18ccbec8f2 + depends: + - cuda-version >=12.9,<12.10.0a0 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: {} + size: 29604 + timestamp: 1753975679251 +- conda: https://prefix.dev/conda-forge/win-64/cuda-cudart-12.9.79-he0c23c2_0.conda + sha256: a30cd9adf3a70d069d4d87c5728ec16778b77071629612ca5d8513cd92d89c09 + md5: 0a243d4f000a0d2f51dd94ee9132b234 + depends: + - cuda-cudart_win-64 12.9.79 he0c23c2_0 + - cuda-version >=12.9,<12.10.0a0 + - ucrt >=10.0.20348.0 + - vc >=14.2,<15 + - vc14_runtime >=14.29.30139 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: {} + size: 170799 + timestamp: 1749218946117 +- conda: https://prefix.dev/conda-forge/win-64/cuda-cudart-dev-12.9.79-he0c23c2_0.conda + sha256: 1ee68f0ffd37889f0fc438d4da7124054b124632e1c3bc15950b9851b002473e + md5: e5bb074108bc2501f8374e80748aa181 + depends: + - cuda-cudart 12.9.79 he0c23c2_0 + - cuda-cudart-dev_win-64 12.9.79 he0c23c2_0 + - cuda-cudart-static 12.9.79 he0c23c2_0 + - cuda-version >=12.9,<12.10.0a0 + - ucrt >=10.0.20348.0 + - vc >=14.2,<15 + - vc14_runtime >=14.29.30139 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: + weak: + - cuda-cudart >=12.9.79,<13.0a0 + size: 23222 + timestamp: 1749219022963 +- conda: https://prefix.dev/conda-forge/win-64/cuda-cudart-static-12.9.79-he0c23c2_0.conda + sha256: 02d3ff9ec59c7f59132ffe9398746ad9422a75706e7cad19acc6c30a5c0fc763 + md5: 718879691b8119c893f587f46c734fca + depends: + - cuda-cudart-static_win-64 12.9.79 he0c23c2_0 + - cuda-version >=12.9,<12.10.0a0 + - ucrt >=10.0.20348.0 + - vc >=14.2,<15 + - vc14_runtime >=14.29.30139 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: {} + size: 23249 + timestamp: 1749218998822 +- conda: https://prefix.dev/conda-forge/win-64/cuda-nvcc-12.9.86-h8f04d04_6.conda + sha256: c8ae18d52a596dd1b2c210dab7c75893b74aac25783c787fc89e6052c9bfeabb + md5: e9b16eaf091bd261c36c239e99cca554 + depends: + - cuda-nvcc_win-64 12.9.86.* + - vs2019_win-64 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: {} + size: 25977 + timestamp: 1771619505004 +- conda: https://prefix.dev/conda-forge/win-64/cuda-nvcc-impl-12.9.86-h53cbb54_2.conda + sha256: d52c7b77b7d4f707efb3b76f93beb1c2b97883db6605818c1727935df9babe5d + md5: 17181de579b111f1cbad7af2b45aed0e + depends: + - cuda-cudart >=12.9.79,<13.0a0 + - cuda-cudart-dev + - cuda-nvcc-dev_win-64 12.9.86 h36c15f3_2 + - cuda-nvcc-tools 12.9.86 he0c23c2_2 + - cuda-nvvm-impl 12.9.86 h2466b09_2 + - cuda-version >=12.9,<12.10.0a0 + - libnvptxcompiler-dev 12.9.86 h57928b3_2 + constrains: + - vc >=14.2 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: {} + size: 27684 + timestamp: 1753976469818 +- conda: https://prefix.dev/conda-forge/win-64/cuda-nvcc-tools-12.9.86-he0c23c2_2.conda + sha256: e28baff7cbee6bbc30797adfe09f497c9ac2b69deb7f5152fc7e238c2f37e42b + md5: b018676d60a0f1e51a120382db5221fc + depends: + - cuda-crt-tools 12.9.86 h57928b3_2 + - cuda-nvvm-tools 12.9.86 h2466b09_2 + - cuda-version >=12.9,<12.10.0a0 + - ucrt >=10.0.20348.0 + - vc >=14.2,<15 + - vc14_runtime >=14.29.30139 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: {} + size: 27361 + timestamp: 1753976245101 +- conda: https://prefix.dev/conda-forge/win-64/cuda-nvcc_win-64-12.9.86-hd70436c_6.conda + sha256: f78ba6f9f461384d79e6496d91645e54b6f42e7bab9fb6858427afe17d916338 + md5: 47c00e8ebf2a716447fc04cec54d91a7 + depends: + - cuda-cudart-dev_win-64 12.9.* + - cuda-nvcc-dev_win-64 12.9.86.* + - cuda-nvcc-impl 12.9.86.* + - cuda-nvcc-tools 12.9.86.* + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: + strong: + - cuda-version >=12.9,<13 + size: 27274 + timestamp: 1771619504292 +- conda: https://prefix.dev/conda-forge/win-64/cuda-nvvm-impl-12.9.86-h2466b09_2.conda + sha256: 7b995ea653816b129bae6e4ee92898824a39fe82227472537bf75ac6ece7e955 + md5: d8cea7bc32045bde718d0b1ceb595445 + depends: + - cuda-version >=12.9,<12.10.0a0 + - ucrt >=10.0.20348.0 + - vc >=14.2,<15 + - vc14_runtime >=14.29.30139 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: {} + size: 31168 + timestamp: 1753975780038 +- conda: https://prefix.dev/conda-forge/win-64/cuda-nvvm-tools-12.9.86-h2466b09_2.conda + sha256: 5692a559206420f77e376a598329db966da762ad574866f9cc80a447d26ac49c + md5: 25e269101d3eb39715a48998bc04289e + depends: + - cuda-version >=12.9,<12.10.0a0 + - ucrt >=10.0.20348.0 + - vc >=14.2,<15 + - vc14_runtime >=14.29.30139 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: {} + size: 40286977 + timestamp: 1753975898550 +- conda: https://prefix.dev/conda-forge/win-64/krb5-1.22.2-h0ea6238_0.conda + sha256: eb60f1ad8b597bcf95dee11bc11fe71a8325bc1204cf51d2bb1f2120ffd77761 + md5: 4432f52dc0c8eb6a7a6abc00a037d93c + depends: + - openssl >=3.5.5,<4.0a0 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: MIT + license_family: MIT + run_exports: + weak: + - krb5 >=1.22.2,<1.23.0a0 + size: 751055 + timestamp: 1769769688841 +- conda: https://prefix.dev/conda-forge/win-64/libcurl-8.20.0-h8206538_0.conda + sha256: f4ce5aa835a698532feaa368e804365a7e45a9edebe006a8e1c80505d893c24e + md5: 7bee27a8f0a295117ccb864f30d2d87e + depends: + - krb5 >=1.22.2,<1.23.0a0 + - libssh2 >=1.11.1,<2.0a0 + - libzlib >=1.3.2,<2.0a0 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: curl + license_family: MIT + run_exports: + weak: + - libcurl >=8.20.0,<9.0a0 + size: 393114 + timestamp: 1777461635732 +- conda: https://prefix.dev/conda-forge/win-64/libexpat-2.8.1-hac47afa_0.conda + sha256: a65e518c20d1482182bc0f1f6dd5d992f25ca44c3b32307be39ae8310db8f060 + md5: 23eb9474a16d4b9f6f27429989e82002 + depends: + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + constrains: + - expat 2.8.1.* + license: MIT + license_family: MIT + run_exports: {} + size: 71280 + timestamp: 1779278786150 +- conda: https://prefix.dev/conda-forge/win-64/liblzma-5.8.3-hfd05255_0.conda + sha256: d636d1a25234063642f9c531a7bb58d84c1c496411280a36ea000bd122f078f1 + md5: 8f83619ab1588b98dd99c90b0bfc5c6d + depends: + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + constrains: + - xz 5.8.3.* + license: 0BSD + run_exports: + weak: + - liblzma >=5.8.3,<6.0a0 + size: 106486 + timestamp: 1775825663227 +- conda: https://prefix.dev/conda-forge/win-64/libnvptxcompiler-dev-12.9.86-h57928b3_2.conda + sha256: b05ab0cb8c66535a9cb27cf229752c42dab1fc4bda46c050514c42ad0a74b12c + md5: ed841728d5a36ce8269c6f875c001236 + depends: + - cuda-version >=12.9,<12.10.0a0 + - libnvptxcompiler-dev_win-64 12.9.86 h57928b3_2 + license: LicenseRef-NVIDIA-End-User-License-Agreement + run_exports: {} + size: 27359 + timestamp: 1753976279054 +- conda: https://prefix.dev/conda-forge/win-64/libssh2-1.11.1-h9aa295b_0.conda + sha256: cbdf93898f2e27cefca5f3fe46519335d1fab25c4ea2a11b11502ff63e602c09 + md5: 9dce2f112bfd3400f4f432b3d0ac07b2 + depends: + - libzlib >=1.3.1,<2.0a0 + - openssl >=3.5.0,<4.0a0 + - ucrt >=10.0.20348.0 + - vc >=14.2,<15 + - vc14_runtime >=14.29.30139 + license: BSD-3-Clause + license_family: BSD + run_exports: + weak: + - libssh2 >=1.11.1,<2.0a0 + size: 292785 + timestamp: 1745608759342 +- conda: https://prefix.dev/conda-forge/win-64/libuv-1.52.1-h6a83c73_0.conda + sha256: ca55710ece8736785ffa0fad4d45402dd40992a81a045d69eda5d40bc1a288f9 + md5: 741d96e586ac833409e5d27cdae08d15 + depends: + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - ucrt >=10.0.20348.0 + license: MIT + license_family: MIT + run_exports: + weak: + - libuv >=1.52.1,<2.0a0 + size: 331213 + timestamp: 1779396042250 +- conda: https://prefix.dev/conda-forge/win-64/libzlib-1.3.2-hfd05255_2.conda + sha256: 88609816e0cc7452bac637aaf65783e5edf4fee8a9f8e22bdc3a75882c536061 + md5: dbabbd6234dea34040e631f87676292f + depends: + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + constrains: + - zlib 1.3.2 *_2 + license: Zlib + license_family: Other + run_exports: + weak: + - libzlib >=1.3.2,<2.0a0 + size: 58347 + timestamp: 1774072851498 +- conda: https://prefix.dev/conda-forge/win-64/ninja-1.13.2-h477610d_0.conda + sha256: e41a945c34a5f0bd2109b73a65486cd93023fa0a9bcba3ef98f9a3da40ba1180 + md5: 7ecb9f2f112c66f959d2bb7dbdb89b67 + depends: + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - ucrt >=10.0.20348.0 + license: Apache-2.0 + license_family: APACHE + run_exports: {} + size: 309417 + timestamp: 1763688227932 +- conda: https://prefix.dev/conda-forge/win-64/openssl-3.6.2-hf411b9b_0.conda + sha256: feb5815125c60f2be4a411e532db1ed1cd2d7261a6a43c54cb6ae90724e2e154 + md5: 05c7d624cff49dbd8db1ad5ba537a8a3 + depends: + - ca-certificates + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: Apache-2.0 + license_family: Apache + run_exports: + weak: + - openssl >=3.6.2,<4.0a0 + size: 9410183 + timestamp: 1775589779763 +- conda: https://prefix.dev/conda-forge/win-64/ucrt-10.0.26100.0-h57928b3_0.conda + sha256: 3005729dce6f3d3f5ec91dfc49fc75a0095f9cd23bab49efb899657297ac91a5 + md5: 71b24316859acd00bdb8b38f5e2ce328 + constrains: + - vc14_runtime >=14.29.30037 + - vs2015_runtime >=14.29.30037 + license: LicenseRef-MicrosoftWindowsSDK10 + run_exports: {} + size: 694692 + timestamp: 1756385147981 +- conda: https://prefix.dev/conda-forge/win-64/vc-14.5-h1b7c187_38.conda + sha256: 61b68e5a4fc71a17f8d64b12e013a2f971ad980bd08e9c389d5e68efe1a67de0 + md5: 774568633f3b26d7a4a6dd4f9ea6d3e1 + depends: + - vc14_runtime >=14.51.36231 + track_features: + - vc14 + license: BSD-3-Clause + license_family: BSD + run_exports: {} + size: 20187 + timestamp: 1780005880049 +- conda: https://prefix.dev/conda-forge/win-64/vc14_runtime-14.51.36231-h1b9f54f_38.conda + sha256: 957c7c65583c7107a5e76f39756c6361fcb7b0dc101ac7c0aea86e7ca09fe49c + md5: 2cdcd8ea1010920911bb2eacb4c61227 + depends: + - ucrt >=10.0.20348.0 + - vcomp14 14.51.36231 h1b9f54f_38 + constrains: + - vs2015_runtime 14.51.36231.* *_38 + license: LicenseRef-MicrosoftVisualCpp2015-2022Runtime + license_family: Proprietary + run_exports: {} + size: 740997 + timestamp: 1780005875753 +- conda: https://prefix.dev/conda-forge/win-64/vcomp14-14.51.36231-h1b9f54f_38.conda + sha256: c645fdc1f0f47718431d973386e946754a10200e7ba2c32032560913a970cacd + md5: 63ee70d69d7540e821940dac5d4d9ba2 + depends: + - ucrt >=10.0.20348.0 + constrains: + - vs2015_runtime 14.51.36231.* *_38 + license: LicenseRef-MicrosoftVisualCpp2015-2022Runtime + license_family: Proprietary + run_exports: + strong: + - vcomp14 >=14.51.36231 + size: 123561 + timestamp: 1780005858779 +- conda: https://prefix.dev/conda-forge/win-64/vs2019_win-64-19.29.30139-h7dcff83_38.conda + sha256: d882d36d11f4ec2c2f148484c3a43c6121bc7e6829ec0c2940305a440aecacc0 + md5: ff50a2973017ef550e7178a76db45abd + depends: + - vswhere + constrains: + - vs_win-64 2019.11 + track_features: + - vc14 + license: BSD-3-Clause + license_family: BSD + run_exports: + strong: + - vc >=14.2,<15 + - vc14_runtime >=14.29.30139 + - ucrt >=10.0.20348.0 + size: 24189 + timestamp: 1780005891796 +- conda: https://prefix.dev/conda-forge/win-64/vs2022_win-64-19.44.35207-ha74f236_38.conda + sha256: d602239c40b42411268dc15f0325d4c67c6e6b51b6f31d4455935f07cd170111 + md5: 2d59c2ac7e4c06c9d60731d10cd6254a + depends: + - vswhere + constrains: + - vs_win-64 2022.14 + track_features: + - vc14 + license: BSD-3-Clause + license_family: BSD + run_exports: + strong: + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - ucrt >=10.0.20348.0 + size: 24145 + timestamp: 1780005884976 +- conda: https://prefix.dev/conda-forge/win-64/zstd-1.5.7-h534d264_6.conda + sha256: 368d8628424966fd8f9c8018326a9c779e06913dd39e646cf331226acc90e5b2 + md5: 053b84beec00b71ea8ff7a4f84b55207 + depends: + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - ucrt >=10.0.20348.0 + - libzlib >=1.3.1,<2.0a0 + license: BSD-3-Clause + license_family: BSD + run_exports: + weak: + - zstd >=1.5.7,<1.6.0a0 + size: 388453 + timestamp: 1764777142545 +- conda_source: cuda_probe[139d67dc] @ . + variants: + target_platform: linux-64 + depends: + - cuda-version 12.* + - cuda-nvcc 12.* + - libstdcxx >=15 + - libgcc >=15 + build_packages: + - conda: https://prefix.dev/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda + - conda: https://prefix.dev/conda-forge/linux-64/binutils_impl_linux-64-2.45.1-default_hfdba357_102.conda + - conda: https://prefix.dev/conda-forge/linux-64/binutils_linux-64-2.45.1-default_h4852527_102.conda + - conda: https://prefix.dev/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda + - conda: https://prefix.dev/conda-forge/linux-64/c-ares-1.34.6-hb03c661_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/cmake-4.3.3-hc85cc9f_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/gcc_impl_linux-64-15.2.0-he0086c7_19.conda + - conda: https://prefix.dev/conda-forge/linux-64/gcc_linux-64-15.2.0-h7be306e_25.conda + - conda: https://prefix.dev/conda-forge/linux-64/gxx_impl_linux-64-15.2.0-hda75c37_19.conda + - conda: https://prefix.dev/conda-forge/linux-64/gxx_linux-64-15.2.0-h1b0a0b8_25.conda + - conda: https://prefix.dev/conda-forge/linux-64/keyutils-1.6.3-hb9d3cd8_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/krb5-1.22.2-ha1258a1_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_102.conda + - conda: https://prefix.dev/conda-forge/linux-64/libcurl-8.20.0-hcf29cc6_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/libedit-3.1.20250104-pl5321h7949ede_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/libev-4.33-hd590300_2.conda + - conda: https://prefix.dev/conda-forge/linux-64/libexpat-2.8.1-hecca717_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/libgcc-15.2.0-he0feb66_19.conda + - conda: https://prefix.dev/conda-forge/linux-64/libgcc-ng-15.2.0-h69a702a_19.conda + - conda: https://prefix.dev/conda-forge/linux-64/libgomp-15.2.0-he0feb66_19.conda + - conda: https://prefix.dev/conda-forge/linux-64/liblzma-5.8.3-hb03c661_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/libnghttp2-1.68.1-h877daf1_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/libsanitizer-15.2.0-h90f66d4_19.conda + - conda: https://prefix.dev/conda-forge/linux-64/libssh2-1.11.1-hcf80075_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_19.conda + - conda: https://prefix.dev/conda-forge/linux-64/libuv-1.52.1-h280c20c_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_2.conda + - conda: https://prefix.dev/conda-forge/linux-64/ncurses-6.6-hdb14827_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/ninja-1.13.2-h171cf75_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/openssl-3.6.2-h35e630c_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/rhash-1.4.6-hb9d3cd8_1.conda + - conda: https://prefix.dev/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda + - conda: https://prefix.dev/conda-forge/noarch/ca-certificates-2026.5.20-hbd8a1cb_0.conda + - conda: https://prefix.dev/conda-forge/noarch/kernel-headers_linux-64-4.18.0-he073ed8_9.conda + - conda: https://prefix.dev/conda-forge/noarch/libgcc-devel_linux-64-15.2.0-hcc6f6b0_119.conda + - conda: https://prefix.dev/conda-forge/noarch/libstdcxx-devel_linux-64-15.2.0-hd446a21_119.conda + - conda: https://prefix.dev/conda-forge/noarch/sysroot_linux-64-2.28-h4ee821c_9.conda + - conda: https://prefix.dev/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + host_packages: + - conda: https://prefix.dev/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda + - conda: https://prefix.dev/conda-forge/linux-64/libgcc-15.2.0-he0feb66_19.conda + - conda: https://prefix.dev/conda-forge/linux-64/libgomp-15.2.0-he0feb66_19.conda + - conda: https://prefix.dev/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_19.conda +- conda_source: cuda_probe[239c2f87] @ . + variants: + cxx_compiler: vs2022 + target_platform: win-64 + depends: + - cuda-version 12.* + - cuda-nvcc 12.* + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - ucrt >=10.0.20348.0 + build_packages: + - conda: https://prefix.dev/conda-forge/noarch/ca-certificates-2026.5.20-h4c7d964_0.conda + - conda: https://prefix.dev/conda-forge/noarch/vswhere-3.1.7-h40126e0_1.conda + - conda: https://prefix.dev/conda-forge/win-64/bzip2-1.0.8-h0ad9c76_9.conda + - conda: https://prefix.dev/conda-forge/win-64/cmake-4.3.3-hdcbee5b_0.conda + - conda: https://prefix.dev/conda-forge/win-64/krb5-1.22.2-h0ea6238_0.conda + - conda: https://prefix.dev/conda-forge/win-64/libcurl-8.20.0-h8206538_0.conda + - conda: https://prefix.dev/conda-forge/win-64/libexpat-2.8.1-hac47afa_0.conda + - conda: https://prefix.dev/conda-forge/win-64/liblzma-5.8.3-hfd05255_0.conda + - conda: https://prefix.dev/conda-forge/win-64/libssh2-1.11.1-h9aa295b_0.conda + - conda: https://prefix.dev/conda-forge/win-64/libuv-1.52.1-h6a83c73_0.conda + - conda: https://prefix.dev/conda-forge/win-64/libzlib-1.3.2-hfd05255_2.conda + - conda: https://prefix.dev/conda-forge/win-64/ninja-1.13.2-h477610d_0.conda + - conda: https://prefix.dev/conda-forge/win-64/openssl-3.6.2-hf411b9b_0.conda + - conda: https://prefix.dev/conda-forge/win-64/ucrt-10.0.26100.0-h57928b3_0.conda + - conda: https://prefix.dev/conda-forge/win-64/vc-14.5-h1b7c187_38.conda + - conda: https://prefix.dev/conda-forge/win-64/vc14_runtime-14.51.36231-h1b9f54f_38.conda + - conda: https://prefix.dev/conda-forge/win-64/vcomp14-14.51.36231-h1b9f54f_38.conda + - conda: https://prefix.dev/conda-forge/win-64/vs2022_win-64-19.44.35207-ha74f236_38.conda + - conda: https://prefix.dev/conda-forge/win-64/zstd-1.5.7-h534d264_6.conda + host_packages: + - conda: https://prefix.dev/conda-forge/win-64/ucrt-10.0.26100.0-h57928b3_0.conda + - conda: https://prefix.dev/conda-forge/win-64/vc-14.5-h1b7c187_38.conda + - conda: https://prefix.dev/conda-forge/win-64/vc14_runtime-14.51.36231-h1b9f54f_38.conda + - conda: https://prefix.dev/conda-forge/win-64/vcomp14-14.51.36231-h1b9f54f_38.conda +- conda_source: cuda_probe[b008fffd] @ . + variants: + target_platform: osx-arm64 + depends: + - libcxx >=22 + build_packages: + - conda: https://prefix.dev/conda-forge/noarch/ca-certificates-2026.5.20-hbd8a1cb_0.conda + - conda: https://prefix.dev/conda-forge/noarch/compiler-rt22_osx-arm64-22.1.7-h7e67a1e_0.conda + - conda: https://prefix.dev/conda-forge/noarch/compiler-rt_osx-arm64-22.1.7-hce30654_0.conda + - conda: https://prefix.dev/conda-forge/noarch/libcxx-headers-22.1.7-h707e725_0.conda + - conda: https://prefix.dev/conda-forge/noarch/sdkroot_env_osx-arm64-26.0-ha3f98da_7.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/bzip2-1.0.8-hd037594_9.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/c-ares-1.34.6-hc919400_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/cctools_impl_osx-arm64-1030.6.3-llvm22_1_hb5e89dc_4.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/cctools_osx-arm64-1030.6.3-llvm22_1_hbe26303_4.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/clang-22-22.1.7-default_hd632d02_1.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/clang-scan-deps-22.1.7-default_h8e162e0_1.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/clang_impl_osx-arm64-22.1.7-default_h17d1ed9_1.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/clang_osx-arm64-22.1.7-hf119d2b_32.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/clangxx_impl_osx-arm64-22.1.7-default_h17d1ed9_1.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/clangxx_osx-arm64-22.1.7-hf119d2b_32.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/cmake-4.3.3-h8cb302d_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/compiler-rt-22.1.7-hce30654_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/compiler-rt22-22.1.7-hd34ed20_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/krb5-1.22.2-h385eeb1_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/ld64_osx-arm64-956.6-llvm22_1_h692d5aa_4.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/libclang-cpp22.1-22.1.7-default_h8e162e0_1.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/libclang13-22.1.7-default_h6dd9417_1.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/libcompiler-rt-22.1.7-hd34ed20_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/libcurl-8.20.0-hd5a2499_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/libcxx-22.1.7-h55c6f16_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/libcxx-devel-22.1.7-h6dc3340_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/libedit-3.1.20250104-pl5321hafb1f1b_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/libev-4.33-h93a5062_2.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/libexpat-2.8.1-hf6b4638_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/libiconv-1.18-h23cfdf5_2.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/libllvm22-22.1.7-h89af1be_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/liblzma-5.8.3-h8088a28_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/libnghttp2-1.68.1-h8f3e76b_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/libsigtool-0.1.3-h98dc951_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/libssh2-1.11.1-h1590b86_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/libuv-1.52.1-h1a92334_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/libxml2-16-2.15.3-h6967ea9_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/libxml2-2.15.3-heed7d32_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/libzlib-1.3.2-h8088a28_2.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/llvm-tools-22-22.1.7-hb545844_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/llvm-tools-22.1.7-hd34ed20_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/ncurses-6.6-h1d4f5a5_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/ninja-1.13.2-h49c215f_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/openssl-3.6.2-hd24854e_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/rhash-1.4.6-h5505292_1.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/sigtool-codesign-0.1.3-h98dc951_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/tapi-1600.0.11.8-h997e182_2.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/zstd-1.5.7-hbf9d68e_6.conda + host_packages: + - conda: https://prefix.dev/conda-forge/osx-arm64/libcxx-22.1.7-h55c6f16_0.conda +- conda_source: cuda_probe[d2e722fe] @ . + variants: + target_platform: osx-64 + depends: + - libcxx >=22 + build_packages: + - conda: https://prefix.dev/conda-forge/noarch/ca-certificates-2026.5.20-hbd8a1cb_0.conda + - conda: https://prefix.dev/conda-forge/noarch/compiler-rt22_osx-64-22.1.7-hcf80936_0.conda + - conda: https://prefix.dev/conda-forge/noarch/compiler-rt_osx-64-22.1.7-h694c41f_0.conda + - conda: https://prefix.dev/conda-forge/noarch/libcxx-headers-22.1.7-h707e725_0.conda + - conda: https://prefix.dev/conda-forge/noarch/sdkroot_env_osx-64-26.0-h62b880e_7.conda + - conda: https://prefix.dev/conda-forge/osx-64/bzip2-1.0.8-h500dc9f_9.conda + - conda: https://prefix.dev/conda-forge/osx-64/c-ares-1.34.6-hb5e19a0_0.conda + - conda: https://prefix.dev/conda-forge/osx-64/cctools_impl_osx-64-1030.6.3-llvm22_1_h8fe25a2_4.conda + - conda: https://prefix.dev/conda-forge/osx-64/cctools_osx-64-1030.6.3-llvm22_1_h0a1bb1c_4.conda + - conda: https://prefix.dev/conda-forge/osx-64/clang-22-22.1.7-default_h3b8fe2e_1.conda + - conda: https://prefix.dev/conda-forge/osx-64/clang-scan-deps-22.1.7-default_h9399c5b_1.conda + - conda: https://prefix.dev/conda-forge/osx-64/clang_impl_osx-64-22.1.7-default_hb18168d_1.conda + - conda: https://prefix.dev/conda-forge/osx-64/clang_osx-64-22.1.7-hb0d1528_32.conda + - conda: https://prefix.dev/conda-forge/osx-64/clangxx_impl_osx-64-22.1.7-default_hb18168d_1.conda + - conda: https://prefix.dev/conda-forge/osx-64/clangxx_osx-64-22.1.7-hb0d1528_32.conda + - conda: https://prefix.dev/conda-forge/osx-64/cmake-4.3.3-h2426fb6_0.conda + - conda: https://prefix.dev/conda-forge/osx-64/compiler-rt-22.1.7-h694c41f_0.conda + - conda: https://prefix.dev/conda-forge/osx-64/compiler-rt22-22.1.7-h1637cdf_0.conda + - conda: https://prefix.dev/conda-forge/osx-64/krb5-1.22.2-h207b36a_0.conda + - conda: https://prefix.dev/conda-forge/osx-64/ld64_osx-64-956.6-llvm22_1_h163eae7_4.conda + - conda: https://prefix.dev/conda-forge/osx-64/libclang-cpp22.1-22.1.7-default_h9399c5b_1.conda + - conda: https://prefix.dev/conda-forge/osx-64/libclang13-22.1.7-default_h2429e1b_1.conda + - conda: https://prefix.dev/conda-forge/osx-64/libcompiler-rt-22.1.7-h1637cdf_0.conda + - conda: https://prefix.dev/conda-forge/osx-64/libcurl-8.20.0-h8f0b9e4_0.conda + - conda: https://prefix.dev/conda-forge/osx-64/libcxx-22.1.7-h19cb2f5_0.conda + - conda: https://prefix.dev/conda-forge/osx-64/libcxx-devel-22.1.7-h7c275be_0.conda + - conda: https://prefix.dev/conda-forge/osx-64/libedit-3.1.20250104-pl5321ha958ccf_0.conda + - conda: https://prefix.dev/conda-forge/osx-64/libev-4.33-h10d778d_2.conda + - conda: https://prefix.dev/conda-forge/osx-64/libexpat-2.8.1-hcc62823_0.conda + - conda: https://prefix.dev/conda-forge/osx-64/libiconv-1.18-h57a12c2_2.conda + - conda: https://prefix.dev/conda-forge/osx-64/libllvm22-22.1.7-hab754da_0.conda + - conda: https://prefix.dev/conda-forge/osx-64/liblzma-5.8.3-hbb4bfdb_0.conda + - conda: https://prefix.dev/conda-forge/osx-64/libnghttp2-1.68.1-h70048d4_0.conda + - conda: https://prefix.dev/conda-forge/osx-64/libsigtool-0.1.3-hc0f2934_0.conda + - conda: https://prefix.dev/conda-forge/osx-64/libssh2-1.11.1-hed3591d_0.conda + - conda: https://prefix.dev/conda-forge/osx-64/libuv-1.52.1-ha3d0635_0.conda + - conda: https://prefix.dev/conda-forge/osx-64/libxml2-16-2.15.3-h0d7f165_0.conda + - conda: https://prefix.dev/conda-forge/osx-64/libxml2-2.15.3-h0712280_0.conda + - conda: https://prefix.dev/conda-forge/osx-64/libzlib-1.3.2-hbb4bfdb_2.conda + - conda: https://prefix.dev/conda-forge/osx-64/llvm-tools-22-22.1.7-hc181bea_0.conda + - conda: https://prefix.dev/conda-forge/osx-64/llvm-tools-22.1.7-h1637cdf_0.conda + - conda: https://prefix.dev/conda-forge/osx-64/ncurses-6.6-hcc0dc9a_0.conda + - conda: https://prefix.dev/conda-forge/osx-64/ninja-1.13.2-hfc0b2d5_0.conda + - conda: https://prefix.dev/conda-forge/osx-64/openssl-3.6.2-hc881268_0.conda + - conda: https://prefix.dev/conda-forge/osx-64/rhash-1.4.6-h6e16a3a_1.conda + - conda: https://prefix.dev/conda-forge/osx-64/sigtool-codesign-0.1.3-hc0f2934_0.conda + - conda: https://prefix.dev/conda-forge/osx-64/tapi-1600.0.11.8-h8d8e812_2.conda + - conda: https://prefix.dev/conda-forge/osx-64/zstd-1.5.7-h3eecb57_6.conda + host_packages: + - conda: https://prefix.dev/conda-forge/osx-64/libcxx-22.1.7-h19cb2f5_0.conda diff --git a/examples/pixi-build/conditional-dependencies/pixi.toml b/examples/pixi-build/conditional-dependencies/pixi.toml new file mode 100644 index 0000000000..e325de13d7 --- /dev/null +++ b/examples/pixi-build/conditional-dependencies/pixi.toml @@ -0,0 +1,33 @@ +[workspace] +channels = [ + "https://prefix.dev/pixi-build-backends", + "https://prefix.dev/conda-forge", +] +platforms = ["linux-64", "win-64", "osx-64", "osx-arm64"] +preview = ["pixi-build"] + +# Depend on ourselves: this invokes the build backend to compile the C++ code +# and drops the `cuda_probe` executable into the environment. +[dependencies] +cuda_probe = { path = "." } + +[tasks] +start = { cmd = "cuda_probe", description = "Run the executable built by the [package] section" } + +[package] +name = "cuda_probe" +version = "0.1.0" +description = "A C++ executable that demonstrates if(...) conditional dependencies" + +[package.build.backend] +name = "pixi-build-cmake" +version = "0.3.*" +channels = [ + "https://prefix.dev/pixi-build-backends", + "https://prefix.dev/conda-forge", +] + +# --- Conditional dependencies: the feature this example shows off --------- +[package.run-dependencies."if(linux or win)"] +cuda-version = "12.*" +cuda-nvcc = "12.*" diff --git a/examples/pixi-build/conditional-dependencies/src/main.cc b/examples/pixi-build/conditional-dependencies/src/main.cc new file mode 100644 index 0000000000..80da0e1305 --- /dev/null +++ b/examples/pixi-build/conditional-dependencies/src/main.cc @@ -0,0 +1,35 @@ +#include + +#if defined(__clang__) +# define COMPILER "Clang " __clang_version__ +#elif defined(__GNUC__) +# define COMPILER "GCC " __VERSION__ +#elif defined(_MSC_VER) +# define COMPILER "MSVC" +#else +# define COMPILER "an unknown compiler" +#endif + +#ifdef HAS_CUDA +# include +#endif + +int main() { + std::printf("cuda_probe built with %s\n", COMPILER); + +#ifdef HAS_CUDA + int devices = 0; + cudaError_t err = cudaGetDeviceCount(&devices); + if (err == cudaSuccess) { + std::printf("CUDA %s runtime linked, %d device(s) visible\n", + CUDA_VERSION_STRING, devices); + } else { + std::printf("CUDA %s runtime linked, but no devices (%s)\n", + CUDA_VERSION_STRING, cudaGetErrorString(err)); + } +#else + std::printf("Built without CUDA support (CPU-only)\n"); +#endif + + return 0; +} From 27f6a57e9599a53a7ef2f74e04a2b2532130e445 Mon Sep 17 00:00:00 2001 From: Julian Hofer Date: Thu, 11 Jun 2026 07:40:40 +0000 Subject: [PATCH 3/4] test: add integration tests for if() conditional package dependencies Cover a simple platform family condition, a complex boolean expression, a match() condition evaluated against build variants and the error message for an expression that does not parse. Extend target_specific_channel_1 with stub cmake and ninja packages so the build environment of pixi-build-cmake can be solved offline. --- ..._v1_examples@conditional-dependencies.snap | 4 +- .../conditional-dependencies/pixi.toml | 8 +- .../linux-64/cmake-0.1.0-hb0f4dca_0.conda | Bin 0 -> 975 bytes .../linux-64/ninja-0.1.0-hb0f4dca_0.conda | Bin 0 -> 974 bytes .../package-unix-0.1.0-hb0f4dca_0.conda | Bin 1203 -> 1202 bytes .../linux-64/repodata.json | 2 +- .../osx-64/cmake-0.1.0-h0dc7051_0.conda | Bin 0 -> 974 bytes .../osx-64/ninja-0.1.0-h0dc7051_0.conda | Bin 0 -> 972 bytes .../package-unix-0.1.0-h0dc7051_0.conda | Bin 1201 -> 1201 bytes .../osx-64/repodata.json | 2 +- .../osx-arm64/cmake-0.1.0-h60d57d3_0.conda | Bin 0 -> 974 bytes .../osx-arm64/ninja-0.1.0-h60d57d3_0.conda | Bin 0 -> 972 bytes .../package-unix-0.1.0-h60d57d3_0.conda | Bin 1201 -> 1200 bytes .../osx-arm64/repodata.json | 2 +- .../rattler-build-log.txt | 16 +- .../win-64/cmake-0.1.0-h9490d1a_0.conda | Bin 0 -> 976 bytes .../win-64/ninja-0.1.0-h9490d1a_0.conda | Bin 0 -> 974 bytes .../package-windows-0.1.0-h9490d1a_0.conda | Bin 1219 -> 1220 bytes .../win-64/repodata.json | 2 +- .../recipes/target_specific_channel_1.yaml | 18 +++ .../test_conditional_dependencies.py | 148 ++++++++++++++++++ 21 files changed, 188 insertions(+), 14 deletions(-) create mode 100644 tests/data/channels/channels/target_specific_channel_1/linux-64/cmake-0.1.0-hb0f4dca_0.conda create mode 100644 tests/data/channels/channels/target_specific_channel_1/linux-64/ninja-0.1.0-hb0f4dca_0.conda create mode 100644 tests/data/channels/channels/target_specific_channel_1/osx-64/cmake-0.1.0-h0dc7051_0.conda create mode 100644 tests/data/channels/channels/target_specific_channel_1/osx-64/ninja-0.1.0-h0dc7051_0.conda create mode 100644 tests/data/channels/channels/target_specific_channel_1/osx-arm64/cmake-0.1.0-h60d57d3_0.conda create mode 100644 tests/data/channels/channels/target_specific_channel_1/osx-arm64/ninja-0.1.0-h60d57d3_0.conda create mode 100644 tests/data/channels/channels/target_specific_channel_1/win-64/cmake-0.1.0-h9490d1a_0.conda create mode 100644 tests/data/channels/channels/target_specific_channel_1/win-64/ninja-0.1.0-h9490d1a_0.conda create mode 100644 tests/integration_python/pixi_build/test_conditional_dependencies.py diff --git a/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_examples@conditional-dependencies.snap b/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_examples@conditional-dependencies.snap index 38f9371054..a0a4392012 100644 --- a/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_examples@conditional-dependencies.snap +++ b/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_examples@conditional-dependencies.snap @@ -28,7 +28,7 @@ expression: project_model "hostDependencies": {}, "buildDependencies": {}, "runDependencies": { - "cuda-version": { + "cuda-nvcc": { "binary": { "version": "12.*", "build": null, @@ -45,7 +45,7 @@ expression: project_model "condition": null } }, - "cuda-nvcc": { + "cuda-version": { "binary": { "version": "12.*", "build": null, diff --git a/examples/pixi-build/conditional-dependencies/pixi.toml b/examples/pixi-build/conditional-dependencies/pixi.toml index e325de13d7..50a585c698 100644 --- a/examples/pixi-build/conditional-dependencies/pixi.toml +++ b/examples/pixi-build/conditional-dependencies/pixi.toml @@ -15,19 +15,19 @@ cuda_probe = { path = "." } start = { cmd = "cuda_probe", description = "Run the executable built by the [package] section" } [package] +description = "A C++ executable that demonstrates if(...) conditional dependencies" name = "cuda_probe" version = "0.1.0" -description = "A C++ executable that demonstrates if(...) conditional dependencies" [package.build.backend] -name = "pixi-build-cmake" -version = "0.3.*" channels = [ "https://prefix.dev/pixi-build-backends", "https://prefix.dev/conda-forge", ] +name = "pixi-build-cmake" +version = "0.3.*" # --- Conditional dependencies: the feature this example shows off --------- [package.run-dependencies."if(linux or win)"] -cuda-version = "12.*" cuda-nvcc = "12.*" +cuda-version = "12.*" diff --git a/tests/data/channels/channels/target_specific_channel_1/linux-64/cmake-0.1.0-hb0f4dca_0.conda b/tests/data/channels/channels/target_specific_channel_1/linux-64/cmake-0.1.0-hb0f4dca_0.conda new file mode 100644 index 0000000000000000000000000000000000000000..a7ee6ac6655745d66102a1859a3c66b27a2e3a4c GIT binary patch literal 975 zcmWIWW@gc40D(li(=n$RQuY2r0WX6HLvCtGVoG93qFz>UejX!(0D~M@DFd9YR!Yv# zOG%6`$WD(>%P-1JEQv2mEh^5;&r`B8strIfod04)B+PInpy5D0y2-hT*{Qk)dWL!i zx*16ZX(lPjiSY({C5c6PRmCMB8-<`Y!f1`H`hOD`m|YndI2afi{%9+(pxPo(G;=r1 z7GZv8h##&2GW_(;GG1DyB z!+^mE2n{Fh+GV-_$q5NY{$n%#UXv<$aZG2KwT;%=ZDN}Z)J$r29gbRixaMW%jayf3 z3LPcccT6&z7*^)^Tf66``Kh|ouUKtYBug4ks^hFXAf&9&$;}y9R{QVa{2EJ^i5WTh zo^B4D`Igsz?Xmfp^!?+E6K~9>O_NN&SE==+_e)4bHdCZ-vY_8F7cakW+b((T{GFn+ zTGT?9{lKCCua)7~%A4=~dUsOf+lqBd|IYZ5$Tv@a&F0;TSA(KMtksKr&iq=tzO}q< zzT4<owuq9>?5NikKyPUi0rczx}GA8Nj8f#7Ygng=f# zHt|RuII`qGfHxzPE;H^V3QZmiOBz8ef(aJgIP^q`FfJCzBrl1g+ku`W5q2B~GRaJ! U0p6@^AcL5JPy(2E7czl(0G)?U{{R30 literal 0 HcmV?d00001 diff --git a/tests/data/channels/channels/target_specific_channel_1/linux-64/ninja-0.1.0-hb0f4dca_0.conda b/tests/data/channels/channels/target_specific_channel_1/linux-64/ninja-0.1.0-hb0f4dca_0.conda new file mode 100644 index 0000000000000000000000000000000000000000..beb70bfc127178521306bfed070c314b10807db9 GIT binary patch literal 974 zcmWIWW@gc40D(li(=n$RQuY2r0WX6HLvCtGVoG93qFz>UejX!(0D~M@DFd9YR!Yv# zOG%6`$WD(>%P-1JEQv2mEh^5;&r`B8strIfod04)B+PInpy5D0x_Oy-S&6y^dWL!i zx*16ZX(lPjiSY({C5c6PRmCMB8-<`Y!f1`H`hOD`m|YndI2afi{%9+(pxV;0_FW^) z7Gd zTU}QU4aOfy(YA4NIr_gXe3G{Lwk95%SuV#_scd`Y=q!axr$Su14LT=H-hWARd76BU z^4g}hhX)p&v0NT}HNW}Zt-O;WUl*)f`ZxTGBVXUz)tk=>M5XIyOckoffa&4c{<hBA8y$jYCh92;*XbO!87Fx*g~#5@E+-Ad}4W V8Q{&z1~P~l2ql1NcL5WK2LS83P`3a8 literal 0 HcmV?d00001 diff --git a/tests/data/channels/channels/target_specific_channel_1/linux-64/package-unix-0.1.0-hb0f4dca_0.conda b/tests/data/channels/channels/target_specific_channel_1/linux-64/package-unix-0.1.0-hb0f4dca_0.conda index 54e26156c232c35b4737f9906d5b025dc2f49c8d..5ffca7f9ee1f63ed12b38afa55f71400af4fefb7 100644 GIT binary patch delta 716 zcmdnYxrviEz?+#xmjMJ4?M_eRjp6`OF^8A9pP!g-S)T)zU|@jJ8e8@MCNQvzGBX&t z3JOlBb$DYLa{rxNtenH`b1xhGyV*{gC| zK-9|_i_hqXcvUWqsQhJM_Uo2v=`JpXgzeVV->o@C8Wb0J@%Y?iXnf9I#*@Drk{u?92Q7{_fCh=5$2D6zyasel8Bvu-mo{+LSE2R*boSxPdnUi8( zDbQf_`CJvZGlL5dp7L&FN~`>OWO0^b*P|P+@0~PFxge9ia{X2H6I6^=Cx6aYpaEZt#B9pIhr+9L@NW zV&<4F7Wkt{USa>fPhK6b;^hmAnK%*!l6yj)b{&cP{oU80`EmSFW9_;77kp4XSj}r* z6Zrpgt76`R%Uj$zq8=$_{M*j4Xa4lwFAAT7F6h}_l6-OLDHHSL159-uYm7tB+}pvd z5PFQ~Y1#Bw$AV5yQ1oDAa*$gP`%rALl6XRMazeYo0guU11|7Ppb`2#AH`!zl9AP;S z;LXUS%M4FJliQem;7MrmEoOIXSlWTnXd1u~`yUFl7(}2cj)7rGqsrtM7DF{yJj3V! TZ&o&tB4!{|1Ez&CW)Kem2tXLv delta 719 zcmdnQxtWtUz?+#xmjMJ8XX{Mljp6`OF%h+siYDe;*5`pG7#Lu*##a5m2@LG2%nVAb zf`Suj9o|@m+LhenZCVt}C00b9c`?Yk#44nX%)vdoqr3cM_IN z4xD&-@!vI9%Or0_#o3hHzBa9=YmbS}tNc{o^OL^CK5D*o_*~BGv`6-gi3g5IocO99 zmz(Q&%ir>ImGX(CYUejX!(0D~M@DFd9YR!Yv# zOG%6`$WD(>%P-1JEQv2mEh^5;&r`B8strIfod04)B+PInpy5D0y2-hT*{Qk)dWL!i zx)}y3$>s*8hVce^C5c6PRmCMB8-<`Y!f1`H`hOD`m|YndI2afi{%9+(pxSbe+q@lS zi!#ub%)GRGBCP3PgxCY4A=Ze0W!Y<07JDMX4`18x znWaxpG{Vg_Nz(oI`ZYJhPVG;1Ra-hQcGb);{vViUNHBWd@R(rq@AqM6aeJ19FLK^{ zx+QcnUQ6yj`p@XX)|ss~T1L_Am-8N$)tS>Xc|k z@;6>)WY{b+C20SK_iTH&-ra1t>UCzlTJ4PHc%PR!=10DALkRwm&r9>%1_F`p`2R*!{nT(MtZ^|Qh6do`s zNHe^OZPK5_m*8|jlO^-u_MQzNEDJcr9|Q)kU_7;fZ->0BNk`dqj@w-==~9PU%h;-y zRar`wGc0*E2hFW*t=6rt`6JiF1m* z27~ZqX668IMkZZm+$j{AIvAETf>;F8E4p#$X%b;vERacF3PraAJw+nyI1FTxnLY!& SS=m4aF$19lFzqg20`UNgvqm8R literal 0 HcmV?d00001 diff --git a/tests/data/channels/channels/target_specific_channel_1/osx-64/ninja-0.1.0-h0dc7051_0.conda b/tests/data/channels/channels/target_specific_channel_1/osx-64/ninja-0.1.0-h0dc7051_0.conda new file mode 100644 index 0000000000000000000000000000000000000000..13869c2c5a3a1495d4cdb1b42bc1781c5de464eb GIT binary patch literal 972 zcmWIWW@gc40D&aC(=n$RQuY2r0WX6HLvCtGVoG93qFz>UejX!(0D~M@DFd9YR!Yv# zOG%6`$WD(>%P-1JEQv2mEh^5;&r`B8strIfod04)B+PInpy5D0x_Oy-S&6y^dWL!i zx)}y3$>s*8hVce^C5c6PRmCMB8-<`Y!f1`H`hOD`m|YndI2afi{%9+(pxW~M_MuLg zEy_S!GV{{%iLj=P5n>OFhFBy1l$+t%MRUo7>&%Pun6A%UbFx&Kk>LZs8DH=uSBEK| zCg?L5Fc>m;T?yU$eYv_5M*;t#KheqO;~i5K@6MN=EVpGstK$5Jm;MG;{n#B5eE8Ug z&n$iGcrBb%qa@vbuU>sK^wfT3*C%u8VsHEWT7I38r^P`fOT|O-|KEoTyXBh#zHI$2 zqPXF}m95*O>Lp)XTkXU*b;j!C#O)v5r21?o_y?pKs&{(|_8+go~fli`Zjng2y=Cp5?Bl&+I}G)a!tc8QNbW#s`QHMLTlKOk zOUZJEC9h^Yyz_QN@|&zQw?`%lA5JiD(Z2IZYZF6sU!&|H24&x@g9_VpJ~l3KPO;Zu z5T4A;9N^8!q|1yueL~X)!;(f2i(qO+Hx4~TB8-a#GRaGy=ysr|M}!@RflM+}XMi^= R8^|DLAd~>6+<8nO9st6xNw@$2 literal 0 HcmV?d00001 diff --git a/tests/data/channels/channels/target_specific_channel_1/osx-64/package-unix-0.1.0-h0dc7051_0.conda b/tests/data/channels/channels/target_specific_channel_1/osx-64/package-unix-0.1.0-h0dc7051_0.conda index 5fa25d1823e8c5a9d9298f59c29dd3e20b31503b..d524b6eeffa19d067a973a798bdcdb94dadfc16c 100644 GIT binary patch delta 531 zcmdnUxsj7Mz?+#xmjMKl>`qVQjp6`OG3k~bffMuVxuvJ}Xg=+B%3PYkW_Zg5oV1ZxX>58z%Id6?0;8&t@z(XanyE|%4ThV~9~5(9aA9y_&}ZeE z@${;2|0-5ZujKXB>enYYX3tr=FKoWTb*V!ZQHTHBdh_7%(YmuW8(IpFUHAW{xN~N| zgu49IO>Ixou08Hj4V7A3c*8z4OtviQ6O*frtH@cohVIKV>wOMwJ?1O$tia5tCS+x| z@q`W2vU^t>c<=IyJ@=RC+4ZAK6`!mQO5bEB%iD56>d}<*>eVZzbQ#S57Zk((V2YRg z^BvP<-np1M<>LRh~BZp+4cW<5@`D@jmTkBsO&G?dH=9n$^qe)(2|GrON9k1f$ z3po-$D71t;?K%?od%LWIar49YqmM&g{b|}ao#igi@#}$q%1#OxzfWA`%rPl|OR3(w z@%VFf<*(6oT#LNVe|h@zizf5reN1unZV^9Zb{t`?zaf&xU>3#hJXge|qii}yHfu|| z#G%$Qw(4b7mXhTROJ2=*c;{`<@rbN@JuI0H3@4bkXx~W+dBT)a!1G3cO(HXhn{DIL zBkU9S6mBnIo-u<#BEXxGNtYQOmocXqQuY2r0WX6HIF1<@CeLOzg~##a8_dawSaoK} F0{~KM>OKGf delta 531 zcmdnUxsj7Mz?+#xmjMKpWa~`ijp6`OF_(7foSB$k&n-W-NAqd0SBGSC&%~b=V5zL` zJgv!=j3M>cW_U{mTxb5{vsNIGW3F6vdfKb|E*@)-A3d?<<`EYLR|XdbL$*yPE-GZ+ zc&{#Z>qf8$*ZHdXDLm6wc;r3ZTVIvZ!^m-DMeTEG1IFsirPt-AM0II4sLvJNaec;t zV-~Joc#HQPShSYe^7MtCt}C00b9c|=J^Hy~fu-ZLdoqr3i|Y+1__?|I^?$p*VB6^n z*FH%(A2*Z~t;~$La{ttE-`s&S6n~cFg3uQMh1FOii|HPqUkA+V%2z`gcuvEv4Uox!0ys`?Y4;`ujXv zm>D;RWUnpV>;BUejX!(0D~M@DFd9YR!Yv# zOG%6`$WD(>%P-1JEQv2mEh^5;&r`B8strIfod04)B+PInpy5D0y2-hT*{Qk)dWL!i zx*28$DW>Kr#_Dc78>leFQF&yIkceXas64TttgtNuS6 z%Bo%Gp~qmzV8Fn8IB?BZ)g#xeB(m22mh@j0s=uycds0mCdChe?>!y9ndwM53RM$?S za?^SBZ2{>yraf`dC*(c-`r3Zav^^HRd)liKmAaKu?1^ieRW}M4#Qgp`vHhx(=cNSA z^pn>NBN#1|<~dEQQ#~NHl%v}8&9QdBtC`Ck(;EM(^gR2*a3gC*%RB4m_e2D*oxHR7 zJ2O`fGkfBNsBGDb@d_4?XWR{xdn|SOk5KlJiR;Q9Nekx-ZdtzLxn4rdqWOhOjPG;K z*R)ia;C9SSrHEOo<2C=Tv)iv4nlY?gEO4jhlHwZX3j%V>52(FaZOwf`Dfd8f5`(yf z_tDD7N-r67S!O$TOnZBpL+l^FOg2OL7m+Lmqg~8#?(95DJFQu^HgTUfEa5g~E!(d+ zZ>8DSJF*Qg%~Q^P-S_HP0Ott-KSm}OxdpKg#eyetZn!IPLV!==WFWWPM%GUL8Y{PJ zj?6P=Fi8Y>GcxHi<4&Q_)WNW%5yT>xUeS$1Pm>7aVu4KZQYg9|=qVCm$6+9o%=8)H T&B_Kch#3eafN6ID6Nm=@rQAbg literal 0 HcmV?d00001 diff --git a/tests/data/channels/channels/target_specific_channel_1/osx-arm64/ninja-0.1.0-h60d57d3_0.conda b/tests/data/channels/channels/target_specific_channel_1/osx-arm64/ninja-0.1.0-h60d57d3_0.conda new file mode 100644 index 0000000000000000000000000000000000000000..ebfc9e06fd71a6fca754553cac8a2a1098e3e481 GIT binary patch literal 972 zcmWIWW@gc40D(li(=n$RQuY2r0WX6HLvCtGVoG93qFz>UejX!(0D~M@DFd9YR!Yv# zOG%6`$WD(>%P-1JEQv2mEh^5;&r`B8strIfod04)B+PInpy5D0x_Oy-S&6y^dWL!i zx*28$DW>Kr#_h%FXcXqPb+iRp!S$JswwPYHaR1b4I6Dnq82+Yvx+_ ziTVtN3Bd*Xf8kE`?y|g{<@raH{_Rda<(V$Xt!(x9@&4J9_nn^Q?YzAt znDcLn%m>v8w|>1WT{WX_VXXBM_bK-KPtEA8=)J?H^PX|Sj(&#R*kajLXKyKXw1n?< z|G;>PdykjobMLErZq%&K{;yhazipGz=bkO?iSymc4uuIHn10~I&C+ucs%5#y3WBo2 z86R66SmdGk)Ia1b+r6J}Cu+VhobSFj>_fXn&9xcts{@%QZkb`?_M}5J)Ox?jJL%iU zxGWVWxE*s-DPorDc+J1-?DngMW(+GA3*4!>q_~Fpf`Hue18Q$pTXUaK$~};r#2{|r zeYEni(n|(imf6l7)83xu5c|h3lg&{6MI?*CXcu#wJ3EikPHUE}P2A@VOSny0%l0eI zTWR+7j%>qA^OUn+_q{q6z(xQ zBlCxoJ(*mMi&RBd#Kg6qYX+-5O1G8VZR7-bpDI{#SuKsS# zDbk?0z>CM{CPU*JN5(fkPMj!q$GBWmoI2T((W?FnBg9%54Y5@`l%L^RgtuJ4N*jrl zY|9$la#*}YQgzIYgPq(bElFa`P&bbFD&fT7421HmT-%FYcLqm0c3n!)PG4!5a$r{5 z^6l4DR~WV#@Eu#1UL#w(rR036ymw3CvFGzj+H%H=_ zlm|71R>yVDEwXvMJZs-nJ8{2|YF6KU575jzk8<7U8E|Ea`u4S~j>H zKHqhGDy2oL_Gms0_Ue#q?lIaQp!sxa($klRZ@kE!e&r<-mx6-fb&EZl z)44Xdaj_*D_5PK_UgWi$J*mZPi(n)#EHR~!HJf7(mcC&9Ht%o+>Qw)KUmUpIV8w~vfYY)%S-;nXTUUF98 z#Hg}$x#pWUUT9pH=`&%ex%-5`iI*4uO-$b!+qP}m^&MN}t@=)`IN^PG(Z8^3Uvx6> ztJqeF8rU9gIVp^j(|aUe zvv^G2&9qL2&+XAQR#PT^s{==l91QSgWYT4ZNBQJtW*>N*PrlCVZVQWS7>%X@97+G7 qK#M^HnnZxUejX!(0D~M@DFd9YR!Yv# zOG%6`$WD(>%P-1JEQv2mEh^5;&r`B8strIfod04)B+PInpy5D0y2-hT*{Qk)dWL!i zx*3)xmIf(?iSY({C5c6PRmCMB8-<`Y!f1`H`hOD`m|YndI2afi{%9+(pxV+>vLpv) zi!#ub%)GRGBCP3RgxCY4A=Zeq@-RHRXdxAFoq6-^11W1(E5#V5rLE{tTzqtPQp&9! zMMeV#BL+i;Q%}O~N&BClBE+zGiqyNBZu$EQSpW97ul;tbNsO)c*yaBjZ~yKv^y95P zEaQ`K@fzdZDW~?B=)AgdYSuhe-tUn$fv?k}&4rH#^Dw%3B?wsxsqh|_=9jp2!&!jq zeAWDAEMk(P`{va=JnLYcE?KqGN7wrLw%Pdxt#%tvvP4!DH)ZA*3+8*J`t`TH{CM^B zg=?4N5??cHz7q91TKpf|y~=l6c7FSLrO>Q?!Qp(LV%_3z8@`Ht3+j?F*`QHML zTlKOkOUZJEC9h^Yyz_QN@|&zQw?`%lA5JiD(Z2IZYZF6sU!&|H24&x@g9_VpJ~l3K zPO;Zu5T4A;9N^8!q|1yujY880!;(f2i(raHHx4~jB8-a#GRaG$=ysr|NrWATflM+} VXn;2>8^|DLAd~>6-bG9x9sn>GOnd+U literal 0 HcmV?d00001 diff --git a/tests/data/channels/channels/target_specific_channel_1/win-64/ninja-0.1.0-h9490d1a_0.conda b/tests/data/channels/channels/target_specific_channel_1/win-64/ninja-0.1.0-h9490d1a_0.conda new file mode 100644 index 0000000000000000000000000000000000000000..d50bb7c93fbc7b185110e803b5c18d207a6c71ed GIT binary patch literal 974 zcmWIWW@gc40D(li(=n$RQuY2r0WX6HLvCtGVoG93qFz>UejX!(0D~M@DFd9YR!Yv# zOG%6`$WD(>%P-1JEQv2mEh^5;&r`B8strIfod04)B+PInpy5D0x_Oy-S&6y^dWL!i zx*3)xmIf(?iSY({C5c6PRmCMB8-<`Y!f1`H`hOD`m|YndI2afi{%9+(pxV;Xp`rq_ zMHy&IW?ou85!Q4tLhOOj5NpK0ax**&w2*YT%DlgN)4LU6x~_>5Z1+5sQx(49tYV|V?zt;ZTyR|ALt2^ttOJ8T?_TrqU`;4EY z{9&_HDCp?v?dXsbpYopl!OO|7B%~Xz6msM#y_6_r$X={0@}P&eG?Ot>S7HR&ju&T+e|C0*)JYZ+Vh zvMNi-a)u?ZW<0#}c17}=tTeYrCJG-;FmKVm^GRzHLv&xG>>&na->icQ+jKrQE^$t= z*I*Ey%*-6%&B&z7j5~!wQwPJ6Mi7f&dPO%5JxwBviv=>tOQGm?pr=TL9fyHTGSg>( TH!B;+AZ8$x0H)mqOduWr57JHb literal 0 HcmV?d00001 diff --git a/tests/data/channels/channels/target_specific_channel_1/win-64/package-windows-0.1.0-h9490d1a_0.conda b/tests/data/channels/channels/target_specific_channel_1/win-64/package-windows-0.1.0-h9490d1a_0.conda index 523247427cd078f438985cd5085d1e2068a036ac..75b0d8a69385d4753d053df48bd5fe6b9b9f1a71 100644 GIT binary patch delta 520 zcmX@id4!WUz?+#xmjMJ4?M_eRjp6`OG1|ThvnJ-JoA)@xturVrZm?xF-+W5xP}aT4 z?s8`Z?cF0w^zJW@bK4!RTax8wvq1aa-SXwOu{;IGoNjqFaYRn$WmE&3lVNtyV6ru% zZT&AsuoVn2T4SsJ-vkEnR(=MyNFO-O{&SzV9*mqwHx zY2M|-|1<795%OW*84KB22Ry$Vv?8=Y{tD! zM$Go7a>;kGZI4bb;CZk*;dEl~vIT#GOt|b0_}es8ng$DzuFy=xo0B zv3U&J=4)~9o8tQ|rN!!2{KjQFE*X@TZsR<0KwWmqJKo1vzeL}D`L0IWHDm1pt$ke$ z0lI%4{ygQ^&nbHQ)U|C)oQWUqRbTqTql-T%O2%iWSCkF0YaU%PH_XP|d zGuqbwWCUBm0HZaw>i~OHDOw{o;H=S#izO4XP8@ z{tN2yWz4A$oz|nhSmzjr>6ZCPzJ*Jla=w10_9REx?S+i;^59GPwW@oxbF`hZkER%h zvH0gbx{>&!FquL^%^5+^e4Wg~v6&c6;!F$2)gRPEGU4XTE*hr*gh=?XLay zdUrQ7y{wpW?ds_rtFK!AFgWM(`@aE~Qce1To_C71CoCo(V>-bMjHt;InSJ09Hu))Y f8Y0w#S-jO?p$(%0yjj^m@xTm(I=~odWCrm7*$LR9 diff --git a/tests/data/channels/channels/target_specific_channel_1/win-64/repodata.json b/tests/data/channels/channels/target_specific_channel_1/win-64/repodata.json index d62d1e80d3..05aa458779 100644 --- a/tests/data/channels/channels/target_specific_channel_1/win-64/repodata.json +++ b/tests/data/channels/channels/target_specific_channel_1/win-64/repodata.json @@ -1 +1 @@ -{"info":{"subdir":"win-64"},"packages":{},"packages.conda":{"package-windows-0.1.0-h9490d1a_0.conda":{"arch":"x86_64","build":"h9490d1a_0","build_number":0,"depends":[],"md5":"cb1891c3f1bf05c1517b5f299b9ac9d2","name":"package-windows","platform":"win","sha256":"8ff6b961fedff5066790d0776a456fee58f2530030d1dfaedb13923f90b320c2","size":1219,"subdir":"win-64","timestamp":1768224547076,"version":"0.1.0"}},"repodata_version":2} \ No newline at end of file +{"info":{"subdir":"win-64"},"packages":{},"packages.conda":{"cmake-0.1.0-h9490d1a_0.conda":{"arch":"x86_64","build":"h9490d1a_0","build_number":0,"depends":[],"md5":"5ae92a5d2e30aa0920f0ffedcab297cc","name":"cmake","platform":"win","sha256":"8ddfba839e49265dbbcc25716e5fb080644cba029b5b679953a1bba721020e9a","size":976,"subdir":"win-64","timestamp":1781164263474,"version":"0.1.0"},"ninja-0.1.0-h9490d1a_0.conda":{"arch":"x86_64","build":"h9490d1a_0","build_number":0,"depends":[],"md5":"322f681f835df535f98fe2b98511e654","name":"ninja","platform":"win","sha256":"cc39a47b4560bbbfc3db9b0b131f75cda2167238f14f92634da4af7e6d8c6ff8","size":974,"subdir":"win-64","timestamp":1781164263474,"version":"0.1.0"},"package-windows-0.1.0-h9490d1a_0.conda":{"arch":"x86_64","build":"h9490d1a_0","build_number":0,"depends":[],"md5":"120bd74dae1c0cfc9b5bed9f353ce837","name":"package-windows","platform":"win","sha256":"bc0bce46371b156a0c9e984ece4122921ec6e340e380eef3060e4debc2331e10","size":1220,"subdir":"win-64","timestamp":1781164263474,"version":"0.1.0"}},"repodata_version":2} diff --git a/tests/data/channels/recipes/target_specific_channel_1.yaml b/tests/data/channels/recipes/target_specific_channel_1.yaml index 31bcf93014..48f08b8bdd 100644 --- a/tests/data/channels/recipes/target_specific_channel_1.yaml +++ b/tests/data/channels/recipes/target_specific_channel_1.yaml @@ -21,3 +21,21 @@ outputs: - mkdir -p $PREFIX/bin - echo "@echo off" > $PREFIX/bin/package.bat - echo "echo windows" >> $PREFIX/bin/package.bat + + # Stubs for the build tools that pixi-build-cmake injects into the build + # environment, so workspaces can be locked without conda-forge access. + - package: + name: cmake + version: 0.1.0 + + build: + script: + - echo stub + + - package: + name: ninja + version: 0.1.0 + + build: + script: + - echo stub diff --git a/tests/integration_python/pixi_build/test_conditional_dependencies.py b/tests/integration_python/pixi_build/test_conditional_dependencies.py new file mode 100644 index 0000000000..91270a0a1a --- /dev/null +++ b/tests/integration_python/pixi_build/test_conditional_dependencies.py @@ -0,0 +1,148 @@ +"""Tests for `if(...)` conditional package dependencies in the `[package]` section.""" + +from pathlib import Path +from typing import Any + +import tomli_w +from rattler.lock import LockFile + +from .common import ExitCode, verify_cli_command + +# The platforms covered by target_specific_channel_1. The channel only ships +# `package-unix` for the unix platforms and `package-windows` for win-64, so a +# conditional dependency that leaks to the wrong platform fails the solve. +PLATFORMS = ["linux-64", "osx-64", "osx-arm64", "win-64"] +UNIX_PLATFORMS = ["linux-64", "osx-64", "osx-arm64"] + +PACKAGE_NAME = "conditional-deps" + + +def write_workspace( + workspace_dir: Path, + channel: str, + run_dependencies: dict[str, Any], + platforms: list[str] = PLATFORMS, + build_variants: dict[str, list[str]] | None = None, +) -> Path: + """Write a workspace manifest with a source package using `pixi-build-cmake`.""" + manifest: dict[str, Any] = { + "workspace": { + # The channel also contains stub `cmake` and `ninja` packages for + # the build environment of the backend, locking stays offline. + "channels": [channel], + "platforms": platforms, + "preview": ["pixi-build"], + }, + "dependencies": {PACKAGE_NAME: {"path": "."}}, + "package": { + "name": PACKAGE_NAME, + "version": "1.0.0", + "build": { + "backend": {"name": "pixi-build-cmake", "version": "*"}, + # No compilers keeps the build environment small. + "config": {"compilers": []}, + }, + "run-dependencies": run_dependencies, + }, + } + if build_variants is not None: + manifest["workspace"]["build-variants"] = build_variants + manifest_path = workspace_dir.joinpath("pixi.toml") + manifest_path.write_text(tomli_w.dumps(manifest)) + return manifest_path + + +def locked_package_names(workspace_dir: Path) -> dict[str, set[str]]: + """Map each platform in the default environment to its locked package names.""" + lock = LockFile.from_path(workspace_dir.joinpath("pixi.lock")) + environment = lock.default_environment() + assert environment is not None + return { + str(platform): {package.name for package in packages} + for platform, packages in environment.packages_by_platform().items() + } + + +def test_simple_conditional_dependency( + pixi: Path, tmp_pixi_workspace: Path, target_specific_channel_1: str +) -> None: + """A platform family condition only adds the dependency on matching platforms.""" + manifest_path = write_workspace( + tmp_pixi_workspace, + target_specific_channel_1, + { + "if(unix)": {"package-unix": "*"}, + "if(win)": {"package-windows": "*"}, + }, + ) + + verify_cli_command([pixi, "lock", "--manifest-path", manifest_path]) + + packages = locked_package_names(tmp_pixi_workspace) + for platform in UNIX_PLATFORMS: + assert "package-unix" in packages[platform] + assert "package-windows" not in packages[platform] + assert "package-windows" in packages["win-64"] + assert "package-unix" not in packages["win-64"] + + +def test_complex_conditional_expression( + pixi: Path, tmp_pixi_workspace: Path, target_specific_channel_1: str +) -> None: + """Boolean operators and platform comparisons evaluate per platform.""" + manifest_path = write_workspace( + tmp_pixi_workspace, + target_specific_channel_1, + {"if(unix and not (host_platform == 'osx-arm64'))": {"package-unix": "*"}}, + ) + + verify_cli_command([pixi, "lock", "--manifest-path", manifest_path]) + + packages = locked_package_names(tmp_pixi_workspace) + assert "package-unix" in packages["linux-64"] + assert "package-unix" in packages["osx-64"] + assert "package-unix" not in packages["osx-arm64"] + assert "package-unix" not in packages["win-64"] + + +def test_variant_conditional_expression( + pixi: Path, tmp_pixi_workspace: Path, target_specific_channel_1: str +) -> None: + """`match()` conditions evaluate against the configured build variants.""" + manifest_path = write_workspace( + tmp_pixi_workspace, + target_specific_channel_1, + { + "if(match(python, '>=3.10'))": {"package-unix": "*"}, + # `package-windows` does not exist on linux-64, so the solve would + # fail loudly if this condition were wrongly applied. + "if(match(python, '<3.10'))": {"package-windows": "*"}, + }, + platforms=["linux-64"], + build_variants={"python": ["3.12"]}, + ) + + verify_cli_command([pixi, "lock", "--manifest-path", manifest_path]) + + packages = locked_package_names(tmp_pixi_workspace) + assert "package-unix" in packages["linux-64"] + assert "package-windows" not in packages["linux-64"] + + +def test_invalid_conditional_expression( + pixi: Path, tmp_pixi_workspace: Path, target_specific_channel_1: str +) -> None: + """An expression that does not parse fails the lock with a helpful error.""" + manifest_path = write_workspace( + tmp_pixi_workspace, + target_specific_channel_1, + {"if(host_platform ==)": {"package-unix": "*"}}, + # A single fixed platform keeps the error output deterministic. + platforms=["linux-64"], + ) + + verify_cli_command( + [pixi, "lock", "--manifest-path", manifest_path], + expected_exit_code=ExitCode.FAILURE, + stderr_contains="invalid selector expression `host_platform ==`", + ) From 1aba46ec9eca7a5bf8b12eeef75a552e6a2afa88 Mon Sep 17 00:00:00 2001 From: Julian Hofer Date: Thu, 11 Jun 2026 12:13:03 +0000 Subject: [PATCH 4/4] refactor: lower package platform targets to if() conditionals at parse time --- .../pixi_build_backend/src/common/variants.rs | 4 +- .../src/generated_recipe.rs | 14 +- .../src/specs_conversion.rs | 96 ++-------- .../pixi_build_backend/src/traits/project.rs | 21 +-- .../pixi_build_backend/src/traits/targets.rs | 130 ++++--------- .../tests/integration/common/model.rs | 53 +++--- .../tests/integration/protocol.rs | 13 +- .../pixi_build_backend_passthrough/src/lib.rs | 66 ++----- crates/pixi_build_cmake/src/main.rs | 2 +- .../discovery__discovery@inherit__nested.snap | 1 - .../discovery__discovery@nested__nested.snap | 1 - .../discovery__discovery@simple.snap | 1 - crates/pixi_build_mojo/src/main.rs | 2 +- crates/pixi_build_python/src/main.rs | 2 +- crates/pixi_build_r/src/main.rs | 2 +- .../pixi_build_rattler_build/src/protocol.rs | 6 - crates/pixi_build_rust/src/main.rs | 59 ++---- .../src/project_model.rs | 20 +- ...sts__conversions_v1_docs@advanced_cpp.snap | 4 +- ...model__tests__conversions_v1_docs@cpp.snap | 5 +- ...model__tests__conversions_v1_docs@dev.snap | 5 +- ...__conversions_v1_docs@getting_started.snap | 5 +- ...el__tests__conversions_v1_docs@python.snap | 5 +- ..._tests__conversions_v1_docs@workspace.snap | 5 +- ...onversions_v1_docs@workspace_variants.snap | 5 +- ...nversions_v1_examples@array-api-extra.snap | 4 +- ..._v1_examples@conditional-dependencies.snap | 2 +- ...onversions_v1_examples@cpp-git-source.snap | 5 +- ...ests__conversions_v1_examples@cpp-sdl.snap | 5 +- ...l__tests__conversions_v1_examples@dev.snap | 5 +- ...el__tests__conversions_v1_examples@v3.snap | 4 +- crates/pixi_build_types/src/project_model.rs | 153 +++++---------- crates/pixi_manifest/src/manifests/package.rs | 16 +- crates/pixi_manifest/src/toml/manifest.rs | 3 +- crates/pixi_manifest/src/toml/package.rs | 176 +++++++++++++----- .../src/utils/inheritable_package_map.rs | 5 +- docs/build/workspace_dependencies.md | 4 +- schema/pixi_build_api.json | 12 +- 38 files changed, 353 insertions(+), 568 deletions(-) diff --git a/crates/pixi_build_backend/src/common/variants.rs b/crates/pixi_build_backend/src/common/variants.rs index 1d1767631e..35d6e0a532 100644 --- a/crates/pixi_build_backend/src/common/variants.rs +++ b/crates/pixi_build_backend/src/common/variants.rs @@ -6,7 +6,6 @@ use miette::IntoDiagnostic; use rattler_build_jinja::Variable; use rattler_build_types::NormalizedKey; use rattler_build_variant_config::VariantConfig; -use rattler_conda_types::Platform; use crate::ProjectModel; @@ -14,7 +13,6 @@ use crate::ProjectModel; pub fn compute_variants( project_model: &P, input_variant_configuration: Option>>, - host_platform: Platform, ) -> miette::Result>> { // Create a variant config from the variant configuration in the parameters. let variant_config = VariantConfig { @@ -23,7 +21,7 @@ pub fn compute_variants( }; // Determine the variant keys that are used in the recipe. - let used_variants = project_model.used_variants(Some(host_platform)); + let used_variants = project_model.used_variants(); // Determine the combinations of the used variants. variant_config diff --git a/crates/pixi_build_backend/src/generated_recipe.rs b/crates/pixi_build_backend/src/generated_recipe.rs index 6579676668..e65b2b5feb 100644 --- a/crates/pixi_build_backend/src/generated_recipe.rs +++ b/crates/pixi_build_backend/src/generated_recipe.rs @@ -378,7 +378,7 @@ impl MetadataProvider for DefaultMetadataProvider { mod tests { use ordermap::OrderMap; use pixi_build_types::{ - BinaryPackageSpec, PackageSpec, SourcePackageName, Target, TargetSelector, Targets, + BinaryPackageSpec, ConditionalExpression, PackageSpec, SourcePackageName, Target, Targets, }; use rattler_conda_types::{Flag, PackageName}; @@ -413,7 +413,6 @@ mod tests { extra_dependencies: Some(extras_with_gtest()), ..Target::default() }), - targets: None, conditional: None, }), ..ProjectModel::default() @@ -431,13 +430,13 @@ mod tests { ); } - /// Per-target extras must be wrapped in a `Conditional` block in the + /// Conditional extras must be wrapped in a `Conditional` block in the /// generated recipe rather than landing as a bare entry. #[test] fn generated_recipe_declares_per_target_extras() { - let mut platform_targets = OrderMap::new(); - platform_targets.insert( - TargetSelector::Win, + let mut conditional_targets = OrderMap::new(); + conditional_targets.insert( + ConditionalExpression::new("win"), Target { extra_dependencies: Some(extras_with_gtest()), ..Target::default() @@ -449,8 +448,7 @@ mod tests { version: Some("0.1.0".parse().unwrap()), targets: Some(Targets { default_target: None, - targets: Some(platform_targets), - conditional: None, + conditional: Some(conditional_targets), }), ..ProjectModel::default() }; diff --git a/crates/pixi_build_backend/src/specs_conversion.rs b/crates/pixi_build_backend/src/specs_conversion.rs index 8b03765c33..6921f275ad 100644 --- a/crates/pixi_build_backend/src/specs_conversion.rs +++ b/crates/pixi_build_backend/src/specs_conversion.rs @@ -4,7 +4,7 @@ use minijinja::Value; use ordermap::OrderMap; use pixi_build_types::{ BinaryPackageSpec, ExtraGroupName, PackageSpec, SourcePackageName, SourcePackageSpec, Target, - TargetSelector, Targets, + Targets, procedures::conda_build_v1::{ CondaBuildV1Dependency, CondaBuildV1DependencySource, CondaBuildV1Prefix, CondaBuildV1RunExports, @@ -51,23 +51,6 @@ pub fn from_source_matchspec_into_package_spec( .ok_or_else(|| miette::miette!("Only file, http/https and git are supported for now")) } -#[derive(Debug, Clone)] -pub enum PlatformKind { - Build, - Host, - Target, -} - -impl std::fmt::Display for PlatformKind { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - PlatformKind::Build => write!(f, "build"), - PlatformKind::Host => write!(f, "host"), - PlatformKind::Target => write!(f, "target"), - } - } -} - pub fn convert_variant_from_pixi_build_types(variant: pixi_build_types::VariantValue) -> Variable { match variant { pixi_build_types::VariantValue::String(s) => Variable::from(s), @@ -83,25 +66,6 @@ pub fn convert_variant_to_pixi_build_types( pixi_build_types::VariantValue::deserialize(value) } -pub fn to_rattler_build_selector( - selector: &TargetSelector, - platform_kind: PlatformKind, -) -> Result { - let selector_str = match selector { - TargetSelector::Platform(p) | TargetSelector::Subdir(p) => { - format!("{platform_kind}_platform == '{p}'") - } - _ => selector.to_string(), - }; - - JinjaExpression::new(selector_str.clone()).map_err(|message| { - SelectorConversionError::InvalidExpression { - expression: selector_str, - message, - } - }) -} - /// Convert a `PackageDependency` to a `SerializableMatchSpec` for use in /// rattler-build's `Requirements`. fn package_dependency_to_matchspec(dep: PackageDependency) -> SerializableMatchSpec { @@ -193,15 +157,6 @@ pub fn from_targets_v1_to_conditional_requirements( items.add_target(default_target, None); } - // Add specific targets. The platform selector becomes a condition on every - // dependency under the target. - if let Some(specific_targets) = &targets.targets { - for (selector, target) in specific_targets { - let condition = to_rattler_build_selector(selector, PlatformKind::Host)?; - items.add_target(target, Some(&condition)); - } - } - // Add conditional `if(...)` targets. The expression is handed to // rattler-build verbatim; pixi does not evaluate it. if let Some(conditional_targets) = &targets.conditional { @@ -622,7 +577,6 @@ mod test { extra_dependencies: Some(extras), ..Target::default() }), - targets: None, conditional: None, }; let requirements = from_targets_v1_to_conditional_requirements(&targets).unwrap(); @@ -636,20 +590,6 @@ mod test { ); } - #[test] - fn test_to_rattler_build_selector_platform() { - // Platform selectors become `_platform == '...'`. - assert_eq!( - to_rattler_build_selector( - &TargetSelector::Platform("linux-64".to_string()), - PlatformKind::Host - ) - .unwrap() - .source(), - "host_platform == 'linux-64'" - ); - } - /// A conditional `if(...)` dependency is wrapped in a `Conditional` carrying /// the user's expression verbatim. #[test] @@ -674,7 +614,6 @@ mod test { ); let targets = Targets { default_target: None, - targets: None, conditional: Some(conditional), }; @@ -715,7 +654,6 @@ mod test { ); let targets = Targets { default_target: None, - targets: None, conditional: Some(conditional), }; @@ -726,10 +664,10 @@ mod test { ); } - /// Per-target extras must be wrapped in a `Conditional` so the resulting - /// recipe only pulls them in for the matching platform selector. + /// Conditional extras must be wrapped in a `Conditional` so the resulting + /// recipe only pulls them in when the expression holds. #[test] - fn test_per_target_extras_conversion() { + fn test_conditional_extras_conversion() { let mut dependencies = OrderMap::new(); dependencies.insert( SourcePackageName::from(PackageName::new_unchecked("gtest")), @@ -746,9 +684,9 @@ mod test { dependencies, ); - let mut platform_targets = OrderMap::new(); - platform_targets.insert( - TargetSelector::Win, + let mut conditional = OrderMap::new(); + conditional.insert( + ConditionalExpression::new("win"), Target { extra_dependencies: Some(extras), ..Target::default() @@ -756,8 +694,7 @@ mod test { ); let targets = Targets { default_target: None, - targets: Some(platform_targets), - conditional: None, + conditional: Some(conditional), }; let requirements = from_targets_v1_to_conditional_requirements(&targets).unwrap(); @@ -771,7 +708,7 @@ mod test { .expect("group has at least one item"); assert!( matches!(first, Item::Conditional(_)), - "per-target extras must be wrapped in a Conditional, got: {first:?}", + "conditional extras must be wrapped in a Conditional, got: {first:?}", ); } @@ -847,20 +784,19 @@ mod test { /// Regression test: `from_targets_v1_to_conditional_requirements` must /// populate `Requirements.run_constraints` from both the default target and - /// platform-specific targets. The variable was being created and threaded + /// conditional targets. The variable was being created and threaded /// to the output but never extended. #[test] fn test_targets_v1_run_constraints_in_requirements() { // Default-target run-constraint plus a linux-64 specific one. - let mut targets_map = OrderMap::new(); - targets_map.insert( - TargetSelector::Platform("linux-64".to_string()), + let mut conditional_map = OrderMap::new(); + conditional_map.insert( + ConditionalExpression::new("host_platform == 'linux-64'"), target_with_only_run_constraints("linux-only", ">=2.0"), ); let targets = Targets { default_target: Some(target_with_only_run_constraints("everywhere", ">=1.0")), - targets: Some(targets_map), - conditional: None, + conditional: Some(conditional_map), }; let req = from_targets_v1_to_conditional_requirements(&targets).unwrap(); @@ -884,10 +820,10 @@ mod test { .expect("expected a concrete match spec"); assert_eq!(default_value.0.to_string(), "everywhere >=1.0"); - // Platform-specific target → wrapped in a Conditional. + // Conditional target → wrapped in a Conditional. let conditional = match items.next().unwrap() { Item::Conditional(c) => c, - Item::Value(_) => panic!("expected platform-specific constraint to be Conditional"), + Item::Value(_) => panic!("expected conditional constraint to be Conditional"), }; let then_item = conditional .then diff --git a/crates/pixi_build_backend/src/traits/project.rs b/crates/pixi_build_backend/src/traits/project.rs index 60c6460678..e50790dfb8 100644 --- a/crates/pixi_build_backend/src/traits/project.rs +++ b/crates/pixi_build_backend/src/traits/project.rs @@ -9,7 +9,7 @@ use std::collections::HashSet; use itertools::Itertools; use pixi_build_types::{self as pbt}; use rattler_build_types::NormalizedKey; -use rattler_conda_types::{Platform, Version}; +use rattler_conda_types::Version; use super::{Dependencies, PackageSpec, targets::Targets}; @@ -22,17 +22,12 @@ pub trait ProjectModel { fn targets(&self) -> Option<&Self::Targets>; /// Return the dependencies of the project model - fn dependencies( - &self, - platform: Option, - ) -> Dependencies<'_, <::Targets as Targets>::Spec> { - self.targets() - .map(|t| t.dependencies(platform)) - .unwrap_or_default() + fn dependencies(&self) -> Dependencies<'_, <::Targets as Targets>::Spec> { + self.targets().map(|t| t.dependencies()).unwrap_or_default() } /// Return the used variants of the project model - fn used_variants(&self, platform: Option) -> HashSet; + fn used_variants(&self) -> HashSet; /// Return the name of the project model fn name(&self) -> Option<&String>; @@ -56,23 +51,23 @@ impl ProjectModel for pbt::ProjectModel { &self.version } - fn used_variants(&self, platform: Option) -> HashSet { + fn used_variants(&self) -> HashSet { let build_dependencies = self .targets() .iter() - .flat_map(|target| target.build_dependencies(platform)) + .flat_map(|target| target.build_dependencies()) .collect_vec(); let host_dependencies = self .targets() .iter() - .flat_map(|target| target.host_dependencies(platform)) + .flat_map(|target| target.host_dependencies()) .collect_vec(); let run_dependencies = self .targets() .iter() - .flat_map(|target| target.run_dependencies(platform)) + .flat_map(|target| target.run_dependencies()) .collect_vec(); build_dependencies diff --git a/crates/pixi_build_backend/src/traits/targets.rs b/crates/pixi_build_backend/src/traits/targets.rs index 9fd501f735..2b4752ac6f 100644 --- a/crates/pixi_build_backend/src/traits/targets.rs +++ b/crates/pixi_build_backend/src/traits/targets.rs @@ -6,7 +6,7 @@ //! * [`TargetSelector`] - An extension trait that extends the target selector with additional functionality. //! * [`Dependencies`] - A wrapper struct that contains all dependencies for a target. use indexmap::IndexMap; -use itertools::{Either, Itertools}; +use itertools::Itertools; use pixi_build_types::SourcePackageName; use rattler_conda_types::Platform; @@ -81,9 +81,12 @@ impl<'a, S> Dependencies<'a, S> { } /// A trait that represent a project target. +/// +/// Dependencies are carried on the default target plus conditional +/// `if()` entries. The conditional entries are evaluated by +/// rattler-build, not here, so the dependency accessors expose the default +/// target only. pub trait Targets { - /// The selector, in pixi this is something like `[target.linux-64] - type Selector: TargetSelector; /// The target it is resolving to type Target; @@ -96,54 +99,20 @@ pub trait Targets { /// Return a spec that matches any version fn empty_spec() -> Self::Spec; - /// Returns all targets - fn targets(&self) -> impl Iterator; - - /// Return all dependencies for the given platform - fn dependencies(&self, platform: Option) -> Dependencies<'_, Self::Spec>; - - /// Return the run dependencies for the given platform - fn run_dependencies( - &self, - platform: Option, - ) -> IndexMap<&SourcePackageName, &Self::Spec>; - - /// Return the run constraints for the given platform - fn run_constraints( - &self, - platform: Option, - ) -> IndexMap<&SourcePackageName, &Self::Spec>; - - /// Return the host dependencies for the given platform - fn host_dependencies( - &self, - platform: Option, - ) -> IndexMap<&SourcePackageName, &Self::Spec>; - - /// Return the build dependencies for the given platform - fn build_dependencies( - &self, - platform: Option, - ) -> IndexMap<&SourcePackageName, &Self::Spec>; - - /// Resolve the target for the given platform. - fn resolve(&self, platform: Option) -> impl Iterator { - if let Some(platform) = platform { - let iter = self - .default_target() - .into_iter() - .chain(self.targets().filter_map(move |(selector, target)| { - if selector.matches(platform) { - Some(target) - } else { - None - } - })); - Either::Right(iter) - } else { - Either::Left(self.default_target().into_iter()) - } - } + /// Return all dependencies of the default target + fn dependencies(&self) -> Dependencies<'_, Self::Spec>; + + /// Return the run dependencies of the default target + fn run_dependencies(&self) -> IndexMap<&SourcePackageName, &Self::Spec>; + + /// Return the run constraints of the default target + fn run_constraints(&self) -> IndexMap<&SourcePackageName, &Self::Spec>; + + /// Return the host dependencies of the default target + fn host_dependencies(&self) -> IndexMap<&SourcePackageName, &Self::Spec>; + + /// Return the build dependencies of the default target + fn build_dependencies(&self) -> IndexMap<&SourcePackageName, &Self::Spec>; } // === Below here are the implementations for v1 === @@ -161,7 +130,6 @@ impl TargetSelector for pbt::TargetSelector { } impl Targets for pbt::Targets { - type Selector = pbt::TargetSelector; type Target = pbt::Target; type Spec = pbt::PackageSpec; @@ -170,71 +138,47 @@ impl Targets for pbt::Targets { self.default_target.as_ref() } - fn targets(&self) -> impl Iterator { - self.targets.iter().flatten() - } - fn empty_spec() -> pbt::PackageSpec { rattler_conda_types::VersionSpec::Any.into() } - fn run_dependencies( - &self, - platform: Option, - ) -> IndexMap<&SourcePackageName, &pbt::PackageSpec> { - let targets = self.resolve(platform).collect_vec(); - - targets - .iter() + fn run_dependencies(&self) -> IndexMap<&SourcePackageName, &pbt::PackageSpec> { + self.default_target() + .into_iter() .flat_map(|t| t.run_dependencies.iter()) .flatten() .collect::>() } - fn run_constraints( - &self, - platform: Option, - ) -> IndexMap<&SourcePackageName, &pbt::PackageSpec> { - let targets = self.resolve(platform).collect_vec(); - - targets - .iter() + fn run_constraints(&self) -> IndexMap<&SourcePackageName, &pbt::PackageSpec> { + self.default_target() + .into_iter() .flat_map(|t| t.run_constraints.iter()) .flatten() .collect::>() } - fn host_dependencies( - &self, - platform: Option, - ) -> IndexMap<&SourcePackageName, &pbt::PackageSpec> { - let targets = self.resolve(platform).collect_vec(); - - targets - .iter() + fn host_dependencies(&self) -> IndexMap<&SourcePackageName, &pbt::PackageSpec> { + self.default_target() + .into_iter() .flat_map(|t| t.host_dependencies.iter()) .flatten() .collect::>() } - fn build_dependencies( - &self, - platform: Option, - ) -> IndexMap<&SourcePackageName, &pbt::PackageSpec> { - let targets = self.resolve(platform).collect_vec(); - - targets - .iter() + fn build_dependencies(&self) -> IndexMap<&SourcePackageName, &pbt::PackageSpec> { + self.default_target() + .into_iter() .flat_map(|t| t.build_dependencies.iter()) .flatten() .collect::>() } - fn dependencies(&self, platform: Option) -> Dependencies<'_, Self::Spec> { - let build_deps = self.build_dependencies(platform); - let host_deps = self.host_dependencies(platform); - let run_deps = self.run_dependencies(platform); - let run_constraints = self.run_constraints(platform); + fn dependencies(&self) -> Dependencies<'_, Self::Spec> { + let build_deps = self.build_dependencies(); + let host_deps = self.host_dependencies(); + let run_deps = self.run_dependencies(); + let run_constraints = self.run_constraints(); Dependencies::new(run_deps, run_constraints, host_deps, build_deps) } diff --git a/crates/pixi_build_backend/tests/integration/common/model.rs b/crates/pixi_build_backend/tests/integration/common/model.rs index 43bbf1517c..79253fefc0 100644 --- a/crates/pixi_build_backend/tests/integration/common/model.rs +++ b/crates/pixi_build_backend/tests/integration/common/model.rs @@ -1,8 +1,9 @@ /// This file contains the test model, which is a minimal example of a ProjectModel /// that can be used to create a ProjectModel from a JSON fixture file. use pixi_build_types::{ - BinaryPackageSpec as PbtBinaryPackageSpec, PackageSpec as PbtPackageSpec, PathSpec, - ProjectModel, Target as PbtTarget, TargetSelector as PbtTargetSelector, Targets as PbtTargets, + BinaryPackageSpec as PbtBinaryPackageSpec, ConditionalExpression, + PackageSpec as PbtPackageSpec, PathSpec, ProjectModel, Target as PbtTarget, + Targets as PbtTargets, }; use rattler_conda_types::{PackageName, ParseStrictness, Version, VersionSpec}; @@ -103,23 +104,22 @@ pub(crate) fn load_project_model_from_json(filename: &str) -> TestProjectModel { pub(crate) fn convert_test_model_to_project_model_v1(test_model: TestProjectModel) -> ProjectModel { use std::str::FromStr; - // Convert the targets + // Convert the targets. Selector targets lower to the equivalent + // conditional expression, mirroring what pixi does at parse time. + let conditional: ordermap::OrderMap = test_model + .targets + .targets + .into_iter() + .map(|(selector, target)| { + ( + target_selector_expression(selector), + convert_target_to_v1(&target), + ) + }) + .collect(); let targets_v1 = PbtTargets { default_target: Some(convert_target_to_v1(&test_model.targets.default_target)), - targets: Some( - test_model - .targets - .targets - .into_iter() - .map(|(selector, target)| { - ( - convert_target_selector_to_v1(selector), - convert_target_to_v1(&target), - ) - }) - .collect(), - ), - conditional: None, + conditional: (!conditional.is_empty()).then_some(conditional), }; ProjectModel { @@ -217,15 +217,16 @@ fn convert_target_to_v1(target: &Target) -> PbtTarget { } } -/// Converts a test TargetSelector to TargetSelector -fn convert_target_selector_to_v1(selector: TargetSelector) -> PbtTargetSelector { - match selector { - TargetSelector::Unix => PbtTargetSelector::Unix, - TargetSelector::Linux => PbtTargetSelector::Linux, - TargetSelector::Win => PbtTargetSelector::Win, - TargetSelector::MacOs => PbtTargetSelector::MacOs, - TargetSelector::Platform(p) => PbtTargetSelector::Platform(p), - } +/// The conditional expression a test TargetSelector lowers to, mirroring the +/// lowering pixi performs at manifest parse time. +fn target_selector_expression(selector: TargetSelector) -> ConditionalExpression { + ConditionalExpression::new(match selector { + TargetSelector::Unix => "unix".to_string(), + TargetSelector::Linux => "linux".to_string(), + TargetSelector::Win => "win".to_string(), + TargetSelector::MacOs => "osx".to_string(), + TargetSelector::Platform(p) => format!("host_platform == '{p}'"), + }) } /// Converts a test PackageSpec to PackageSpec diff --git a/crates/pixi_build_backend/tests/integration/protocol.rs b/crates/pixi_build_backend/tests/integration/protocol.rs index d2f38baab5..b349323051 100644 --- a/crates/pixi_build_backend/tests/integration/protocol.rs +++ b/crates/pixi_build_backend/tests/integration/protocol.rs @@ -8,8 +8,8 @@ use pixi_build_backend::{ utils::test::intermediate_conda_outputs, }; use pixi_build_types::{ - BinaryPackageSpec, ExtraGroupName, PackageSpec, PathSpec, ProjectModel, SourcePackageName, - Target, TargetSelector, Targets, + BinaryPackageSpec, ConditionalExpression, ExtraGroupName, PackageSpec, PathSpec, ProjectModel, + SourcePackageName, Target, Targets, procedures::conda_build_v1::{CondaBuildV1Output, CondaBuildV1Params}, }; use rattler_build_core::console_utils::LoggingOutputHandler; @@ -257,9 +257,9 @@ async fn test_conda_outputs_extra_dependencies() { let mut win_extras = OrderMap::new(); win_extras.insert(ExtraGroupName::new("gpu").unwrap(), gpu_group); - let mut platform_targets = OrderMap::new(); - platform_targets.insert( - TargetSelector::Win, + let mut conditional_targets = OrderMap::new(); + conditional_targets.insert( + ConditionalExpression::new("win"), Target { extra_dependencies: Some(win_extras), ..Target::default() @@ -274,8 +274,7 @@ async fn test_conda_outputs_extra_dependencies() { extra_dependencies: Some(default_extras), ..Target::default() }), - targets: Some(platform_targets), - conditional: None, + conditional: Some(conditional_targets), }), ..ProjectModel::default() }; diff --git a/crates/pixi_build_backend_passthrough/src/lib.rs b/crates/pixi_build_backend_passthrough/src/lib.rs index 384ffe427c..f2bac20979 100644 --- a/crates/pixi_build_backend_passthrough/src/lib.rs +++ b/crates/pixi_build_backend_passthrough/src/lib.rs @@ -20,7 +20,7 @@ use pixi_build_frontend::{ }; use pixi_build_types::{ BackendCapabilities, BinaryPackageSpec, ConstraintSpec, ExtraGroupName, NamedSpec, PackageSpec, - ProjectModel, SourcePackageName, Target, TargetSelector, Targets, VariantValue, + ProjectModel, SourcePackageName, Target, Targets, VariantValue, procedures::{ conda_build_v1::{CondaBuildV1Params, CondaBuildV1Result}, conda_outputs::{ @@ -402,24 +402,14 @@ fn find_variant_keys(project_model: &ProjectModel, params: &CondaOutputsParams) } }; - // Check default target + // Check default target. Conditional targets are rejected by + // `reject_conditional_targets` before this point. if let Some(default_target) = &targets.default_target { check_deps(default_target.build_dependencies.as_ref()); check_deps(default_target.host_dependencies.as_ref()); check_deps(default_target.run_dependencies.as_ref()); } - // Check platform-specific targets - if let Some(targets_map) = &targets.targets { - for (selector, target) in targets_map { - if matches_target_selector(selector, params.host_platform) { - check_deps(target.build_dependencies.as_ref()); - check_deps(target.host_dependencies.as_ref()); - check_deps(target.run_dependencies.as_ref()); - } - } - } - variant_keys.into_iter().collect() } @@ -568,7 +558,6 @@ fn create_output( let mut run_dependencies = extract_dependencies( &project_model.targets, |t| t.run_dependencies.as_ref(), - params.host_platform, &variant, ); @@ -576,7 +565,6 @@ fn create_output( let host_deps = extract_dependencies( &project_model.targets, |t| t.host_dependencies.as_ref(), - params.host_platform, &variant, ); @@ -598,9 +586,7 @@ fn create_output( // Extra groups come from the project model, and - // when the backend was handed a pre-built package - from its index.json. let mut extra_dependencies = convert_extra_depends(&index_json.experimental_extra_depends); - for (group, specs) in - extract_extra_dependencies(&project_model.targets, params.host_platform, &variant) - { + for (group, specs) in extract_extra_dependencies(&project_model.targets, &variant) { extra_dependencies.entry(group).or_default().extend(specs); } @@ -608,7 +594,6 @@ fn create_output( build_dependencies: Some(extract_dependencies( &project_model.targets, |t| t.build_dependencies.as_ref(), - params.host_platform, &variant, )), host_dependencies: Some(host_deps), @@ -650,10 +635,9 @@ fn create_output( fn extract_dependencies Option<&OrderMap>>( targets: &Option, extract: F, - platform: Platform, variant: &BTreeMap, ) -> CondaOutputDependencies { - let depends = applicable_targets(targets, platform) + let depends = applicable_targets(targets) .into_iter() .flat_map(|target| extract(target).into_iter().flat_map(OrderMap::iter)) .map(|(name, spec)| NamedSpec { @@ -668,25 +652,12 @@ fn extract_dependencies Option<&OrderMap, platform: Platform) -> Vec<&Target> { +/// Returns the default target. Conditional targets are rejected by +/// `reject_conditional_targets` before this point. +fn applicable_targets(targets: &Option) -> Vec<&Target> { targets .iter() - .flat_map(|targets| { - targets - .default_target - .iter() - .chain( - targets - .targets - .iter() - .flatten() - .flat_map(move |(selector, target)| { - matches_target_selector(selector, platform).then_some(target) - }), - ) - }) + .flat_map(|targets| targets.default_target.iter()) .collect() } @@ -717,15 +688,13 @@ fn resolve_dependency_spec( } /// Extracts the extra groups declared by the project -/// model for the given platform, mirroring how `extract_dependencies` walks -/// targets. Groups declared across multiple matching targets are merged. +/// model, mirroring how `extract_dependencies` walks targets. fn extract_extra_dependencies( targets: &Option, - platform: Platform, variant: &BTreeMap, ) -> BTreeMap>> { let mut result: BTreeMap>> = BTreeMap::new(); - for target in applicable_targets(targets, platform) { + for target in applicable_targets(targets) { let Some(extras) = target.extra_dependencies.as_ref() else { continue; }; @@ -898,19 +867,6 @@ fn convert_run_exports_json( } } -/// Returns true if the given [`TargetSelector`] matches the specified -/// `platform`. -fn matches_target_selector(selector: &TargetSelector, platform: Platform) -> bool { - match selector { - TargetSelector::Unix => platform.is_unix(), - TargetSelector::Linux => platform.is_linux(), - TargetSelector::Win => platform.is_windows(), - TargetSelector::MacOs => platform.is_osx(), - TargetSelector::Platform(target_platform) => target_platform == platform.as_str(), - TargetSelector::Subdir(subdir) => subdir == platform.as_str(), - } -} - /// The passthrough backend has no jinja evaluator and therefore cannot decide /// whether an `if(...)` conditional applies. Panic rather than silently dropping /// the conditional dependencies; a real backend evaluates these via diff --git a/crates/pixi_build_cmake/src/main.rs b/crates/pixi_build_cmake/src/main.rs index 01fd937f3c..0db3b0ac8d 100644 --- a/crates/pixi_build_cmake/src/main.rs +++ b/crates/pixi_build_cmake/src/main.rs @@ -91,7 +91,7 @@ impl GenerateRecipe for CMakeGenerator { // This properly handles target selectors like [target.linux-64] by using // the ProjectModel trait's platform-aware API instead of trying to evaluate // rattler-build selectors with simple string comparison. - let model_dependencies = model.dependencies(Some(host_platform)); + let model_dependencies = model.dependencies(); // Get the list of compilers from config, defaulting to ["cxx"] if not specified let compilers = config diff --git a/crates/pixi_build_discovery/tests/snapshots/discovery__discovery@inherit__nested.snap b/crates/pixi_build_discovery/tests/snapshots/discovery__discovery@inherit__nested.snap index ffda773c76..cf33769305 100644 --- a/crates/pixi_build_discovery/tests/snapshots/discovery__discovery@inherit__nested.snap +++ b/crates/pixi_build_discovery/tests/snapshots/discovery__discovery@inherit__nested.snap @@ -38,6 +38,5 @@ init-params: buildDependencies: {} runDependencies: {} runConstraints: {} - targets: {} configuration: ~ target-configuration: ~ diff --git a/crates/pixi_build_discovery/tests/snapshots/discovery__discovery@nested__nested.snap b/crates/pixi_build_discovery/tests/snapshots/discovery__discovery@nested__nested.snap index a16ba2c6ab..d1f81a9d53 100644 --- a/crates/pixi_build_discovery/tests/snapshots/discovery__discovery@nested__nested.snap +++ b/crates/pixi_build_discovery/tests/snapshots/discovery__discovery@nested__nested.snap @@ -38,6 +38,5 @@ init-params: buildDependencies: {} runDependencies: {} runConstraints: {} - targets: {} configuration: ~ target-configuration: ~ diff --git a/crates/pixi_build_discovery/tests/snapshots/discovery__discovery@simple.snap b/crates/pixi_build_discovery/tests/snapshots/discovery__discovery@simple.snap index 711a652cec..c0bc63d796 100644 --- a/crates/pixi_build_discovery/tests/snapshots/discovery__discovery@simple.snap +++ b/crates/pixi_build_discovery/tests/snapshots/discovery__discovery@simple.snap @@ -38,6 +38,5 @@ init-params: buildDependencies: {} runDependencies: {} runConstraints: {} - targets: {} configuration: ~ target-configuration: ~ diff --git a/crates/pixi_build_mojo/src/main.rs b/crates/pixi_build_mojo/src/main.rs index 0a407bfb22..8f65ead640 100644 --- a/crates/pixi_build_mojo/src/main.rs +++ b/crates/pixi_build_mojo/src/main.rs @@ -82,7 +82,7 @@ impl GenerateRecipe for MojoGenerator { // This properly handles target selectors like [target.linux-64] by using // the ProjectModel trait's platform-aware API instead of trying to evaluate // rattler-build selectors with simple string comparison. - let model_dependencies = model.dependencies(Some(host_platform)); + let model_dependencies = model.dependencies(); let compilers = config.compilers.clone().unwrap_or_default(); diff --git a/crates/pixi_build_python/src/main.rs b/crates/pixi_build_python/src/main.rs index c5f060c150..533679bae7 100644 --- a/crates/pixi_build_python/src/main.rs +++ b/crates/pixi_build_python/src/main.rs @@ -171,7 +171,7 @@ impl GenerateRecipe for PythonGenerator { // This properly handles target selectors like [target.linux-64] by using // the ProjectModel trait's platform-aware API instead of trying to evaluate // rattler-build selectors with simple string comparison. - let model_dependencies = model.dependencies(Some(host_platform)); + let model_dependencies = model.dependencies(); let cython_pkg = pixi_build_types::SourcePackageName::from( rattler_conda_types::PackageName::new_unchecked("cython"), ); diff --git a/crates/pixi_build_r/src/main.rs b/crates/pixi_build_r/src/main.rs index 15afa48204..10d6b16a64 100644 --- a/crates/pixi_build_r/src/main.rs +++ b/crates/pixi_build_r/src/main.rs @@ -97,7 +97,7 @@ impl GenerateRecipe for RGenerator { GeneratedRecipe::from_model(model.clone(), &mut metadata_provider).into_diagnostic()?; let requirements = &mut generated_recipe.recipe.requirements; - let model_dependencies = model.dependencies(Some(host_platform)); + let model_dependencies = model.dependencies(); // Auto-detect or use configured compilers let compilers = match &config.compilers { diff --git a/crates/pixi_build_rattler_build/src/protocol.rs b/crates/pixi_build_rattler_build/src/protocol.rs index e8b296f80b..3939132e70 100644 --- a/crates/pixi_build_rattler_build/src/protocol.rs +++ b/crates/pixi_build_rattler_build/src/protocol.rs @@ -707,12 +707,6 @@ impl ProtocolInstantiator for RattlerBuildBackendInstantiator { extract_workspace_deps(default_target, &mut workspace_dependencies)?; } - if let Some(targets) = target.targets { - for (_, target) in targets { - extract_workspace_deps(target, &mut workspace_dependencies)?; - } - } - if let Some(conditional) = target.conditional { for (_, target) in conditional { extract_workspace_deps(target, &mut workspace_dependencies)?; diff --git a/crates/pixi_build_rust/src/main.rs b/crates/pixi_build_rust/src/main.rs index 2714acbf83..3ca3119912 100644 --- a/crates/pixi_build_rust/src/main.rs +++ b/crates/pixi_build_rust/src/main.rs @@ -80,7 +80,7 @@ impl GenerateRecipe for RustGenerator { // This properly handles target selectors like [target.linux-64] by using // the ProjectModel trait's platform-aware API instead of trying to evaluate // rattler-build selectors with simple string comparison. - let model_dependencies = model.dependencies(Some(host_platform)); + let model_dependencies = model.dependencies(); // Get the list of compilers from config, defaulting to ["rust", "c"] if not // specified. The rust compilers already depend on the c compiler. @@ -853,8 +853,8 @@ mod tests { "name": "foobar", "version": "0.1.0", "targets": { - "targets": { - "linux-64": { + "conditional": { + "host_platform == 'linux-64'": { "buildDependencies": { "openssl": { "binary": { @@ -867,26 +867,16 @@ mod tests { } }); - // Test that the ProjectModel correctly filters dependencies for Linux64 - let linux_deps = project_model.dependencies(Some(Platform::Linux64)); + // Conditional dependencies are not part of the default target; they are + // evaluated by rattler-build, not the backend. + let default_deps = project_model.dependencies(); assert!( - linux_deps + !default_deps .build .contains_key(&pixi_build_types::SourcePackageName::from( PackageName::new_unchecked("openssl") )), - "openssl should be in build dependencies for Linux64" - ); - - // Test that the ProjectModel correctly excludes dependencies for Osx64 - let osx_deps = project_model.dependencies(Some(Platform::Osx64)); - assert!( - !osx_deps - .build - .contains_key(&pixi_build_types::SourcePackageName::from( - PackageName::new_unchecked("openssl") - )), - "openssl should NOT be in build dependencies for Osx64" + "openssl should NOT be in the default build dependencies" ); // Test that the intermediate recipe contains the conditional items with correct condition @@ -950,7 +940,7 @@ mod tests { "name": "foobar", "version": "0.1.0", "targets": { - "targets": { + "conditional": { "unix": { "buildDependencies": { "gcc": { @@ -964,37 +954,16 @@ mod tests { } }); - // Test that the ProjectModel correctly filters dependencies for Linux64 (unix) - let linux_deps = project_model.dependencies(Some(Platform::Linux64)); - assert!( - linux_deps - .build - .contains_key(&pixi_build_types::SourcePackageName::from( - PackageName::new_unchecked("gcc") - )), - "gcc should be in build dependencies for Linux64 (unix)" - ); - - // Test that the ProjectModel correctly filters dependencies for Osx64 (unix) - let osx_deps = project_model.dependencies(Some(Platform::Osx64)); - assert!( - osx_deps - .build - .contains_key(&pixi_build_types::SourcePackageName::from( - PackageName::new_unchecked("gcc") - )), - "gcc should be in build dependencies for Osx64 (unix)" - ); - - // Test that the ProjectModel correctly excludes dependencies for Win64 (not unix) - let win_deps = project_model.dependencies(Some(Platform::Win64)); + // Conditional dependencies are not part of the default target; they are + // evaluated by rattler-build, not the backend. + let default_deps = project_model.dependencies(); assert!( - !win_deps + !default_deps .build .contains_key(&pixi_build_types::SourcePackageName::from( PackageName::new_unchecked("gcc") )), - "gcc should NOT be in build dependencies for Win64 (not unix)" + "gcc should NOT be in the default build dependencies" ); // Test that the intermediate recipe contains the conditional items with correct condition diff --git a/crates/pixi_build_type_conversions/src/project_model.rs b/crates/pixi_build_type_conversions/src/project_model.rs index 83ecbb641c..7c48447656 100644 --- a/crates/pixi_build_type_conversions/src/project_model.rs +++ b/crates/pixi_build_type_conversions/src/project_model.rs @@ -197,6 +197,9 @@ fn to_target_v1( }) } +/// Converts a manifest [`TargetSelector`] to its wire form. Only used for the +/// per-target backend configuration (`[package.build.target.]`); +/// dependencies carry conditional expressions instead. pub fn to_target_selector_v1(selector: &TargetSelector) -> pbt::TargetSelector { match selector { TargetSelector::Platform(platform) => pbt::TargetSelector::Platform(platform.to_string()), @@ -212,20 +215,10 @@ fn to_targets_v1( manifest: &PackageManifest, channel_config: &ChannelConfig, ) -> Result { - let selected_targets = manifest - .targets - .iter() - .filter_map(|(k, v)| { - v.map(|selector| { - to_target_v1(k, channel_config) - .map(|target| (to_target_selector_v1(selector), target)) - }) - }) - .collect::, _>>()?; - // Conditional `if(...)` dependencies are not platform selectors; they are // carried separately and passed through to rattler-build, which evaluates - // the expression. + // the expression. The deprecated `[package.target.*]` tables are already + // lowered into conditional dependencies at parse time. let conditional = manifest .conditional_dependencies .iter() @@ -235,8 +228,7 @@ fn to_targets_v1( .collect::, _>>()?; Ok(pbt::Targets { - default_target: Some(to_target_v1(manifest.targets.default(), channel_config)?), - targets: Some(selected_targets), + default_target: Some(to_target_v1(&manifest.dependencies, channel_config)?), conditional: (!conditional.is_empty()).then_some(conditional), }) } diff --git a/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_docs@advanced_cpp.snap b/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_docs@advanced_cpp.snap index 2a3f626303..b2c194e8f2 100644 --- a/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_docs@advanced_cpp.snap +++ b/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_docs@advanced_cpp.snap @@ -1,5 +1,6 @@ --- source: crates/pixi_build_type_conversions/src/project_model.rs +assertion_line: 327 expression: project_model --- { @@ -21,7 +22,6 @@ expression: project_model "buildDependencies": {}, "runDependencies": {}, "runConstraints": {} - }, - "targets": {} + } } } diff --git a/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_docs@cpp.snap b/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_docs@cpp.snap index 6c205d30c6..a157ded921 100644 --- a/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_docs@cpp.snap +++ b/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_docs@cpp.snap @@ -1,6 +1,6 @@ --- source: crates/pixi_build_type_conversions/src/project_model.rs -assertion_line: 324 +assertion_line: 327 expression: project_model --- { @@ -74,7 +74,6 @@ expression: project_model "buildDependencies": {}, "runDependencies": {}, "runConstraints": {} - }, - "targets": {} + } } } diff --git a/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_docs@dev.snap b/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_docs@dev.snap index f519296107..b06c5de3e2 100644 --- a/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_docs@dev.snap +++ b/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_docs@dev.snap @@ -1,6 +1,6 @@ --- source: crates/pixi_build_type_conversions/src/project_model.rs -assertion_line: 324 +assertion_line: 327 expression: project_model --- { @@ -76,7 +76,6 @@ expression: project_model } }, "runConstraints": {} - }, - "targets": {} + } } } diff --git a/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_docs@getting_started.snap b/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_docs@getting_started.snap index c78f045c0b..6042fe857f 100644 --- a/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_docs@getting_started.snap +++ b/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_docs@getting_started.snap @@ -1,6 +1,6 @@ --- source: crates/pixi_build_type_conversions/src/project_model.rs -assertion_line: 324 +assertion_line: 327 expression: project_model --- { @@ -58,7 +58,6 @@ expression: project_model } }, "runConstraints": {} - }, - "targets": {} + } } } diff --git a/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_docs@python.snap b/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_docs@python.snap index f74d310972..95d9c1bd8e 100644 --- a/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_docs@python.snap +++ b/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_docs@python.snap @@ -1,6 +1,6 @@ --- source: crates/pixi_build_type_conversions/src/project_model.rs -assertion_line: 324 +assertion_line: 327 expression: project_model --- { @@ -58,7 +58,6 @@ expression: project_model } }, "runConstraints": {} - }, - "targets": {} + } } } diff --git a/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_docs@workspace.snap b/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_docs@workspace.snap index e950e27753..a8a65b9b06 100644 --- a/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_docs@workspace.snap +++ b/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_docs@workspace.snap @@ -1,6 +1,6 @@ --- source: crates/pixi_build_type_conversions/src/project_model.rs -assertion_line: 324 +assertion_line: 327 expression: project_model --- { @@ -70,7 +70,6 @@ expression: project_model } }, "runConstraints": {} - }, - "targets": {} + } } } diff --git a/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_docs@workspace_variants.snap b/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_docs@workspace_variants.snap index 84f28a194a..234b84177e 100644 --- a/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_docs@workspace_variants.snap +++ b/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_docs@workspace_variants.snap @@ -1,6 +1,6 @@ --- source: crates/pixi_build_type_conversions/src/project_model.rs -assertion_line: 324 +assertion_line: 327 expression: project_model --- { @@ -87,7 +87,6 @@ expression: project_model } }, "runConstraints": {} - }, - "targets": {} + } } } diff --git a/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_examples@array-api-extra.snap b/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_examples@array-api-extra.snap index 91c124dae9..3ee90ed35f 100644 --- a/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_examples@array-api-extra.snap +++ b/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_examples@array-api-extra.snap @@ -1,5 +1,6 @@ --- source: crates/pixi_build_type_conversions/src/project_model.rs +assertion_line: 318 expression: project_model --- { @@ -21,7 +22,6 @@ expression: project_model "buildDependencies": {}, "runDependencies": {}, "runConstraints": {} - }, - "targets": {} + } } } diff --git a/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_examples@conditional-dependencies.snap b/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_examples@conditional-dependencies.snap index a0a4392012..8159b588b7 100644 --- a/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_examples@conditional-dependencies.snap +++ b/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_examples@conditional-dependencies.snap @@ -1,5 +1,6 @@ --- source: crates/pixi_build_type_conversions/src/project_model.rs +assertion_line: 318 expression: project_model --- { @@ -22,7 +23,6 @@ expression: project_model "runDependencies": {}, "runConstraints": {} }, - "targets": {}, "conditional": { "linux or win": { "hostDependencies": {}, diff --git a/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_examples@cpp-git-source.snap b/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_examples@cpp-git-source.snap index 6005f84642..7b1de8f74b 100644 --- a/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_examples@cpp-git-source.snap +++ b/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_examples@cpp-git-source.snap @@ -1,6 +1,6 @@ --- source: crates/pixi_build_type_conversions/src/project_model.rs -assertion_line: 315 +assertion_line: 318 expression: project_model --- { @@ -40,7 +40,6 @@ expression: project_model "buildDependencies": {}, "runDependencies": {}, "runConstraints": {} - }, - "targets": {} + } } } diff --git a/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_examples@cpp-sdl.snap b/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_examples@cpp-sdl.snap index a55de22958..686c33d6fa 100644 --- a/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_examples@cpp-sdl.snap +++ b/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_examples@cpp-sdl.snap @@ -1,6 +1,6 @@ --- source: crates/pixi_build_type_conversions/src/project_model.rs -assertion_line: 315 +assertion_line: 318 expression: project_model --- { @@ -42,7 +42,6 @@ expression: project_model "buildDependencies": {}, "runDependencies": {}, "runConstraints": {} - }, - "targets": {} + } } } diff --git a/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_examples@dev.snap b/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_examples@dev.snap index f444120f28..d7c4300f4d 100644 --- a/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_examples@dev.snap +++ b/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_examples@dev.snap @@ -1,6 +1,6 @@ --- source: crates/pixi_build_type_conversions/src/project_model.rs -assertion_line: 315 +assertion_line: 318 expression: project_model --- { @@ -93,7 +93,6 @@ expression: project_model } }, "runConstraints": {} - }, - "targets": {} + } } } diff --git a/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_examples@v3.snap b/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_examples@v3.snap index eb2ceeaf7b..f05667a9fb 100644 --- a/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_examples@v3.snap +++ b/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_examples@v3.snap @@ -1,5 +1,6 @@ --- source: crates/pixi_build_type_conversions/src/project_model.rs +assertion_line: 318 expression: project_model --- { @@ -87,7 +88,6 @@ expression: project_model } } } - }, - "targets": {} + } } } diff --git a/crates/pixi_build_types/src/project_model.rs b/crates/pixi_build_types/src/project_model.rs index 7e43144d6b..20fce7ddfe 100644 --- a/crates/pixi_build_types/src/project_model.rs +++ b/crates/pixi_build_types/src/project_model.rs @@ -130,12 +130,10 @@ impl From for ConditionalExpression { /// Represents a platform-based target selector. /// -/// # Deprecated -/// -/// Platform target selectors correspond to the deprecated -/// `[package.target.]` tables and will be removed in a future version. -/// Use conditional `if()` dependencies instead, which are carried -/// separately in [`Targets::conditional`]. +/// Dependencies no longer use platform selectors; they are carried as +/// conditional `if()` entries in [`Targets::conditional`]. This +/// type only keys the per-target backend configuration +/// (`[package.build.target.]`) in the initialize request. #[derive(Debug, Clone, DeserializeFromStr, SerializeDisplay, Eq, PartialEq)] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub enum TargetSelector { @@ -182,29 +180,39 @@ impl FromStr for TargetSelector { } } +impl Hash for TargetSelector { + /// Custom hash implementation that uses discriminant values to keep the + /// hash as stable as possible when adding new enum variants. + fn hash(&self, state: &mut H) { + match self { + TargetSelector::Unix => 0u8.hash(state), + TargetSelector::Linux => 1u8.hash(state), + TargetSelector::Win => 2u8.hash(state), + TargetSelector::MacOs => 3u8.hash(state), + TargetSelector::Subdir(s) => { + 4u8.hash(state); + s.hash(state); + } + TargetSelector::Platform(p) => { + 5u8.hash(state); + p.hash(state); + } + } + } +} + /// A collect of targets including a default target. +/// +/// Platform-specific dependencies are carried exclusively as conditional +/// `if()` entries; the frontend lowers the deprecated +/// `[package.target.]` tables to the equivalent expression before +/// sending the project model. #[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] #[serde(rename_all = "camelCase")] pub struct Targets { pub default_target: Option, - /// Platform-specific targets. - /// - /// # Deprecated - /// - /// These correspond to the deprecated `[package.target.]` tables - /// and will be removed in a future version. Use [`Targets::conditional`] - /// (`if()` dependencies) instead. - /// - /// We use an [`OrderMap`] to preserve the order in which the items where - /// defined in the manifest. - #[cfg_attr( - feature = "schemars", - schemars(with = "Option>") - )] - pub targets: Option>, - /// Conditional `if()` dependencies. The expression is passed /// through to rattler-build, which evaluates it; pixi does not. Keyed by the /// bare inner expression without the `if(...)` wrapper. @@ -222,10 +230,9 @@ impl Targets { pub fn is_empty(&self) -> bool { let has_meaningless_default_target = self.default_target.as_ref().is_none_or(|t| t.is_empty()); - let has_only_empty_targets = self.targets.as_ref().is_none_or(|t| t.is_empty()); let has_only_empty_conditional = self.conditional.as_ref().is_none_or(|t| t.is_empty()); - has_meaningless_default_target && has_only_empty_targets && has_only_empty_conditional + has_meaningless_default_target && has_only_empty_conditional } } @@ -710,27 +717,6 @@ impl Hash for ProjectModel { } } -impl Hash for TargetSelector { - /// Custom hash implementation that uses discriminant values to keep the - /// hash as stable as possible when adding new enum variants. - fn hash(&self, state: &mut H) { - match self { - TargetSelector::Unix => 0u8.hash(state), - TargetSelector::Linux => 1u8.hash(state), - TargetSelector::Win => 2u8.hash(state), - TargetSelector::MacOs => 3u8.hash(state), - TargetSelector::Subdir(s) => { - 4u8.hash(state); - s.hash(state); - } - TargetSelector::Platform(p) => { - 5u8.hash(state); - p.hash(state); - } - } - } -} - impl Hash for Targets { /// Custom hash implementation using StableHashBuilder to ensure different /// field configurations produce different hashes while maintaining @@ -738,13 +724,11 @@ impl Hash for Targets { fn hash(&self, state: &mut H) { let Targets { default_target, - targets, conditional, } = self; StableHashBuilder::::new() .field("default_target", default_target) - .field("targets", targets) .field("conditional", conditional) .finish(state); } @@ -1006,20 +990,6 @@ mod tests { hasher.finish() } - #[test] - fn test_target_selector_roundtrip() { - // Platform families and concrete platforms round-trip through their - // string form. - for (text, selector) in [ - ("unix", TargetSelector::Unix), - ("linux", TargetSelector::Linux), - ("linux-64", TargetSelector::Subdir("linux-64".to_string())), - ] { - assert_eq!(selector.to_string(), text); - assert_eq!(text.parse::().unwrap(), selector); - } - } - #[test] fn test_conditional_expression_roundtrip() { // A conditional expression carries its bare inner text and displays it @@ -1057,8 +1027,7 @@ mod tests { // non-default/non-empty values project_model.targets = Some(Targets { default_target: None, - targets: Some(OrderMap::new()), - conditional: None, + conditional: Some(OrderMap::new()), }); let hash2 = calculate_hash(&project_model); @@ -1072,8 +1041,7 @@ mod tests { }; project_model.targets = Some(Targets { default_target: Some(empty_target), - targets: Some(OrderMap::new()), - conditional: None, + conditional: Some(OrderMap::new()), }); let hash3 = calculate_hash(&project_model); @@ -1136,8 +1104,7 @@ mod tests { }; project_model.targets = Some(Targets { default_target: Some(target_with_deps), - targets: Some(OrderMap::new()), - conditional: None, + conditional: Some(OrderMap::new()), }); let hash3 = calculate_hash(&project_model); @@ -1254,7 +1221,6 @@ mod tests { fn serialize_targets_v1_with_default_target() { let targets = Targets { default_target: Some(create_sample_target_v1()), - targets: None, conditional: None, }; @@ -1264,56 +1230,40 @@ mod tests { } #[test] - fn serialize_targets_v1_with_multiple_targets() { - let platform_strs = [ - "unix", - "win", - "macos", - "linux-64", - "linux-arm64", - "linux-ppc64le", - "osx-64", - "osx-arm64", - "win-64", - "win-arm64", - ]; + fn serialize_targets_v1_with_conditional_targets() { + let expressions = ["unix", "win", "osx", "host_platform == 'linux-64'"]; let targets = Targets { default_target: None, - targets: Some( - platform_strs + conditional: Some( + expressions .iter() - .map(|s| { - let selector = match *s { - "unix" => TargetSelector::Unix, - "win" => TargetSelector::Win, - "macos" => TargetSelector::MacOs, - other => TargetSelector::Platform(other.to_string()), - }; - (selector, create_sample_target_v1()) + .map(|expression| { + ( + ConditionalExpression::new(*expression), + create_sample_target_v1(), + ) }) .collect(), ), - conditional: None, }; let serialized = serde_json::to_string(&targets).unwrap(); - for platform in platform_strs { - assert!(serialized.contains(platform), "Missing: {platform}"); + for expression in expressions { + assert!(serialized.contains(expression), "Missing: {expression}"); } } #[test] fn deserialize_targets_v1_with_empty_fields() { let json = r#"{ - "defaultTarget": null, - "targets": null + "defaultTarget": null }"#; let deserialized: Targets = serde_json::from_str(json).unwrap(); assert!(deserialized.default_target.is_none()); - assert!(deserialized.targets.is_none()); + assert!(deserialized.conditional.is_none()); } #[test] @@ -1328,7 +1278,7 @@ mod tests { "buildDependencies": null, "runDependencies": null }, - "targets": { + "conditional": { "unix": { "hostDependencies": null, "buildDependencies": null, @@ -1339,12 +1289,11 @@ mod tests { let deserialized: Targets = serde_json::from_str(json).unwrap(); assert!(deserialized.default_target.is_some()); - assert!(deserialized.targets.is_some()); assert!( deserialized - .targets + .conditional .unwrap() - .contains_key(&TargetSelector::Unix) + .contains_key(&ConditionalExpression::new("unix")) ); } @@ -1459,13 +1408,11 @@ mod tests { // Test with TargetsV1 as well let targets1 = Targets { default_target: Some(target1), - targets: None, conditional: None, }; let targets2 = Targets { default_target: Some(target2), - targets: None, conditional: None, }; diff --git a/crates/pixi_manifest/src/manifests/package.rs b/crates/pixi_manifest/src/manifests/package.rs index 9d5f46a6ed..1e8e9d94a4 100644 --- a/crates/pixi_manifest/src/manifests/package.rs +++ b/crates/pixi_manifest/src/manifests/package.rs @@ -2,7 +2,7 @@ use indexmap::IndexMap; use pixi_build_types::ConditionalExpression; use crate::target::PackageTarget; -use crate::{PackageBuild, Targets, package::Package}; +use crate::{PackageBuild, package::Package}; /// Holds the parsed content of the package part of a pixi manifest. This /// describes the part related to the package only. @@ -14,17 +14,13 @@ pub struct PackageManifest { /// Information about the build system for the package pub build: PackageBuild, - /// Defines the platform-specific dependencies of the package. - /// - /// # Deprecated - /// - /// These come from the deprecated `[package.target.]` tables and - /// will be removed in a future version. Use [`Self::conditional_dependencies`] - /// (`if()` dependencies) instead. - pub targets: Targets, + /// The unconditional dependencies of the package. + pub dependencies: PackageTarget, /// Dependencies guarded by an `if()` conditional. These are not /// platform selectors; the expression is passed through to rattler-build, - /// which decides whether the dependencies apply. + /// which decides whether the dependencies apply. The deprecated + /// `[package.target.]` tables are lowered into entries of this + /// map at parse time. pub conditional_dependencies: IndexMap, } diff --git a/crates/pixi_manifest/src/toml/manifest.rs b/crates/pixi_manifest/src/toml/manifest.rs index de558b1e5d..2c8d5bfa74 100644 --- a/crates/pixi_manifest/src/toml/manifest.rs +++ b/crates/pixi_manifest/src/toml/manifest.rs @@ -1337,8 +1337,7 @@ mod test { "#, ); let host_deps = pkg - .targets - .default() + .dependencies .dependencies .get(&crate::SpecType::Host) .expect("host bucket"); diff --git a/crates/pixi_manifest/src/toml/package.rs b/crates/pixi_manifest/src/toml/package.rs index 80801dc5cc..f5e4e3c8e0 100644 --- a/crates/pixi_manifest/src/toml/package.rs +++ b/crates/pixi_manifest/src/toml/package.rs @@ -11,7 +11,7 @@ use toml_span::{DeserError, Span, Spanned, Value, de_helpers::TableHelper}; use url::Url; use crate::{ - PackageManifest, Preview, TargetSelector, Targets, TomlError, WithWarnings, + PackageManifest, Preview, TargetSelector, TomlError, WithWarnings, error::GenericError, package::Package, target::PackageTarget, @@ -419,7 +419,8 @@ impl TomlPackage { (host_conditional, |target| &mut target.host_dependencies), (build_conditional, |target| &mut target.build_dependencies), ]; - let mut conditional_targets: IndexMap = IndexMap::new(); + let mut conditional_targets: IndexMap = + IndexMap::new(); for (specs, field) in sections { for spec in specs { *field(conditional_targets.entry(spec.expression).or_default()) = @@ -443,31 +444,43 @@ impl TomlPackage { ); } - // `if(...)` conditionals are not platform selectors; they are kept - // separate and passed through to rattler-build, which evaluates the - // expression. - let mut conditional_dependencies: IndexMap = - IndexMap::new(); - for (expression, toml_target) in conditional_targets { - let target = toml_target.into_package_target(preview, &workspace_dependencies)?; - conditional_dependencies.insert(ConditionalExpression::new(expression), target); - } - - let mut targets: IndexMap, PackageTarget> = IndexMap::new(); - // The legacy `[package.target.PLATFORM]` syntax is deprecated but still - // supported. Emit a deprecation warning with a tailored suggestion for - // the equivalent conditional dependency tables. + // supported: each table lowers to the conditional dependency tables for + // the equivalent expression. Emit a deprecation warning that spells out + // that replacement. for (selector, toml_target) in self.target { + let expression = target_selector_expression(&selector.value); warnings.push( Deprecation::package_target( - package_target_replacement_help(&selector.value, &toml_target), + package_target_replacement_help(expression.as_str(), &toml_target), selector.span.clone(), ) .into(), ); + if conditional_targets.contains_key(&expression) { + return Err(GenericError::new(format!( + "duplicate condition: `[package.target.{}]` is equivalent to `\"if({expression})\"`", + selector.value + )) + .with_opt_span(selector.span) + .with_span_label("this target table lowers to the same condition") + .with_help(format!( + "Move the dependencies into the `\"if({expression})\"` tables and remove the `[package.target.{}]` table", + selector.value + )) + .into()); + } + conditional_targets.insert(expression, toml_target); + } + + // `if(...)` conditionals are not platform selectors; they are kept + // separate and passed through to rattler-build, which evaluates the + // expression. + let mut conditional_dependencies: IndexMap = + IndexMap::new(); + for (expression, toml_target) in conditional_targets { let target = toml_target.into_package_target(preview, &workspace_dependencies)?; - targets.insert(selector, target); + conditional_dependencies.insert(expression, target); } if let Some(WorkspaceInheritableField::Value(Spanned { @@ -599,30 +612,33 @@ impl TomlPackage { )?, }, build: build_result.value, - targets: Targets::from_default_and_user_defined(default_package_target, targets), + dependencies: default_package_target, conditional_dependencies, }) .with_warnings(warnings)) } } -/// Build the tailored `help` text suggesting the conditional dependency tables -/// that replace a deprecated `[package.target.SELECTOR]` entry. +/// The conditional expression a deprecated `[package.target.SELECTOR]` table +/// lowers to. /// /// Platform selectors map to `host_platform == ''` (the behavior the /// legacy syntax already had); family selectors (`unix`/`linux`/`win`/`osx`) -/// map to the bare rattler-build boolean. -fn package_target_replacement_help( - selector: &TargetSelector, - toml_target: &TomlPackageTarget, -) -> String { - let expression = match selector { +/// map to the bare rattler-build boolean of the same name. Note that the +/// `macos` alias maps to `osx`, the only spelling defined in rattler-build's +/// jinja context. +fn target_selector_expression(selector: &TargetSelector) -> ConditionalExpression { + match selector { TargetSelector::Platform(_) | TargetSelector::Subdir(_) => { - format!("host_platform == '{selector}'") + ConditionalExpression::new(format!("host_platform == '{selector}'")) } - other => other.to_string(), - }; + other => ConditionalExpression::new(other.to_string()), + } +} +/// Build the tailored `help` text suggesting the conditional dependency tables +/// that replace a deprecated `[package.target.SELECTOR]` entry. +fn package_target_replacement_help(expression: &str, toml_target: &TomlPackageTarget) -> String { let mut lines = Vec::new(); let mut push_line = |section: &str| { lines.push(format!(" [package.{section}.\"if({expression})\"]")); @@ -714,11 +730,11 @@ mod test { use insta::assert_snapshot; use pixi_spec::PixiSpec; use pixi_test_utils::format_parse_error; - use rattler_conda_types::{PackageName, Platform}; + use rattler_conda_types::PackageName; use tempfile::TempDir; use super::*; - use crate::{KnownPreviewFeature, SpecType, TargetSelector, toml::FromTomlStr}; + use crate::{KnownPreviewFeature, SpecType, toml::FromTomlStr}; use pixi_build_types::ConditionalExpression; /// Parses a manifest using only `Preview::default()` and asserts it succeeds. @@ -888,8 +904,7 @@ mod test { .value; let test_extra = manifest - .targets - .default() + .dependencies .extra_dependencies .get("test") .expect("test extra exists"); @@ -930,13 +945,13 @@ mod test { .value; let win_target = manifest - .targets - .for_target(&TargetSelector::Win) + .conditional_dependencies + .get(&ConditionalExpression::new("win")) .expect("win target exists"); assert!(win_target.extra_dependencies.contains_key("test")); assert!(win_target.extra_dependencies.contains_key("bench")); // Default target should NOT have the per-target extras. - assert!(manifest.targets.default().extra_dependencies.is_empty()); + assert!(manifest.dependencies.extra_dependencies.is_empty()); } #[test] @@ -1466,7 +1481,7 @@ mod test { "#; let manifest = parse_package(input); - let deps = &manifest.targets.default().dependencies; + let deps = &manifest.dependencies.dependencies; assert_single_version(deps, SpecType::Run, "run-dep", "==1.0"); assert_single_version(deps, SpecType::Host, "host-dep", "==2.0"); @@ -1498,17 +1513,17 @@ mod test { let manifest = parse_package(input); // Default target only has the shared run dep. - let default_deps = &manifest.targets.default().dependencies; + let default_deps = &manifest.dependencies.dependencies; assert_single_version(default_deps, SpecType::Run, "shared", "==1.0"); assert!( !default_deps.contains_key(&SpecType::RunConstraints), "run-constraints should not leak into default target", ); - // linux-64 target has its own deps and constraints. + // The linux-64 target lowers to the equivalent conditional expression. let linux = manifest - .targets - .for_target(&TargetSelector::Subdir(Platform::Linux64)) + .conditional_dependencies + .get(&ConditionalExpression::new("host_platform == 'linux-64'")) .expect("linux-64 target should exist"); assert_single_version(&linux.dependencies, SpecType::Run, "only-linux", "==2.0"); assert_single_version( @@ -1544,7 +1559,7 @@ mod test { // Plain entry stays on the default target. assert_single_version( - &manifest.targets.default().dependencies, + &manifest.dependencies.dependencies, SpecType::Run, "shared", "==1.0", @@ -1672,15 +1687,82 @@ mod test { "# ); - // The legacy target still works: the dependency lands on the platform target. + // The legacy target still works: it lowers to the equivalent + // conditional dependency entry. let linux = parsed .value - .targets - .for_target(&TargetSelector::Subdir(Platform::Linux64)) - .expect("linux-64 target should exist"); + .conditional_dependencies + .get(&ConditionalExpression::new("host_platform == 'linux-64'")) + .expect("linux-64 target should lower to a conditional entry"); assert_single_version(&linux.dependencies, SpecType::Build, "foo", "==1.0"); } + #[test] + fn test_package_target_collides_with_equivalent_conditional() { + // A deprecated target table and an explicit `if(...)` table that lower + // to the same expression are rejected; silently merging them would hide + // a half-finished migration. + let input = r#" + name = "pkg" + version = "1.0" + + [build] + backend = { name = "bla", version = "1.0" } + + [run-dependencies."if(host_platform == 'linux-64')"] + foo = "==1.0" + + [target.linux-64.build-dependencies] + bar = "==2.0" + "#; + + let parse_error = TomlPackage::from_toml_str(input) + .and_then(|w| { + w.into_manifest( + WorkspacePackageProperties::default(), + PackageDefaults::default(), + &Preview::default(), + Path::new(""), + ) + }) + .unwrap_err(); + assert_snapshot!(format_parse_error(input, parse_error), @r#" + × duplicate condition: `[package.target.linux-64]` is equivalent to `"if(host_platform == 'linux-64')"` + ╭─[pixi.toml:11:17] + 10 │ + 11 │ [target.linux-64.build-dependencies] + · ────┬─── + · ╰── this target table lowers to the same condition + 12 │ bar = "==2.0" + ╰──── + help: Move the dependencies into the `"if(host_platform == 'linux-64')"` tables and remove the `[package.target.linux-64]` table + "#); + } + + #[test] + fn test_package_target_osx_lowers_to_osx_expression() { + // `[package.target.osx]` must lower to the rattler-build family boolean + // `osx`; `macos` is not defined in rattler-build's jinja context and + // would silently evaluate to false. + let input = r#" + name = "pkg" + version = "1.0" + + [build] + backend = { name = "bla", version = "1.0" } + + [target.osx.run-dependencies] + foo = "==1.0" + "#; + + let manifest = parse_package(input); + let target = manifest + .conditional_dependencies + .get(&ConditionalExpression::new("osx")) + .expect("the osx target must lower to the `osx` conditional expression"); + assert_single_version(&target.dependencies, SpecType::Run, "foo", "==1.0"); + } + #[test] fn test_run_constraints_source_spec_requires_pixi_build() { // Source specs in [package.run-constraints] must be rejected unless the diff --git a/crates/pixi_manifest/src/utils/inheritable_package_map.rs b/crates/pixi_manifest/src/utils/inheritable_package_map.rs index 23be547daf..c63b0694fd 100644 --- a/crates/pixi_manifest/src/utils/inheritable_package_map.rs +++ b/crates/pixi_manifest/src/utils/inheritable_package_map.rs @@ -2,6 +2,7 @@ use std::{ops::Range, str::FromStr}; use indexmap::IndexMap; use itertools::Itertools; +use pixi_build_types::ConditionalExpression; use pixi_spec::{PixiSpec, TomlSpec}; use rattler_conda_types::PackageName; use toml_span::{ @@ -217,7 +218,7 @@ impl<'de> toml_span::Deserialize<'de> for InheritablePackageMap { #[derive(Debug)] pub struct ConditionalSpecs { /// The bare inner expression, without the `if(...)` wrapper. - pub expression: String, + pub expression: ConditionalExpression, /// Span of the sub-table value. pub value_span: Range, /// The dependencies declared under this condition. @@ -264,7 +265,7 @@ impl<'de> toml_span::Deserialize<'de> for ConditionalInheritablePackageMap { let value_span = entry_value.span; match InheritablePackageMap::deserialize(&mut entry_value) { Ok(specs) => conditional.push(ConditionalSpecs { - expression: expression.to_string(), + expression: ConditionalExpression::new(expression), value_span: value_span.start..value_span.end, specs, }), diff --git a/docs/build/workspace_dependencies.md b/docs/build/workspace_dependencies.md index fee7c73cd5..4589041fec 100644 --- a/docs/build/workspace_dependencies.md +++ b/docs/build/workspace_dependencies.md @@ -11,7 +11,7 @@ of dependency specs that packages opt into per entry. `[workspace.dependencies]` is part of the `pixi-build` preview and applies **only to package dependencies** (`[package.*-dependencies]`, `[package.run-constraints]` and `[package.build.backend]`, including their - `[package.target..*]` variants). + `"if()"` conditional sub-tables). The workspace-level environment tables (`[dependencies]`, `[host-dependencies]`, `[build-dependencies]`, `[pypi-dependencies]`, `[constraints]`) do **not** participate; entries there continue to be @@ -71,7 +71,7 @@ The inheritance marker is recognized in every package dependency table: - `[package.build-dependencies]` - `[package.run-dependencies]` - `[package.run-constraints]` -- `[package.target..*]` variants of the above +- `"if()"` conditional sub-tables of the above - `[package.build.backend]` (the lookup key is the backend's `name`) ## Layering package overrides diff --git a/schema/pixi_build_api.json b/schema/pixi_build_api.json index 5b8713f081..e7bd4b4e73 100644 --- a/schema/pixi_build_api.json +++ b/schema/pixi_build_api.json @@ -127,7 +127,7 @@ }, "$defs": { "Targets": { - "description": "A collect of targets including a default target.", + "description": "A collect of targets including a default target.\n\nPlatform-specific dependencies are carried exclusively as conditional\n`if()` entries; the frontend lowers the deprecated\n`[package.target.]` tables to the equivalent expression before\nsending the project model.", "type": "object", "properties": { "defaultTarget": { @@ -140,16 +140,6 @@ } ] }, - "targets": { - "description": "Platform-specific targets.\n\n# Deprecated\n\nThese correspond to the deprecated `[package.target.]` tables\nand will be removed in a future version. Use [`Targets::conditional`]\n(`if()` dependencies) instead.\n\nWe use an [`OrderMap`] to preserve the order in which the items where\ndefined in the manifest.", - "type": [ - "object", - "null" - ], - "additionalProperties": { - "$ref": "#/$defs/Target" - } - }, "conditional": { "description": "Conditional `if()` dependencies. The expression is passed\nthrough to rattler-build, which evaluates it; pixi does not. Keyed by the\nbare inner expression without the `if(...)` wrapper.", "type": [