Skip to content

Commit 8af376f

Browse files
committed
Document OS-specific approaches for noarch packages
1 parent 780563d commit 8af376f

File tree

1 file changed

+127
-0
lines changed

1 file changed

+127
-0
lines changed

src/maintainer/knowledge_base.rst

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1028,10 +1028,137 @@ In order to qualify as a noarch python package, all of the following criteria mu
10281028
which builds on Linux `and` Windows, with ``build_number`` offsets to create a pair packages, like
10291029
``dataclasses``.
10301030

1031+
.. hint::
1032+
1033+
You can build platform-specific ``noarch`` packages to include runtime requirements depending on the target OS.
1034+
See mini-tutorial below.
1035+
10311036
If an existing python package qualifies to be converted to a noarch package, you can request the required changes
10321037
by opening a new issue and including ``@conda-forge-admin, please add noarch: python``.
10331038

1039+
.. _os_specific_noarch:
1040+
1041+
Noarch packages with OS-specific dependencies
1042+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1043+
1044+
It is possible to build ``noarch`` packages with runtime requirements that depend on the target OS (Linux, Windows,
1045+
MacOS), regardless the architecture (amd64, ARM, PowerPC, etc). This approach relies on four concepts:
1046+
1047+
1. Virtual packages. Prefixed with a double underscore, they are used by conda to represent properties of the running system
1048+
as constraints for the solver. We will use ``__linux``, ``__win`` or ``__osx``, which are only present when
1049+
the running platform is Linux, Windows, or MacOS, respectively. ``__unix`` is present in both Linux and MacOS. Note
1050+
that this feature is **only fully available on conda 4.10 or above**.
1051+
2. Jinja conditionals, which can be used to mimic platform selectors.
1052+
3. ``conda-forge.ymls``'s :ref:`noarch_platforms` option.
1053+
4. conda-build's ``conda_build_config.yaml`` to create a matrix build that depends on the ``noarch_platforms`` values.
1054+
1055+
The idea is to generate OS-specific noarch packages for the OS that need different dependencies. Let's say you have a pure
1056+
Python package, perfectly eligible for ``noarch: python``, but on Windows it requires ``windows-only-dependency``. You might
1057+
have something like:
1058+
1059+
.. code-block:: yaml
1060+
1061+
# recipe/meta.yaml
1062+
name: package
1063+
source:
1064+
...
1065+
build:
1066+
number: 0
1067+
requirements:
1068+
...
1069+
run:
1070+
- python
1071+
- numpy
1072+
- windows-only-dependency # [win]
1073+
1074+
We can replace it with:
1075+
1076+
.. code-block:: yaml
1077+
1078+
# recipe/meta.yaml
1079+
name: package
1080+
source:
1081+
...
1082+
build:
1083+
number: 0
1084+
noarch: python
1085+
requirements:
1086+
...
1087+
run:
1088+
- python
1089+
- numpy
1090+
- __{{ target_os }}
1091+
{% if target_os == 'win' %}
1092+
- windows-only-dependency
1093+
{% endif %}
1094+
1095+
Cool! Where does ``target_os`` come from? We need to define it in ``conda_build_config.yaml``.
1096+
Note how the values have been chosen carefully so they match the virtual packages names:
1097+
1098+
.. code-block:: yaml
1099+
1100+
# recipe/conda_build_config.yaml
1101+
target_os:
1102+
- unix # [unix]
1103+
- win # [win]
1104+
1105+
By default, conda-forge will only build ``noarch`` packages on a ``linux-64`` CI runner, so
1106+
the ``target_os`` matrix would only provide the ``unix`` value (because the ``# [win]`` selector
1107+
would never be true). Fortunately, we can change the default behaviour in ``conda-forge.yml``:
1108+
1109+
.. code-block:: yaml
1110+
1111+
# conda-forge.yml
1112+
noarch_platforms:
1113+
- linux-64
1114+
- win-64
1115+
1116+
This will provide two runners per package! But since we are using selectors in ``conda_build_config.yaml``,
1117+
only one is true at a time. Perfect! All these changes require a feedstock rerender to be applied:
1118+
:ref:`_dev_update_rerender`.
1119+
1120+
Last but not least, what if you need conditional dependencies on all three operating systems? Do it like this:
1121+
1122+
.. code-block:: yaml
1123+
1124+
# recipe/meta.yaml
1125+
name: package
1126+
source:
1127+
...
1128+
build:
1129+
number: 0
1130+
noarch: python
1131+
requirements:
1132+
...
1133+
run:
1134+
- python
1135+
- numpy
1136+
- __{{ target_os }}
1137+
{% if target_os == 'osx' %}
1138+
- osx-only-dependency
1139+
{% elif target_os == 'win' %}
1140+
- windows-only-dependency
1141+
{% else %}
1142+
- linux-only-dependency
1143+
{% endif %}
1144+
1145+
.. code-block:: yaml
1146+
1147+
# recipe/conda_build_config.yaml
1148+
target_os:
1149+
- linux # [linux]
1150+
- osx # [osx]
1151+
- win # [win]
1152+
1153+
.. code-block:: yaml
1154+
1155+
# conda-forge.yml
1156+
noarch_platforms:
1157+
- linux-64
1158+
- osx-64
1159+
- win-64
10341160
1161+
Again, d
10351162
Noarch generic
10361163
--------------
10371164

0 commit comments

Comments
 (0)