Skip to content

Build

https://docs.conda.io/projects/conda-build/en/latest/concepts/recipe.html

parameters

https://docs.conda.io/projects/conda-build/en/stable/resources/commands/conda-build.html

Building a conda package requires a recipe. A conda-build recipe is a flat directory that contains the following files:

  • meta.yaml: Only package/name and package/version are required

  • build.sh: It is executed using the bash command for macOS and Linux.

  • bld.bat: It is executed using cmd for Windows.

  • run_test.[py,pl,sh,bat]: a test script that runs automatically if it is part of the recipe.

  • Optional patches that are applied to the source.

  • Other resources that are not included in the source and cannot be generated by the build scripts.

bld.bat

"%PYTHON%" setup.py install
if errorlevel 1 exit 1

build.sh

$PYTHON setup.py install     # Python command to install the script

build.sh

You can define the build.sh script inline in the meta.yaml file otherwise conda-build will look for a build.sh script in the recipe directory

build:
  number: 100
  script: python -m pip install . --no-deps --ignore-installed #--no-cache-dir -vvv

install conda-build

  • Must install cond-build in base env.

  • https://docs.conda.io/projects/conda-build/en/stable/install-conda-build.html

  • For proper functioning, it is strongly recommended to install conda-build in the conda base environment. Not doing so may lead to problems.

    conda activate base
    conda install conda-build
    

conda mambabuild

boa has been deprecated in favor of rattler‑build, a substantially faster rust-based alternative.

  • https://github.com/conda/conda-build/issues/5351

  • boa appears to be a concluded project

  • latest conda >= 23.10.0 by default use libmamba solver so there is no need to use conda mambabuild that requires boa

debug

https://docs.conda.io/projects/conda-build/en/stable/user-guide/recipes/debugging.html

debugging is a process of getting into or recreating the environment and set of shell environment variables that conda-build creates during its build or test processes.

conda debug recipe
conda debug recipe --python=3.12 --variants="{blas_impl: 'openblas'}"
cd /debug/path && source /debug/path/build_env_setup.sh
conda build purge-all # remove previously built packages

build conda package

We run the command inside the project root folder:

  • --output will disable all output messages

  • --croot path cannot be a subfolder of the current project folder; must be outside of the project folder AssertionError: Can't merge/copy source into subdirectory of itself. Please create separate spaces for these things.

Example:

export VERSION=0.15.1
conda build recipe --no-anaconda-upload --python 3.12 --croot ../conda-build --no-test
  • We assume in the meta.yaml file there is a variable named VERSION.

  • In the first line we pass the version value to the VERSION variable.

  • The second line is used to build the conda package to a folder called conda-build.

More options:

conda build recipe --no-anaconda-upload --python 3.12 --croot c:/pkg/conda --no-test
conda build recipe --no-anaconda-upload --python 3.12 --croot /build/path --no-test --channel ch1 --channel ch2
Note that without set --python, will build a package compatible to the python version in the current env. We can also set the cli flags via env var CONDA_PY and the flag --variants which accepts JSON-formatted text. example: https://docs.conda.io/projects/conda-build/en/latest/resources/variants.html
conda build recipe --variants "{python: [2.7, 3.5], vc: [9, 14]}"

remove source and build intermediates

conda build purge

pass variable value to meta.yaml

before running conda build

export VERSION=1.0.0

Templating with Jinja: https://docs.conda.io/projects/conda-build/en/3.21.x/resources/define-metadata.html

  • Conda-build supports Jinja templating in the meta.yaml file

  • We can use Jinja templating inside the meta.yaml file to dynamically inject environment variables.

    package:
      name: {{ NAME }}
      version: {{ VERSION }}
    
    In this example, the values of env varables NAME and VERSION will be injected into the meta.yaml file.

meta.yaml

https://stackoverflow.com/questions/38919840/get-package-version-for-conda-meta-yaml-from-source-file

https://www.underworldcode.org/articles/build-conda-packages/

{% set NAME = "pkg" %}
{% set VERSION = load_setup_py_data().version %}
{% set GITHUB_URL = load_setup_py_data().url %}
{% set DESCRIPTION = load_setup_py_data().description %}

package:
  name: {{ NAME }}
  version: {{ VERSION }}

source:
  path: ../

outputs:
  - name: {{ NAME }}
    build:
      number: 0
      script: python -m pip install --no-deps --ignore-installed .
      entry_points:
        - pkg-run = pkg.main:cli
    requirements:
      host:
        - pip
        - python
        - setuptools >=41.0.0
      run:
        - click
        - numba
        - numpy
        - pandas
        - python
    about:
      home: {{ GITHUB_URL }}
      summary: {{ DESCRIPTION }}

  - name: {{ NAME }}.test
    requirements:
      run:
        - pytest
        - pytest-cov
        - coverage
    test:
      source_files:
        - tests
    about:
      home: {{ GITHUB_URL }}
      summary: Test dependencies for {{ NAME }}

  - name: {{ NAME }}.doc
    requirements:
      run:
        - docstring_parser
        - mkdocs
        - mkdocstrings <0.18
        - mkdocs-click
        - mkdocs-material
        - mkdocs-material-extensions
        - pytkdocs
    about:
      home: {{ GITHUB_URL }}
      summary: Doc dependencies for {{ NAME }}

issue

https://stackoverflow.com/questions/69030813/doing-a-conda-build-does-not-find-any-files/69044365#69044365

push conda package to conda repo

import requests
def push_conda(
    filepath,
    *,
    channel='example/dev',
    platform='linux-64',
    repo_url='https://conda.example.com',
    force=False,
):
    url = f'{repo_url}/api/packages'
    files = {'file': open(filepath, 'rb')}
    params = {
        'channel': channel,
        'platform': platform,
        'force': False,
    }
    r = requests.post(url, files=files, data=params)
    if r.status_code != 200:
        try:
            msg = r.json().get('message')
        except json.JSONDecodeError:
            msg = r.text
        finally:
            raise Exception(msg)

filepath = '/path/to/conda-build/linux-64/my-build-0.1.0-py39_0.tar.bz2'
push_conda(filepath)