feat: keep target_platform concrete for noarch packages and add build.subdir - #2663
Open
baszalmstra wants to merge 2 commits into
Open
feat: keep target_platform concrete for noarch packages and add build.subdir#2663baszalmstra wants to merge 2 commits into
target_platform concrete for noarch packages and add build.subdir#2663baszalmstra wants to merge 2 commits into
Conversation
….subdir For noarch outputs target_platform was replaced with noarch in the variant, the jinja context, and the build script environment. Keep it concrete (matching conda-build) and derive the package subdir separately via Output::subdir(). The hash input still uses noarch for noarch packages, so build strings are unchanged. Also port conda-build's output-level 'target' key as 'build.subdir' to override the subdir a package is stamped with.
baszalmstra
commented
Jul 16, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
For noarch outputs,
target_platformused to be replaced withnoarcheverywhere: in the variant, the jinja context, and thetarget_platformenvironment variable in the build script. This does not match conda-build, wheretarget_platformkeeps the requested platform and only the subdir of the resulting package becomesnoarch(see the Discord discussion with @isuruf).With this PR:
The package is still stamped as
noarchand placed in thenoarchfolder.Build strings do not change. The hash input still replaces
target_platformwithnoarchfor noarch packages (now insideHashInput::from_variant), so hashes remain platform independent and byte-identical to what rattler-build produces today.test_build_string_py_noarchandtest_noarch_variantsassert the exact same build strings as before, and a new test asserts that noarch hashes are identical across target platforms.Implementation
BuildConfiguration::target_platformis now always a concrete platform. The subdir of a package is derived instead:Output::subdir()returnsbuild.subdirif set,noarchfor noarch packages, and the target platform otherwise.target_platform == NoArchas an "is this noarch?" check (relinking, linking checks, the Windows symlink check, run-export selection,--noarch-build-platform, native test skipping) now usesOutput::subdir(), so behavior there is unchanged.subdir/arch/platform, the output folder, prefix placeholder detection, file mapping, and package content tests also go throughOutput::subdir()and behave as before.Visible behavior changes for noarch builds besides
target_platformitself:CONDA_BUILD_CROSS_COMPILATIONis now0when host and build platform match. It was always1for noarch becausenoarch != build_platform.MACOSX_DEPLOYMENT_TARGET) are now set in the build script becauseos_varsreceives a concrete platform. This is what made the compiler activation workaround intzdata-feedstocknecessary before.ARCHis unchanged (it was already derived from the host platform).build.subdirConda-build has an output-level
targetkey that only controls the subdir the package is stamped with. This PR ports it asbuild.subdir(renamed per @isuruf's suggestion):It only affects index.json and the output folder. It does not change
target_platformor dependency resolution, and it cannot be combined withnoarch. The key supports jinja templates and inherits from the top-level build section in multi-output recipes, likenoarch.Open questions
SUBDIRin the build script still refers to the package subdir (noarch), while conda-build populates it fromhost_subdir(a concrete platform). Should we follow conda-build here as well?target_platformas the package subdir, because at test time the value is derived from the package (index.json /hash_input.json) rather than from the build.Compatibility with existing conda-forge recipes
Assessment of the impact on conda-forge recipes
Summary
Changing rattler-build so that
target_platformremains the requested platform for noarch outputs appears to have a small compatibility risk for conda-forge recipes.The search did not find a current
recipe.yamlthat clearly and intentionally relies ontarget_platform=noarch. The strongest ecosystem evidence points in the opposite direction:tzdata-feedstockexplicitly works around rattler-build settingtarget_platformtonoarch.One recipe,
m2w64-sysroot-feedstock, has a build script whose behavior can change depending on the value. It should be included in regression testing, although its normal conda-forge noarch build is unlikely to change.Behavior in conda-build
Given a noarch recipe built with
target_platform=win-64, conda-build keeps the requested target platform visible to the build script:Running:
conda-build recipe --variants "{target_platform: win-64}"prints:
The resulting package is nevertheless placed in the
noarchsubdirectory.Conda-build therefore distinguishes between:
target_platform;SUBDIRis populated fromconfig.host_subdir, not from the final package subdirectory (source). When package metadata is created, conda-build explicitly sets the package subdirectory tonoarchwhenmetadata.noarchis set (source).Conda-build also supports an output-level
targetkey:This is assigned to
output_metadata.config.target_subdir(source) and controls the final package subdirectory (source). It remains separate fromtarget_platform.Conda-forge search
The search focused on current
recipe.yamlfiles because those are the recipes using the v1 recipe format and rattler-build. It covered:target_platformandnoarch;${{ target_platform }}interpolation in noarch outputs;build_platform != target_platformselectors in noarch outputs;target_platform;target_platformenvironment variable;No current
recipe.yamlwas found containing a literal comparison such as:GitHub code search indexes default branches and can lag behind recent changes, so this is not a guarantee that no such recipe exists. It does, however, cover the most direct ways a recipe could intentionally depend on the behavior.
Confirmed workaround:
tzdata-feedstocktzdata-feedstockexplicitly overridestarget_platform:This is not a dependency on the current behavior. It documents a concrete problem caused by it: compiler activation does not run when
target_platform=noarch.Keeping
target_platformconcrete would make this workaround unnecessary and align rattler-build with conda-build.Potentially behavior-sensitive recipe:
m2w64-sysroot-feedstockm2w64-sysroot-feedstockdefines a noarch output usingcopy.sh:The corresponding
copy.shcontains:With the current rattler-build behavior, the condition is true because
target_platform=noarch. With a concretetarget_platform, it would be false when the requested platform iswin-64.This deserves regression coverage. However, the noarch package is normally produced in a Linux conda-forge job. In that job the concrete target is
linux-64, so the condition remains true and the resulting artifact should be unchanged.References that do not rely on
target_platform=noarchSeveral noarch outputs use expressions such as:
Examples include:
mnelab-feedstocklightgbm-feedstockconda-global-feedstockpybind11-feedstockpyb2d3-feedstockgz-msgs-feedstockThese are not evidence of reliance on
target_platform=noarch. Recipe expressions are evaluated using the requested platform before rattler-build assigns the effective noarch output platform. If these expressions sawnoarch, some would attempt to depend on a package such ascross-python_noarch, which is clearly not their intent.Other recipes explicitly require selectors to see the requested platform:
stim-split-feedstockskips its noarch output unlesstarget_platformislinux-64.backports.zstd-feedstockusestarget_platform == "linux-64"when selecting its single noarch build.These recipes support preserving the requested target platform rather than replacing it with
noarch.Risk assessment
The direct recipe compatibility risk appears low:
target_platform=noarch;The less visible risk is indirect behavior in activation scripts supplied by build dependencies. Those scripts can inspect
target_platformwithout the recipe mentioning it. Thetzdataworkaround demonstrates that this already causes incompatibilities when the value isnoarch.The intended invariant: