# The recipe spec

Rattler-Build implements a new recipe spec, different from the traditional
"`meta.yaml`" file used in `conda-build`. A recipe has to be stored as a
`recipe.yaml` file.

## History

A discussion was started on what a new recipe spec could or should look like.
The fragments of this discussion can be found [here](https://github.com/mamba-org/conda-specs/blob/master/proposed_specs/recipe.md).

The reason for a new spec are:

- make it easier to parse (i.e. "pure YAML"); `conda-build` uses a mix of comments
  and Jinja to achieve a great deal of flexibility, but it's hard to parse the
  recipe with a computer
- iron out some inconsistencies around multiple outputs (`build` vs. `build/script`
  and more)
- remove any need for recursive parsing & solving
- finally, the initial implementation in `boa` relied on `conda-build`;
  Rattler-Build removes any dependency on Python or `conda-build` and
  reimplements everything in Rust

## Major differences from `conda-build`

- recipe filename is `recipe.yaml`, not `meta.yaml`
- outputs have less complicated behavior, keys are same as top-level recipe
  (e.g. `build/script`, not just `script` and `package/name`, not just `name`)
- no implicit meta-packages in outputs
- no full Jinja2 support: no conditional or `{% set ...` support, only string
  interpolation; variables can be set in the toplevel "context" which is valid
  YAML
- Jinja string interpolation needs to be preceded by a dollar sign at the
  beginning of a string, e.g. `- ${{ version }}` in order for it to be valid
  YAML
- selectors use a YAML dictionary style (vs. comments in conda-build). Instead
  of `- somepkg  #[osx]` we use:
  ```yaml
  if: osx
  then:
    - somepkg
  ```

- `skip` instruction uses a list of skip conditions and not the selector syntax
  from `conda-build` (e.g. `skip: ["osx", "win and py37"]`)

## Spec

The recipe spec has the following parts:

- [x] `schema_version`: optional integer identifying the recipe schema
  version. Only `1` is currently accepted; omit this field to default to
  schema version 1.
- [x] `context`: to set up variables that can later be used in Jinja string
  interpolation
- [x] `package`: defines name, version etc. of the top-level package
- [x] `source`: points to the sources that need to be downloaded in order to
  build the recipe
- [x] `build`: defines how to build the recipe and what build number to use
- [x] `requirements`: defines requirements of the top-level package
- [x] `tests`: defines tests for the top-level package
- [x] `outputs`: a recipe can have multiple outputs. Each output can and should
  have a `package`, `requirements` and `test` section
- [x] `about`: package metadata such as homepage, license and description
- [x] `extra`: free-form metadata that rattler-build does not interpret

## Spec reference

The spec is also made available through a JSON Schema (which is used for
validation).<br/>
The schema (and `pydantic` source file) can be found in this repository:
[`recipe-format`](https://github.com/prefix-dev/recipe-format)


See more in the [automatic linting](../automatic_linting.md) chapter.

<!--
Quick start (from conda-build)
------------------------------

You can use `boa convert meta.yaml` to convert an existing recipe from conda-build syntax to boa. The command will output the new recipe to stdout. To quickly save the result, you can use `boa convert meta.yaml > recipe.yaml` and run `boa build .`. Please note that the conversion process is working fine only for "simple" recipes and there will be some needed manual work to convert complex recipes.

-->

Examples
--------

```yaml title="recipe.yaml"
--8<-- "docs/snippets/recipes/imagesize.yaml"
```


### Package section

Specifies package information.

```yaml
package:
  name: bsdiff4
  version: "2.1.4"
```

- **name**: The lower case name of the package. It may contain "`-`", but no
  spaces.
- **version**: The version number of the package. Use the PEP-386 verlib
  conventions. Cannot contain "`-`". YAML interprets version numbers such as 1.0
  as floats, meaning that 0.10 will be the same as 0.1. To avoid this, put the
  version number in quotes so that it is interpreted as a string.


### Source section

Specifies where the source code of the package is coming from. The source may
come from a tarball file, `git`, `hg`, or `svn`. It may be a local path and it may
contain patches.


#### Source from tarball or `zip` archive

```yaml
source:
  url: https://pypi.python.org/packages/source/b/bsdiff4/bsdiff4-1.1.4.tar.gz
  md5: 29f6089290505fc1a852e176bd276c43
  sha256: 5a022ff4c1d1de87232b1c70bde50afbb98212fd246be4a867d8737173cf1f8f
```

A source may be verified with `sha256` and/or `md5`; `sha1` is not supported.

If an extracted archive contains only 1 folder at its top level, its contents
will be moved 1 level up, so that the extracted package contents sit in the root
of the work folder.

An empty `sha256` or `md5` (e.g. `sha256: ""`) is accepted as an all-zeros
placeholder (`0000...0000`). This is handy while scaffolding a recipe before the
real checksum is known: the build still downloads the source and reports the
actual checksum in the resulting mismatch, which you can then paste back into
the recipe.

##### Supported archive formats

When the URL points to one of the archive formats listed below, the file is
downloaded to the source cache and automatically extracted into the work
directory. Detection is based on the file extension only.

- **Tar archives**: `.tar`, `.tar.gz` (`.tgz`, `.taz`), `.tar.bz2` (`.tbz`,
  `.tbz2`, `.tz2`), `.tar.xz` (`.txz`), `.tar.lzma` (`.tlz`), `.tar.zst`
  (`.tzst`), `.tar.Z` (`.taZ`), `.tar.lz`, `.tar.lzo`
- **Zip archives**: `.zip`
- **7-Zip archives**: `.7z`

Files with any other extension (for example `.rpm`, `.deb`, `.dmg`,
`.AppImage`, single binaries, …) are downloaded and placed in the work
directory as-is, without extraction. If you need to unpack such a file, install
the appropriate tooling as a `build` requirement and extract it from your
build script. The same applies when [`file_name`](#specifying-a-file-name) is
set on an archive source — extraction is then disabled for that source.

##### Specifying a file name

For URL and local path sources, `file_name` renames the downloaded file in the work directory.
The primary use case is giving a clean name to pre-built binaries whose URL path segments are not
descriptive:

```yaml
source:
  url: https://github.com/owner/project/releases/download/v1.0.0/project-v1.0.0-linux-amd64
  sha256: <sha256>
  file_name: project  # rename to a clean, platform-independent name
```

!!! warning "Setting `file_name` disables automatic archive extraction"
    When `file_name` is set on an archive source (`.tar.gz`, `.zip`, `.7z`, etc.), the archive is
    **not extracted** — it is placed in the work directory as-is under the given name.
    This is true even if `file_name` is set to the same name the archive would have had by default:

    ```yaml
    source:
      url: https://pypi.python.org/packages/source/b/bsdiff4/bsdiff4-1.1.4.tar.gz
      sha256: 5a022ff4c1d1de87232b1c70bde50afbb98212fd246be4a867d8737173cf1f8f
      # The archive is NOT extracted — it is placed as bsdiff4-1.1.4.tar.gz in the work directory
      file_name: bsdiff4-1.1.4.tar.gz
    ```

    To download an archive and have it extracted automatically (the default behaviour), omit
    `file_name`:

    ```yaml
    source:
      url: https://pypi.python.org/packages/source/b/bsdiff4/bsdiff4-1.1.4.tar.gz
      sha256: 5a022ff4c1d1de87232b1c70bde50afbb98212fd246be4a867d8737173cf1f8f
      # file_name is not set — the archive is extracted into the work directory
    ```

#### Source from `git`

```yaml
source:
  git: https://github.com/ilanschnell/bsdiff4.git
  # branch: master # note: defaults to fetching the repo's default branch
```

You can use `rev` to pin the commit version directly:

```yaml
source:
  git: https://github.com/ilanschnell/bsdiff4.git
  rev: "50a1f7ed6c168eb0815d424cba2df62790f168f0"
```

Or you can use the `tag`:

```yaml
source:
  git: https://github.com/ilanschnell/bsdiff4.git
  tag: "1.1.4"
```

`git` can also be a relative path to the recipe directory:

```yaml
source:
  git: ../../bsdiff4/.git
  tag: "1.1.4"
```

Furthermore, if you want to fetch just the current "`HEAD`" (this may result in
non-deterministic builds), then you can use `depth`.

```yaml
source:
  git: https://github.com/ilanschnell/bsdiff4.git
  depth: 1 # note: the behaviour defaults to -1
```

Note: `tag` or `rev` may not be available within commit depth range, hence we don't
allow using `rev` or the `tag` and `depth` of them together if not set to `-1`.

```yaml
source:
  git: https://github.com/ilanschnell/bsdiff4.git
  tag: "1.1.4"
  depth: 1 # error: use of `depth` with `rev` is invalid, they are mutually exclusive
```

When you want to use `git-lfs`, you need to set `lfs: true`. This will also pull
the `lfs` files from the repository.

```yaml
source:
  git: ../../bsdiff4/.git
  tag: "1.1.4"
  lfs: true # note: defaults to false
```

By default, Rattler-Build will recursively initialize and update all git
submodules. For repositories with large or numerous submodules that aren't needed
for the build, you can disable this by setting `submodules: false`:

```yaml
source:
  git: https://github.com/riscv-collab/riscv-gnu-toolchain.git
  tag: "2024.09.03"
  submodules: false # note: defaults to true
```

If you need only specific submodules, set `submodules: false` and initialize them
manually in your build script.

##### Verifying commit hash with `expected_commit`

!!! note
    This feature is only available with `--experimental` as it was not part of the standardization yet.


For security and reproducibility, you can specify an `expected_commit` field to verify that the checked out commit matches the expected SHA hash. This is useful to detect if a tag or branch has been moved to point to a different commit:

```yaml
source:
  git: https://github.com/ilanschnell/bsdiff4.git
  tag: "1.1.4"
  expected_commit: 50a1f7ed6c168eb0815d424cba2df62790f168f0
```

If the actual commit does not match the expected commit, the build will fail with an error message indicating the mismatch. This feature is inspired by [Wolfi/Melange](https://github.com/wolfi-dev/wolfi-os) and provides an additional layer of security for your builds.

#### Source from a local path

If the path is relative, it is taken relative to the recipe directory. The
source is copied to the work directory before building.

```yaml
  source:
    path: ../src
    use_gitignore: false # note: defaults to true
```

By default, all files in the local path that are ignored by `git` are also ignored
by Rattler-Build. You can disable this behavior by setting `use_gitignore` to
`false`.

#### Patches

Patches may optionally be applied to the source.

```yaml
  source:
    #[source information here]
    patches:
      - my.patch # the patch file is expected to be found in the recipe
```

<!-- boa (conda-build) automatically determines the patch strip level. -->

Patch paths are resolved relative to the recipe directory. They may also refer
to a restricted set of build-time directory variables that are only known once
the build has started:

- `${{ SRC_DIR }}` – the source working directory
- `${{ RECIPE_DIR }}` – the recipe directory
- `${{ BUILD_DIR }}` – the top-level build directory

This is useful when a patch ships inside another source. Because sources are
fetched in order into the shared `SRC_DIR`, a later source can apply a patch
that was extracted from an earlier one:

```yaml
source:
  - url: https://example.com/tool-{{ version }}.tar.gz  # ships patches under src/
    sha256: "..."
  - url: https://example.com/lib-{{ version }}.tar.gz
    sha256: "..."
    target_directory: lib_src
    patches:
      - ${{ SRC_DIR }}/src/patches/0001-fix.patch
```

Only the variables listed above are allowed in `patches`; any other variable
is treated as undefined and produces an error.

#### Destination path

Within Rattler-Build's work directory, you may specify a particular folder to
place the source into. Rattler-Build will always drop you into the same folder
(`[build folder]/work`), but it's up to you whether you want your source extracted
into that folder, or nested deeper. This feature is particularly useful when dealing
with multiple sources, but can apply to recipes with single sources as well.

```yaml
source:
  #[source information here]
  target_directory: my-destination/folder
```

#### Attestation verification (experimental)

!!! note
    This feature requires the `--experimental` flag.

For URL sources, you can specify an `attestation` block to verify that the downloaded archive
was built by an expected publisher using [Sigstore](https://sigstore.dev) attestations.

```yaml
source:
  url: https://files.pythonhosted.org/packages/.../flask-3.1.1.tar.gz
  sha256: "..."
  attestation:
    publishers:
      - github:pallets/flask
```

The attestation config has the following fields:

- **`publishers`** - A list of publisher identities in `github:owner/repo` format. At least one
  publisher must match for verification to succeed.
- **`bundle_url`** (optional) - URL to the Sigstore bundle file. For PyPI sources, this is
  automatically derived from the PyPI attestation API. For GitHub releases, use the pattern
  `https://github.com/{owner}/{repo}/releases/download/{tag}/{filename}.sigstore.json`.

See the [Sigstore source attestation documentation](../sigstore.md#source-attestation-verification)
for more details and examples.

#### Source from multiple sources

Some software is most easily built by aggregating several pieces.

The syntax is a list of source dictionaries. Each member of this list follows
the same rules as the single source. All features for each member are supported.

Example:

```yaml
source:
  - url: https://package1.com/a.tar.bz2
    target_directory: stuff
  - url: https://package1.com/b.tar.bz2
    target_directory: stuff
  - git: https://github.com/mamba-org/boa
    target_directory: boa
```

Here, the two URL tarballs will go into one folder, and the `git` repo is checked
out into its own space. `git` will not clone into a non-empty folder.

### Include only certain files from source

While you can specify only the files you need from a source, `source.filter` gives you the option to filter with globs instead.

```yaml title="recipe.yaml"
source:
  path: /path/to/source
  filter:
    - list
    - of
    - globs
```

Glob patterns throughout the recipe file can also use a flexible `include` /
`exclude` pair, such as:

```yaml title="recipe.yaml"
source:
  path: /path/to/source
  filter:
    include:
      - include/**/*.h
    exclude:
      - include/**/private.h
```

The `filter` field is available for `path`, `url`, and `git` sources. It is
applied to the files that are copied into the work directory — the copied tree
for directory `path` sources, the contents of the extracted archive for `url`
sources (and `path` sources pointing to an archive), and the checked-out tree
for `git` sources. This is useful for trimming large sources down to the parts
you actually need to build:

```yaml title="recipe.yaml"
source:
  - url: https://github.com/llvm/llvm-project/archive/refs/tags/llvmorg-${{ version }}.tar.gz
    sha256: ad18b70e287954c3d62bc7e0b86e7b7af2adf87bcfce21c15fe717f101d7aace
    filter:
      # we don't want to accidentally build more than clang here
      - cmake/*
      - clang/*
      - clang-tools-extra/*
```

```yaml title="recipe.yaml"
source:
  url: https://github.com/pytorch/pytorch/releases/download/v${{ version }}/pytorch-v${{ version }}.tar.gz
  sha256: 757145cfd55c7c8c01f58c959f76230641cc67fdd1d8b6a130f93ad1bc116f5f
  filter:
    exclude:
      # ensure we use our own fmt
      - third_party/fmt/*
```

## Build section

Specifies build information.

Each field that expects a path can also handle a glob pattern. The matching is
performed from the top of the build environment, so to match files inside your
project you can use a pattern similar to the following one:
`"**/myproject/**/*.txt"`. This pattern will match any `.txt` file found in your
project. Quotation marks (`""`) are required for patterns that start with a `*`.

Recursive globbing using `**` is also supported.

#### Build number and string

The build number should be incremented for new builds of the same version. The
number defaults to `0`. The build string cannot contain "`-`". The string defaults
to the default Rattler-Build build string plus the build number.

```yaml
build:
  number: 1
  string: abc
```

#### Dynamic linking

This section contains settings for the shared libraries and executables on
Linux and macOS.

```yaml
build:
  dynamic_linking:
    rpaths:
      - lib/
    binary_relocation: true
    rpath_allowlist:
      - /usr/lib/**
    missing_dso_allowlist:
      - "**/libcuda.so*"
    overdepending_behavior: error
    overlinking_behavior: error
```

Fields (all optional):

- **`rpaths`** - List of RPATH entries to set on ELF and Mach-O binaries.
  Defaults to `["lib/"]`.
- **`binary_relocation`** - Controls which binaries get their prefixes
  rewritten during installation. Accepts `true` (all binaries, default),
  `false` (none) or a list of glob patterns to include.
- **`rpath_allowlist`** - Glob patterns of RPATH entries that may point
  outside the package prefix without triggering an overlinking warning.
- **`missing_dso_allowlist`** - Glob patterns of dynamic libraries that are
  allowed to be missing from the host environment without failing the
  overlinking check.
- **`overdepending_behavior`** - What to do when a declared dependency is not
  actually linked. One of `ignore` or `error`.
- **`overlinking_behavior`** - What to do when a binary links against a
  library that is not a declared dependency. One of `ignore` or `error`.

#### Package variant flags (V3, beta)

!!! warning "Beta — opt in with `--v3`"
    This field is part of the V3 repodata revision and is only accepted when
    Rattler-Build is invoked with `--v3`. Without the flag, recipes that set
    `build.flags` fail to evaluate. See [V3 packages](../v3.md) for
    background and a complete description.

Variant flags are short lowercase tags that describe a *variant* of the
package (e.g. `cuda`, `blas:openblas`). They are written into the package's
`index.json` and can be matched downstream with the V3 `flags=[…]`
`MatchSpec` key.

```yaml
build:
  flags:
    - cuda
    - blas:openblas
```

A flag must match the regex `^[a-z0-9_]+(:[a-z0-9_]+)?$` — lowercase ASCII,
digits and underscores, optionally with a single `:`-separated suffix. The
list is conditional and templated like other recipe lists, and any flag that
depends on a Jinja variable participates in variant hashing:

```yaml
build:
  flags:
    - if: cuda_compiler_version != "None"
      then: cuda
    - blas:${{ blas_impl }}
```

### Script

By default, Rattler-Build uses a `build.sh` file on Unix (macOS and Linux) and a
`build.bat` file on Windows, if they exist in the same folder as the `recipe.yaml`
file. With the script parameter you can either supply a different filename or
write out short build scripts. You may need to use selectors to use different
scripts for different platforms.

```yaml
build:
  # A very simple build script
  script: pip install .

  # The build script can also be a list
  script:
    - pip install .
    - echo "hello world"
    - if: unix
      then:
        - echo "unix"
```

#### Script object form

For anything beyond a bare command list, `script` can be written as a mapping
with the following fields (all optional):

- **`content`** - Inline commands to execute. Equivalent to passing a string
  or list directly as `script:`. Accepts a string, a list of strings, or
  `if`/`then`/`else` conditionals. Mutually exclusive with `file`.
- **`file`** - Path to an external script file (relative to the recipe
  directory). If the filename has no extension, the platform-appropriate
  extension is appended (`.sh` on Unix, `.bat` on Windows). Mutually exclusive
  with `content`.
- **`env`** - Mapping of environment variables to set for the script. Values
  can be hard-coded strings or Jinja expressions, and `env.get(...)` can be
  used to forward variables from the outer environment with an optional
  default.
- **`secrets`** - List of environment variable names whose values should be
  forwarded from the outer environment but masked in logs and stripped from
  the rendered recipe. The variables must already be set in the environment
  running `rattler-build`.
- **`interpreter`** - Explicit interpreter to run `content` with. Supported
  values are `bash` (default on Unix), `cmd` (Windows `cmd.exe`),
  `powershell`, `nu` (nushell), `brush`, `python`, `perl`, `rscript`, `ruby`
  and `node`/`nodejs`. When unset, the interpreter is auto-detected from the
  script's file extension (`.sh`/`.bash`, `.bat`/`.cmd`, `.ps1`, `.nu`, `.py`,
  `.pl`, `.r`, `.rb`, `.js`).
- **`cwd`** - Working directory for the script. Relative paths are resolved
  against the host prefix (`$PREFIX` / `%PREFIX%`). Defaults to the build work
  directory.

!!! note "Where interpreters come from"

    Every build and test script is launched through a native shell wrapper
    (`bash` on Unix, `cmd.exe` on Windows) that activates the build/host
    prefixes and then invokes the chosen interpreter as a command.

    An interpreter that runs the build script is a build-time tool, so add it to
    `requirements.build` (for example `interpreter: nu` → `nushell`,
    `interpreter: rscript` → `r-base`, `interpreter: node` → `nodejs`). It is
    resolved from the activated environment in the same order the `PATH` would:
    the **build** prefix, then the **host** prefix, and for most interpreters the
    system `PATH` as a last resort. So a `host` dependency is also found, but
    `build` is the correct place; relying on a system copy works but makes builds
    non-reproducible. When the build and host environments are merged
    (`build.merge_build_and_host_envs`), that single environment is used.

    Two interpreters are resolved differently:
     - `bash`/`cmd` (and `powershell` on Windows) may be taken from the
       system `PATH` on their native platform.
     - `brush` is resolved **only** from the build environment (not the host
       prefix or the system `PATH`), so it must be in `requirements.build`.

```yaml title="recipe.yaml"
build:
  script:
    content:
      - python -m pip install . -vv --no-deps --no-build-isolation
    env:
      # Hard-coded value
      USE_SYSTEM_DEPS: "on"
      # Forwarded from the outer environment with a default
      CMAKE_ARGS: ${{ env.get("CMAKE_ARGS", default="") }}
    secrets:
      # Masked in logs; must be exported in the outer environment
      - GITHUB_TOKEN
    interpreter: bash
```

Using an external script file:

```yaml title="recipe.yaml"
build:
  script:
    file: build/install.py
    interpreter: python
    env:
      USE_SYSTEM_DEPS: "on"

requirements:
  build:
    # `python` is the interpreter, so it must be available in the build env
    - python
```

Selecting `nushell` with the required build dependency:

```yaml title="recipe.yaml"
build:
  script:
    interpreter: nu
    content: |
      echo "Hello from nushell!"

requirements:
  build:
    - nushell
```

#### Build steps (experimental)

`build.steps` is an experimental alternative to `build.script` and requires
`--experimental`. `script` and `steps` are mutually exclusive, including
`steps: []`.

Each step is a scoped build-wrapper section. Step-local `env` values and `cwd`
changes apply only to that step. A step supports:

- **`run`** - Required inline command, multiline string, or list of commands.
- **`if`** - Optional Jinja selector expression evaluated before the step runs. Do not wrap expressions in `${{ }}`.
- **`interpreter`** - Optional interpreter override for this step.
- **`cwd`** - Optional working directory for this step. Relative paths are
  resolved against the host prefix (`$PREFIX` / `%PREFIX%`).
- **`env`** - Optional environment variables scoped to this step.

```yaml title="recipe.yaml"
build:
  steps:
    - if: unix
      run:
        - mkdir -p "$PREFIX/bin"
        - cp "$RECIPE_DIR/tool" "$PREFIX/bin/tool"

    - run: python -m pip install . --no-deps
      env:
        SETUPTOOLS_SCM_PRETEND_VERSION: ${{ version }}
```

!!! warning "Windows multiline steps"
    On Windows, a multiline `run: |` block is emitted as one command-list item.
    Fail-fast guards are inserted between list items, not between the physical
    lines inside one multiline scalar.

See [Build script](../build_script.md) for more examples and the full
behaviour of environment variables, secrets, and interpreters.

### Skipping builds

Lists conditions under which Rattler-Build should skip the build of this recipe.
Particularly useful for defining recipes that are platform-specific. By default,
a build is never skipped.

```yaml
build:
  skip:
    - win
    ...
```

### Architecture-independent packages

Allows you to specify "no architecture" when building a package, thus making it
compatible with all platforms and architectures. Architecture-independent packages
can be installed on any platform.

Assigning the `noarch` key as `generic` tells `conda` to not try any manipulation of
the contents.

```yaml
build:
  noarch: generic
```

`noarch: generic` is most useful for packages such as static JavaScript assets
and source archives. For pure Python packages (similar to `none-any` wheels)
that can run on any Python version, you can use the `noarch: python` value instead:

```yaml
build:
  noarch: python
```

!!! note
    At the time of this writing, `noarch` packages should not make use
    of preprocess-selectors: `noarch` packages are built with the directives which
    evaluate to `true` in the platform it is built on, which probably will result
    in incorrect/incomplete installation in other platforms.

#### Conditional `noarch`

The `noarch` key can be set conditionally from a variant variable, which is
useful for recipes that build a `noarch: python` package in some variants and
an arch-specific package in others:

```yaml
build:
  # no noarch when `use_noarch` is false or undefined
  noarch: ${{ "python" if use_noarch }}
  # or, with an explicit else branch:
  noarch: ${{ "python" if use_noarch else none }}
```

An expression that renders to an empty or null-like value (`none`, `null`,
`~`, or the empty string) — as well as a literal `noarch: null` — is treated
the same as omitting the `noarch` key entirely. Referencing an undefined
variable is still an error: if the variable is only defined on some platforms,
provide an explicit fallback with the `default` filter, e.g.
`${{ "python" if use_noarch | default(false) }}`.

### Include only certain files in the package

Sometimes you may want to include only a subset of the files installed by the
build process in your package. For this, the `files` key can be used. Only _new_
files are considered for inclusion (ie. files that were not in the host
environment beforehand).

```yaml title="recipe.yaml"
build:
  # select files to be included in the package
  # this can be used to remove files from the package, even if they are installed in the
  # environment
  files:
    - list
    - of
    - globs
```

Glob patterns throughout the recipe file can also use a flexible `include` /
`exclude` pair, such as:

```yaml title="recipe.yaml"
build:
  files:
    include:
      - include/**/*.h
    exclude:
      - include/**/private.h
```


### Python specific options

#### Entry points

The following example creates a Python entry point named "`bsdiff4`" that calls
``bsdiff4.cli.main_bsdiff4()``. This is needed in [`noarch: python` packages](#architecture-independent-packages) to create
OS specific entry points at installation time.

```yaml
build:
  python:
    entry_points:
      - bsdiff4 = bsdiff4.cli:main_bsdiff4
      - bspatch4 = bsdiff4.cli:main_bspatch4
```

#### Version independent (ABI3) packages

Since Rattler-Build 0.35.0 and [CEP 20](https://github.com/conda/ceps/blob/main/cep-0020.md)
you can create version-independent Python packages that still contain compiled code.

ABI3 packages support building a native Python extension using a specific Python
version and running it against any later Python version. ABI3 or stable ABI is
supported by only CPython - the reference Python implementation with the Global
Interpreter Lock (GIL) enabled.

```yaml
build:
  python:
    version_independent: true  # defaults to false
```

#### Other `build.python` options

- **`skip_pyc_compilation`** - List of glob patterns of Python files that
  should be skipped when pre-compiling `.pyc` files during the build. Only
  relevant for non-`noarch` Python packages.
- **`use_python_app_entrypoint`** - When set to `true`, generates entry points
  that launch through the `python.app` wrapper on macOS. Useful for GUI
  applications that need access to the main event loop.
- **`site_packages_path`** - Overrides the relative `site-packages` directory
  that the `python` package itself exports. Only meaningful when building the
  `python` package.

```yaml
build:
  python:
    entry_points:
      - mytool = mytool.cli:main
    skip_pyc_compilation:
      - "mypkg/vendored/**"
    use_python_app_entrypoint: true
```

### Post-processing

Applies regex-based text replacements to files in the package during the packaging phase. Each entry specifies a set of files to match and a regex substitution
to apply.

```yaml title="recipe.yaml"
build:
  post_process:
    - files:
        - "bin/*"
      regex: "/old/path"
      replacement: "/new/path"
    - files:
        - "**/*.cmake"
        - "**/*.pc"
      regex: "/home/builder"
      replacement: "$PREFIX"
```

Each `post_process` entry has the following fields:

- **`files`** (required) — A list of glob patterns selecting which files to
  process. Supports `include`/`exclude` mappings and `if`/`then`/`else`
  conditionals.
- **`regex`** (required) — A regular expression pattern to match within each
  selected file.
- **`replacement`** (required) — The replacement string. Supports regex capture
  group references (e.g. `$1`, `${name}`).

All three fields are required for each entry.

#### Conditional post-processing

`post_process` entries support `if`/`then`/`else` conditionals, including
nesting:

```yaml title="recipe.yaml"
build:
  post_process:
    - if: unix
      then:
        - files:
            - "lib/**/*.la"
          regex: "/build/prefix"
          replacement: "$PREFIX"
    - files:
        - "**/*.txt"
      regex: "old_name"
      replacement: "new_name"
```

In the example above, the `.la` file replacement runs only on Unix, while the
`.txt` replacement runs unconditionally.

#### Behavior

- Post-processing runs during packaging, **after** relocation and Python
  post-processing, but **before** linking checks.
- Files are read as UTF-8 text using Rust’s read_to_string. If a matched file is not valid UTF-8, the build will fail.
- The regex uses `replace_all` semantics from Rust's `regex` crate: all non-overlapping matches in a file are replaced.
- Steps are applied sequentially. Later entries see the results of earlier ones.

#### Output inheritance

In multi-output recipes, each output inherits the top-level `post_process` if
the output does not define its own. If an output defines its own `post_process`, it fully overrides the top-level list. No merging is performed.

### Always include / copy files

By default, `rattler-build` packages only files that the build script creates
in the host prefix. The `always_include_files` and `always_copy_files` keys
override this on a per-glob basis:

- **`always_include_files`** - Glob patterns of files to add to the package
  even if they were already present in the host environment before the
  build ran. Useful when the build replaces a file that another dependency
  installed.
- **`always_copy_files`** - Glob patterns of files that should be copied
  rather than hard-linked into the install prefix. Use this for files the
  build script mutates in place, so mutations in one package do not leak
  into other environments sharing the same package cache.

```yaml
build:
  always_include_files:
    - bin/my-tool
  always_copy_files:
    - share/my-tool/config.yaml
```

### Merge build and host environments

By default, `build` and `host` are separate prefixes so that cross-compilation
works correctly. For recipes that do not cross-compile, setting
`merge_build_and_host_envs: true` merges the two environments into a single
prefix, matching the behaviour of legacy `conda-build` recipes that don't
distinguish between `build` and `host`.

```yaml
build:
  merge_build_and_host_envs: true
```

### Prefix detection

Controls how `rattler-build` finds and rewrites the build prefix inside
packaged files so that installed packages work from any install location.

```yaml
build:
  prefix_detection:
    # Files that should always be treated as text or binary regardless of
    # auto-detection
    force_file_type:
      text:
        - bin/*.py
      binary:
        - lib/**/*.so
    # Files that should be skipped entirely during prefix replacement
    # (true = skip all, false = skip none, list = glob patterns)
    ignore:
      - share/doc/**
    # Skip prefix detection in binary files (Unix only)
    ignore_binary_files: false
```

- **`force_file_type.text`** / **`force_file_type.binary`** - Glob patterns
  that force specific files to be treated as text or binary during prefix
  detection, overriding the automatic heuristics.
- **`ignore`** - Either a boolean or a list of glob patterns. `true` skips
  prefix replacement for all files, `false` (default) enables it for all,
  and a list skips only the matching files.
- **`ignore_binary_files`** - Skip prefix replacement in binary files (Unix
  only). Binary relocation is still handled separately under
  `dynamic_linking`.

### Variant configuration

The `variant` key controls how the build participates in the variant matrix
derived from `variant_config.yaml` and `pin_subpackage(..., exact=True)`.

```yaml
build:
  variant:
    use_keys:
      - numpy
    ignore_keys:
      - python
    down_prioritize_variant: 1
```

- **`use_keys`** - Variant keys that must be part of this build's variant
  matrix even if they are not referenced elsewhere in the recipe.
- **`ignore_keys`** - Variant keys that should be stripped from this
  build's variant even if they are referenced. Packages built with
  `ignore_keys` will not get a separate output per value of that key.
- **`down_prioritize_variant`** - Integer priority offset applied to this
  variant during solving (defaults to `0`). Higher values make the variant
  less preferred when multiple variants satisfy a dependency. This is
  implemented via `track_features`, so it is the magnitude of the value that
  matters (the sign is ignored).

## Include build recipe

The recipe and rendered `recipe.yaml` file are included in
the `package_metadata` by default. You can disable this by passing
`--no-include-recipe` on the command line.

!!! note
    See the [full build options](../build_options.md) guide for longer-form
    explanations and examples of the build keys documented above.


## Requirements section

Specifies the build and runtime requirements. Dependencies of these requirements
are included automatically.

Versions for requirements must follow the `conda`/`mamba` match specification. See
`build-version-spec`.

!!! note "V3 `MatchSpec` keys (beta — opt in with `--v3`)"
    When Rattler-Build is invoked with `--v3`, dependency strings everywhere
    in this section (`build`, `host`, `run`, `run_constraints`, `extras`,
    `run_exports`) accept three additional bracket keys:

    - `flags=[…]` — match by package variant flag (`pytorch[flags=[cuda]]`,
      `numpy[flags=[blas:*]]`).
    - `when="…"` — only include the dependency when the embedded predicate
      is satisfied (`scipy[when="python >=3.10"]`). Replaces the deprecated
      `; if` syntax.
    - `extras=[…]` — pull in optional dependency groups declared by the
      producing package (`mypkg[extras=[plot]]`).

    Without `--v3` these keys are rejected at parse time. See
    [V3 packages](../v3.md) for the full description.

### Build

Tools required to build the package.

These packages are run on the build system and include things such as version
control systems (`git`, `svn`) make tools (GNU make, Autotool, CMake) and compilers
(real cross, pseudo-cross, or native when not cross-compiling), and any source
pre-processors.

Packages which provide "`sysroot`" files, like the `CDT` packages (see below), also
belong in the `build` section.

```yaml
requirements:
  build:
    - git
    - cmake
```

### Host

Represents packages that need to be specific to the target platform when the
target platform is not necessarily the same as the native build platform. For
example, in order for a recipe to be "cross-capable", shared libraries
requirements must be listed in the `host` section, rather than the `build` section,
so that the shared libraries that get linked are ones for the target platform,
rather than the native build platform. You should also include the base
interpreter for packages that need one. In other words, a Python package would
list `python` here and an R package would list `mro-base` or `r-base`.

```yaml
requirements:
  build:
    - ${{ compiler('c') }}
    - if: linux
      then:
        - ${{ cdt('xorg-x11-proto-devel') }}
  host:
    - python
```

!!! note
    When both "`build`" and "`host`" sections are defined, the `build` section can
    be thought of as "build tools" - things that run on the native platform, but
    output results for the target platform (e.g. a cross-compiler that runs on
    `linux-64`, but targets `linux-armv7`).


The `PREFIX` environment variable points to the host prefix. With respect to
activation during builds, both the host and build environments are activated.
The build prefix is activated before the host prefix so that the host prefix has
priority over the build prefix. Executables that don't exist in the host prefix
should be found in the build prefix.

The `build` and `host` prefixes are always separate when both are defined, or when
`${{ compiler() }}` Jinja2 functions are used. The only time that `build` and `host`
are merged is when the `host` section is absent, and no `${{ compiler() }}` Jinja2
functions are used in `recipe.yaml`.

### Run

Packages required to run the package.

These are the dependencies that are installed automatically whenever the package is installed. Package names should follow the [package match
specifications](https://conda.io/projects/conda/en/latest/user-guide/concepts/pkg-specs.html#package-match-specifications).

```yaml
requirements:
  run:
    - python
    - six >=1.8.0
```

To build a recipe against different versions of NumPy and ensure that each
version is part of the package dependencies, list `numpy` as a requirement in
`recipe.yaml` and use a `conda_build_config.yaml` file with multiple NumPy
versions.

### Run constraints

Packages that are optional at runtime but must obey the supplied additional
constraint if they are installed.

Package names should follow the [package match
specifications](https://conda.io/projects/conda/en/latest/user-guide/concepts/pkg-specs.html#package-match-specifications).

```yaml
requirements:
  run_constraints:
    - optional-subpackage ==${{ version }}
```

For example, let's say we have an environment that has package "a" installed at
version 1.0. If we install package "b" that has a `run_constraints` entry of
"`a >1.0`", then `mamba` would need to upgrade "a" in the environment in order to
install "b".

This is especially useful in the context of virtual packages, where the
`run_constraints` dependency is not a package that `mamba` manages, but rather a
[virtual
package](https://docs.conda.io/projects/conda/en/latest/user-guide/tasks/manage-virtual.html)
that represents a system property that `mamba` can't change. For example, a
package on Linux may impose a `run_constraints` dependency on `__glibc >=2.12`.
This is the version bound consistent with CentOS 6. Software built against glibc
2.12 will be compatible with CentOS 6. This `run_constraints` dependency helps
`mamba`, `conda` or `pixi` tell the user that a given package can't be installed if their system
glibc version is too old.

### Optional dependencies / extras (V3, beta)

!!! warning "Beta — opt in with `--v3`"
    `requirements.extras` is part of the V3 repodata revision and is only
    accepted when Rattler-Build is invoked with `--v3`. Without the flag,
    recipes that declare an `extras` mapping fail to evaluate. See
    [V3 packages](../v3.md) for background.

`extras` is a mapping from a group name to a list of dependencies that are
*not* installed by default. Consumers opt in via the V3 `extras=[…]`
`MatchSpec` key. This mirrors the optional-dependencies idea from
`pyproject.toml`.

```yaml
requirements:
  run:
    - python >=3.10
  extras:
    plot:
      - matplotlib >=3.8
    full:
      - matplotlib >=3.8
      - pandas >=2
```

A downstream recipe can then pull a group in by name:

```yaml
requirements:
  run:
    - mypkg[extras=[plot]]
```

In the built package, optional groups are written into
`index.json::extra_depends`.

### Run exports

Packages may have runtime requirements such as shared libraries (e.g. `zlib`), which are required for linking at build time, and for resolving the link at run time.
With `run_exports` packages runtime requirements can be implicitly added.
`run_exports` are weak by default, these two requirements for the `zlib` package are therefore equivalent:

```yaml title="recipe.yaml for zlib"
  requirements:
    run_exports:
      - ${{ pin_subpackage('libzlib', exact=True) }}
```

```yaml title="recipe.yaml for zlib"
  requirements:
    run_exports:
      weak:
        - ${{ pin_subpackage('libzlib', exact=True) }}
```

The alternative to `weak` is `strong`.
For `gcc` this would look like this:

```yaml title="recipe.yaml for gcc"
  requirements:
    run_exports:
      strong:
        - ${{ pin_subpackage('libgcc', exact=True) }}
```

`weak` exports will only be implicitly added as runtime requirement, if the package is a host dependency.
`strong` exports will be added for both build and host dependencies.

In addition to `weak` and `strong`, the `run_exports` mapping supports the
following keys:

- **`weak_constraints`** - Like `weak`, but the exported specs are added to
  the downstream package's `run_constraints` rather than its `run`
  requirements.
- **`strong_constraints`** - Same as `weak_constraints`, but applies to
  both build and host dependencies.
- **`noarch`** - Run exports that are only added for downstream `noarch`
  packages. Useful when a package ships architecture-specific builds but
  wants to pin differently for pure-Python consumers.

```yaml title="recipe.yaml"
  requirements:
    run_exports:
      strong:
        - ${{ pin_subpackage('libfoo', exact=True) }}
      weak_constraints:
        - foo-plugin >=2
      noarch:
        - python >=3.9
```

In the following example you can see the implicitly added runtime dependencies.

```yaml title="recipe.yaml of some package using gcc and zlib"
  requirements:
    build:
      - gcc            # has a strong run export
    host:
      - zlib           # has a (weak) run export
      # - libgcc       <-- implicitly added by gcc
    run:
      # - libgcc       <-- implicitly added by gcc
      # - libzlib      <-- implicitly added by libzlib
```


### Ignore run exports

There maybe cases where an upstream package has a problematic `run_exports` constraint.
You can ignore it in your recipe by listing the upstream package name in the
`ignore_run_exports` section in `requirements`.

You can ignore them by package name, or by naming the runtime dependency directly.

```yaml
  requirements:
    ignore_run_exports:
      from_package:
        - zlib
```

Using a runtime dependency name:

```yaml
  requirements:
    ignore_run_exports:
      by_name:
        - libzlib
```

!!! note
    `ignore_run_exports` only applies to runtime dependencies coming from an upstream package.

## Tests section

Rattler-Build supports four different types of tests. The "script test" installs
the package and runs a list of commands. The "Python test" attempts to import a
list of Python modules and runs `pip check`. The "downstream test" runs the tests
of a downstream package that reverse depends on the package being built. And lastly,
the "package content test" checks if the built package contains the mentioned items.

The `tests` section is a list of these items:

```yaml
tests:
  - script:
      - echo "hello world"
    requirements:
      run:
        - pytest
    files:
      source:
        - test-data.txt

  - python:
      imports:
        - bsdiff4
      pip_check: true  # this is the default
  - downstream: numpy
```

### Script test

The script test has 3 top-level keys: `script`, `files` and `requirements`. Only
the `script` key is required.

#### Test commands

Commands that are run as part of the test.

```yaml
tests:
  - script:
      - echo "hello world"
      - bsdiff4 -h
      - bspatch4 -h
```

#### External scripts

You can also easily run a script from your recipe directory.
Note that your package should either depend on the interpreter (e.g. Python or R)
or you need to add a `requirements` section to the test that installs the interpreter.

```yaml
tests:
  - script: tests/run_test.py
  - script: tests/run_test.R
  - script: tests/run_test.sh
```

#### Extra test files

Test files that are copied from the source work directory into the temporary
test directory and are needed during testing (note that the source work
directory is otherwise not available at all during testing).

You can also include files that come from the `recipe` folder. They are copied
into the test directory as well.

At test execution time, the test directory is the current working directory.

```yaml
tests:
  - script:
      - ls
    files:
      source:
        - myfile.txt
        - tests/
        - some/directory/pattern*.sh
      recipe:
        - extra-file.txt
```

#### Test requirements

In addition to the runtime requirements, you can specify requirements needed
during testing. The runtime requirements that you specified in the "`run`" section
described above are automatically included during testing (because the built
package is installed as it regularly would be).

In the `build` section you can specify additional requirements that are only
needed on the build system for cross-compilation (e.g. emulators or compilers).

```yaml
tests:
  - script:
      - echo "hello world"
    requirements:
      build:
        - myemulator
      run:
        - nose
```

### Python tests

For this test type you can list a set of Python modules that need to be
importable. The test will fail if any of the modules cannot be imported.

The test will also automatically run `pip check` to check for any broken
dependencies. This can be disabled by setting `pip_check: false` in the YAML.


```yaml
tests:
  - python:
      imports:
        - bsdiff4
        - bspatch4
      pip_check: true  # can be left out because this is the default
      python_version: 3.12.*  # optional: use list for multiple versions, default resolves to environment
```

Internally this will write a small Python script that imports the modules:

```python
import bsdiff4
import bspatch4
```

### Perl tests

For this test type you can list a set of Perl modules that need to be
importable. The test will fail if any of the modules cannot be imported.

```yaml
tests:
  - perl:
      uses:
        - Call::Context
```

Internally this will write a small Perl script that imports the modules:

```perl
use Call::Context;
```

### R tests

For this test type you can list a set of R modules that need to be
importable. The test will fail if any of the modules cannot be imported.

```yaml
- r:
    libraries:
      - knitr
```

Internally this will write a small R script that imports the modules:

```r
library(knitr)
```

### Ruby tests

For this test type you can list a set of Ruby modules or gems that need to be
loadable. The test will fail if any of them cannot be required.

```yaml
tests:
  - ruby:
      requires:
        - json
        - rspec
```

Internally this will write a small Ruby script that `require`s each module:

```ruby
require 'json'
require 'rspec'
```

### Check for package contents

Checks if the built package contains the mentioned items. These checks are executed directly at
the end of the build process to make sure that all expected files are present in the package.

```yaml
tests:
  - package_contents:
      # checks for the existence of files inside $PREFIX or %PREFIX%
      # or, checks that there is at least one file matching the specified `glob`
      # pattern inside the prefix
      files:
        - etc/libmamba/test.txt
        - etc/libmamba
        - etc/libmamba/*.mamba.txt

      # For more advanced cases, you can use the expanded form with exists and not_exists:
      # files:
      #   exists:
      #     - etc/libmamba/test.txt
      #     - etc/libmamba
      #     - etc/libmamba/*.mamba.txt
      #   not_exists:
      #     - etc/libmamba/unwanted.txt

      # checks for the existence of `mamba/api/__init__.py` inside of the
      # Python site-packages directory (note: also see Python import checks)
      site_packages:
        - mamba.api


      # looks in $PREFIX/bin/mamba for unix and %PREFIX%\Library\bin\mamba.exe on Windows
      # note: also check the `commands` and execute something like `mamba --help` to make
      # sure things work fine
      bin:
        - mamba

      # enable strict mode: error if any file in the package is not matched by one of the globs
      # (default: false)
      strict: true

      # searches for `$PREFIX/lib/libmamba.so` or `$PREFIX/lib/libmamba.dylib` on Linux or macOS,
      # on Windows for %PREFIX%\Library\lib\mamba.dll & %PREFIX%\Library\bin\mamba.bin
      lib:
        - mamba

      # searches for `$PREFIX/include/libmamba/mamba.hpp` on unix, and
      # on Windows for `%PREFIX%\Library\include\libmamba\mamba.hpp`
      include:
        - libmamba/mamba.hpp
```

### Downstream tests

A downstream test can mention a single package that has a dependency on the package being built.
The test will install the package and run the tests of the downstream package with our current
package as a dependency.

Sometimes downstream packages do not resolve. In this case, the test is ignored.

```yaml
tests:
  - downstream: numpy
```


## Outputs section

!!! tip
    For a complete guide including staging outputs and examples, see [Multi-Output Recipes](multi_output.md).

Explicitly specifies packaging steps. This section supports multiple outputs, as
well as different package output types. The format is a list of mappings.

When using multiple outputs, certain top-level keys are "forbidden": `package`
and `requirements`. Instead of `package`, a top-level `recipe` key can be
defined. The `recipe.name` is ignored but the `recipe.version` key is used as
default version for each output. Other "top-level" keys are merged into each
output (e.g. the `about` section) to avoid repetition. Each output is a
complete recipe, and can have its own `build`, `requirements`, and `test`
sections.

```yaml
recipe:
  # the recipe name is ignored
  name: some
  version: 1.0

outputs:
  - package:
      # version is taken from recipe.version (1.0)
      name: some-subpackage

  - package:
      name: some-other-subpackage
      version: 2.0
```

Each output acts like an independent recipe and can have their own `script`,
`build_number`, and so on.

```yaml
outputs:
  - package:
      name: subpackage-name
    build:
      script: install-subpackage
```

If `script` lacks a file extension,
the appropriate extension for the platform will be appended,
e.g. the above will run `install-subpackage.sh` in `bash` on most platforms
and `install-subpackage.bat` in `cmd.exe` on Windows.

Each output is built independently. You should take care of not packaging the
same files twice.

### Subpackage requirements

Like a top-level recipe, a subpackage may have zero or more dependencies listed
as build, host or run requirements.

The dependencies listed as subpackage build requirements are available only
during the packaging phase of that subpackage.

```yaml
outputs:
  - package:
      name: subpackage-name
    requirements:
      build:
        - some-dep
      run:
        - some-dep
```

You can also use the `pin_subpackage` function to pin another output from the
same recipe.

```yaml
outputs:
  - package:
      name: libtest
  - package:
      name: test
    requirements:
      build:
        - ${{ pin_subpackage('libtest', upper_bound='x.x') }}
```

The outputs are topologically sorted by the dependency graph which is taking the
`pin_subpackage` invocations into account. When using `pin_subpackage(name,
exact=True)` a special behavior is used where the `name` package is injected as
a "variant" and the variant matrix is expanded appropriately. For example, when
you have the following situation, with a `variant_config.yaml` file that
contains `openssl: [1, 3]`:

```yaml
outputs:
  - package:
      name: libtest
    requirements:
      host:
        - openssl
  - package:
      name: test
    requirements:
      build:
        - ${{ pin_subpackage('libtest', exact=True) }}
```

Due to the variant config file, this will build two versions of `libtest`. We
will also build two versions of `test`, one that depends on `libtest (openssl
1)` and one that depends on `libtest (openssl 3)`.

### Staging outputs

!!!note

    See the [staging outputs guide](../multiple_output_cache.md) for a full
    walkthrough.

A staging output builds code once and caches the results. Other package outputs
can **inherit** from a staging cache to receive the built files directly in
their `$PREFIX` without rebuilding. Staging outputs do **not** produce package
artifacts themselves.

```yaml
outputs:
  - staging:
      name: my-staging-cache   # required, follows package name rules
    source:                     # optional, additional sources
      - url: https://example.com/src.tar.gz
        sha256: abc123...
    requirements:
      build:                    # build-time dependencies
        - ${{ compiler('c') }}
        - cmake
      host:                     # host dependencies
        - zlib
      ignore_run_exports:       # optional, filter run exports at the staging level
        from_package:
          - zlib
    build:
      script:                   # build script (only field allowed under build)
        - cmake -B build
        - cmake --build build --target install
```

The `staging:` output supports:

- `staging.name` — required, the cache name that inheriting packages reference
- `source` — optional source sections (in addition to top-level sources)
- `requirements` — `build`, `host`, and `ignore_run_exports` (no `run` requirements)
- `build.script` — the build script to execute

#### Inheriting from staging

Package outputs use the `inherit:` key to receive files from a staging cache.
Two forms are supported:

```yaml
outputs:
  - staging:
      name: my-build
    build:
      script:
        - make install

  # Short form — inherits all files and run exports
  - package:
      name: mylib
    inherit: my-build
    build:
      files:
        - lib/**

  # Extended form — control run exports inheritance
  - package:
      name: mylib-dev
    inherit:
      from: my-build
      run_exports: false   # do not inherit run exports from staging deps
    build:
      files:
        - include/**
```

When a package inherits from staging:

1. The staging cache's prefix files are copied into the package's `$PREFIX`
2. The staging cache's work directory is restored (allowing incremental builds)
3. Run exports from staging dependencies are added to the package's run
   requirements (unless `run_exports: false` is set)
4. The `files` globs select which subset of the inherited files end up in the
   final package

#### Top-level inheritance

In recipes that have both a top-level `build:` section and staging outputs,
package outputs can choose to inherit from the top-level build instead of from
staging by setting `inherit: null`:

```yaml
build:
  script:
    - echo "top-level" > $PREFIX/share/data.txt

outputs:
  - staging:
      name: compile-stage
    build:
      script:
        - echo "compiled" > $PREFIX/lib/compiled.so

  - package:
      name: compiled-pkg
    inherit: compile-stage       # gets files from staging
    build:
      files:
        - lib/**

  - package:
      name: data-pkg
    inherit: null                # gets files from top-level build
    build:
      files:
        - share/**
```

## About section

Specifies identifying information about the package. The information displays in
the package server.

```yaml
about:
  homepage: https://example.com/bsdiff4
  license: BSD-3-Clause # (1)!
  license_file: LICENSE
  summary: binary diff and patch using the BSDIFF4-format
  description: |
    Long description of bsdiff4 ...
  repository: https://github.com/ilanschnell/bsdiff4
  documentation: https://docs.com
```

1.  Only the SPDX specifiers are allowed, more info here: [SPDX](https://spdx.org/licenses/)
    If you want another license type `LicenseRef-<YOUR-LICENSE>` can be used, e.g. `license: LicenseRef-Proprietary`

The full list of accepted `about` keys:

- **`homepage`** - Project homepage URL.
- **`repository`** - Source repository URL.
- **`documentation`** - Documentation URL.
- **`license`** - SPDX license expression (see note above).
- **`license_file`** - License file(s) to include in the package (see below).
- **`license_family`** - Coarse license family (e.g. `MIT`, `Apache`, `GPL`).
  Deprecated and kept only for compatibility with legacy `conda-build`
  recipes; prefer setting a precise SPDX expression in `license`.
- **`summary`** - One-line description of the package.
- **`description`** - Longer free-form description.

### License file

Adds a file containing the software license to the package metadata.
Many licenses require the license statement to be distributed with the package.
The filename is relative to the source or recipe directory. The value can be a
single filename or a YAML list for multiple license files. Values can also point
to directories with license information. Directory entries must end with a `/`
suffix (this is to lessen unintentional inclusion of non-license files; all the
directory's contents will be unconditionally and recursively added).

If a license file is found in both the source and recipe directories, the file from
the recipe directory is used (you should see a warning about this in the build log).

```yaml
about:
  license_file:
    - LICENSE
    - vendor-licenses/
```

License file entries may also refer to a restricted set of build-time directory
variables that are only known once the build has finished. These are resolved
during packaging:

- `${{ PREFIX }}` – the host prefix
- `${{ BUILD_PREFIX }}` – the build prefix
- `${{ SRC_DIR }}` – the source working directory
- `${{ RECIPE_DIR }}` – the recipe directory
- `${{ BUILD_DIR }}` – the top-level build directory

This is useful for packages (such as R packages) that install their license
files into `${{ PREFIX }}` during the build:

```yaml
about:
  license_file:
    - LICENSE
    - ${{ PREFIX }}/lib/R/library/mypkg/LICENSE
```

Entries that reference one of these variables may contain glob patterns
(e.g. `${{ PREFIX }}/share/licenses/*/LICENSE`) and are always allowed — unlike
plain absolute paths they do not require `--allow-absolute-license-paths`.


## Extra section

A schema-free area for storing non-`conda`-specific metadata in standard YAML
form.

???+ Example "Example: To store recipe maintainers information"
    ```yaml
    extra:
      maintainers:
       - name of maintainer
    ```


## Templating with Jinja

Rattler-Build supports limited Jinja templating in the `recipe.yaml` file.

You can set up Jinja variables in the `context` section:

```yaml
context:
  name: "test"
  version: "5.1.2"
  # later keys can reference previous keys
  # and use jinja functions to compute new values
  major_version: ${{ (version | split('.'))[0] }}
  tests_to_skip:
    # fails for one reason
    - test_foo
    # fails for another reason
    - test_bar
```

Later in your `recipe.yaml` you can use these values in string interpolation
with Jinja:

```yaml
source:
  url: https://github.com/mamba-org/${{ name }}/v${{ version }}.tar.gz

tests:
  - script:
    - pytest -k "not (${{ tests_to_skip | join(" or ")" }})"
```

Jinja has built-in support for some common string manipulations.

In Rattler-Build, complex Jinja is completely disallowed as we try to produce
YAML that is valid at all times. So you should not use any `{% if ... %}` or
similar Jinja constructs that produce invalid YAML. Furthermore, instead of
plain double curly brackets Jinja statements need to be prefixed by `$`, e.g.
`${{ ... }}`:

```yaml
package:
  name: {{ name }}   # WRONG: invalid yaml
  name: ${{ name }} # correct
```

For more information, see the [Jinja template
documentation](https://jinja.palletsprojects.com/en/3.1.x/) and the list of
available environment variables [`env-vars`]().

Jinja templates are evaluated during the build process.
<!-- TODO: implement the command to do below
To retrieve a fully rendered `recipe.yaml`, use the `` command.
-->

#### Additional Jinja2 functionality in Rattler-Build

Besides the default Jinja2 functionality, additional Jinja functions are
available during the Rattler-Build process: `pin_compatible`, `pin_subpackage`,
`compiler` and `stdlib`.

The `compiler` function takes `c`, `cxx`, `fortran` and other values as argument
and automatically selects the right (cross-)compiler for the target platform.
Similarly, `stdlib` function selects the right standard library dependencies.

```
build:
  - ${{ compiler('c') }}
  - ${{ stdlib('c') }}
```

The `pin_subpackage` function pins another package produced by the recipe with
the supplied parameters.

Similarly, the `pin_compatible` function will pin a package according to the
specified rules.

#### Pin expressions

Rattler-Build knows pin expressions. A pin expression can have a `lower_bound`,
`upper_bound` and `exact` value. A `upper_bound` and `lower_bound` are specified with a
string containing only `x` and `.`, e.g. `upper_bound="x.x.x"` would signify to pin
the given package to `<1.2.3` (if the package version is `1.2.2`, for example).

A pin with `lower_bound="x.x",upper_bound="x.x"` for a package of version `1.2.2` would
evaluate to `>=1.2,<1.3.0a0`.

If `exact=true`, then the `hash` is included, and the package is pinned exactly,
e.g. `==1.2.2 h1234`. This is a unique package variant that cannot exist more
than once, and thus is "exactly" pinned.

You can also hard-code version strings into `lower_bound` and `upper_bound`.
See the [Jinja Reference](./jinja.md) for more information.

#### Pin subpackage

Pin subpackage refers to another package from the same recipe file. It is
commonly used in the `requirements/run_exports` section to export a run export from the
package, or with multiple outputs to refer to a previous build.

It looks something like:

```yaml
package:
  name: mypkg
  version: "1.2.3"

requirements:
  run_exports:
    # this will evaluate to `mypkg <1.3`
    - ${{ pin_subpackage(name, upper_bound='x.x') }}
```

#### Pin compatible

Pin compatible lets you pin a package based on the version retrieved from the
variant file (if the pinning from the variant file needs customization).

For example, if the variant specifies a pin for `numpy: 1.11`, one can use
`pin_compatible` to relax it:

```yaml
requirements:
  host:
    # this will select numpy 1.11
    - numpy
  run:
    # this will export `numpy >=1.11,<2`, instead of the stricter `1.11` pin
    - ${{ pin_compatible('numpy', lower_bound='x.x', upper_bound='x') }}
```

#### The env Jinja functions

You can access the environment variables set outside the build script using the
`env` object in Jinja.

There are three functions:

- `env.get("ENV_VAR")` will insert the value of "ENV_VAR" into the recipe.
- `env.get("ENV_VAR", default="undefined")` will insert the value of `ENV_VAR`
  into the recipe or, if `ENV_VAR` is not defined, the specified default value
  (in this case "undefined")
- `env.exists("ENV_VAR")` returns a boolean true of false if the env var is set
  to any value

This can be used for some light templating, for example:

```yaml
build:
  string: ${{ env.get("GIT_BUILD_STRING") }}_${{ hash }}
```

#### `match` function

This function matches the first argument (the package version) against the second
argument (the version spec) and returns the resulting boolean. This only works for packages
defined in the "variant_config.yaml" file.

```yaml title="recipe.yaml"
match(python, '>=3.4')
```

For example, you could require a certain dependency only for builds against python 3.4 and above:

```yaml title="recipe.yaml"
requirements:
  build:
    - if: match(python, '>=3.4')
      then:
        - some-dep
```

With a corresponding variant config that looks like the following:

```yaml title="variant_config.yaml"
python: ["3.2", "3.4", "3.6"]
```

Example: [`match` usage example](https://github.com/prefix-dev/rattler-build/tree/main/examples/match_and_cdt/recipe.yaml)

#### `cdt` function

This function helps add Core Dependency Tree packages as dependencies by converting packages as required according to hard-coded logic.

```yaml
# on x86_64 system
cdt('package-name') # outputs: package-name-cos6-x86_64
# on aarch64 system
cdt('package-name') # outputs: package-name-cos6-aarch64
```

Example: [`cdt` usage example](https://github.com/prefix-dev/rattler-build/tree/main/examples/match_and_cdt/recipe.yaml)

## Preprocessing selectors

You can add selectors to any item, and the selector is evaluated in a
preprocessing stage. If a selector evaluates to `true`, the item is flattened
into the parent element. If a selector evaluates to `false`, the item is
removed.

Selectors can use `if ... then ... else` as follows:

```yaml
source:
  - if: not win
    then:
      - url: http://path/to/unix/source
    else:
      - url: http://path/to/windows/source

# or the equivalent with two if conditions:

source:
  - if: unix
    then:
      - url: http://path/to/unix/source
  - if: win
    then:
      - url: http://path/to/windows/source
```

A selector is a valid Python statement that is executed. You can read more about
them in the ["Selectors in recipes" chapter](../selectors.md).

Note that `conda-build`'s Python version selectors (`py27`, `py34`, etc.) are
not supported in `rattler-build`. Use the more general comparison operators
instead.

Because the selector is any valid Python expression, complicated logic is
possible:

```yaml
- if: unix and not win
  then: ...
- if: (win or linux) and not py27
  then: ...
```

Lists are automatically "merged" upwards, so it is possible to group multiple
items under a single selector:

```yaml
tests:
  - script:
    - if: unix
      then:
      - test -d ${PREFIX}/include/xtensor
      - test -f ${PREFIX}/lib/cmake/xtensor/xtensorConfigVersion.cmake
    - if: win
      then:
      - if not exist %LIBRARY_PREFIX%\include\xtensor\xarray.hpp (exit 1)
      - if not exist %LIBRARY_PREFIX%\lib\cmake\xtensor\xtensorConfigVersion.cmake (exit 1)

# On unix this is rendered to:
tests:
  - script:
    - test -d ${PREFIX}/include/xtensor
    - test -f ${PREFIX}/lib/cmake/xtensor/xtensorConfigVersion.cmake
```


## Experimental features

!!! warning
    These are experimental features of Rattler-Build and may change or go away completely.

### Jinja functions

- [`load_from_file`](../experimental_features.md#load_from_filefile_path)
- [`git.*` functions](../experimental_features.md#git-functions)
