summaryrefslogtreecommitdiff
blob: b467a178a77ca6c2fe2f34c5f184a15d9dc71315 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
=====================================
python-any-r1 — build-time dependency
=====================================

.. highlight:: bash

The ``python-any-r1`` eclass is used to enable Python support
in packages needing it purely at build time.

Eclass reference: `python-any-r1.eclass(5)`_


Basic use for unconditional Python
==================================
The defining feature of this eclass is that it defines a ``pkg_setup``
phase.  It normally calls ``python_setup`` function in order to find
a suitable Python interpreter, and set the global environment
appropriately.

This means that a most trivial package using an autotools-compatible
build system that needs Python at build time could look like
the following:

.. code-block:: bash
   :emphasize-lines: 6,7,21

    # Copyright 1999-2020 Gentoo Authors
    # Distributed under the terms of the GNU General Public License v2

    EAPI=7

    PYTHON_COMPAT=( python3_{6..8} )
    inherit python-any-r1

    DESCRIPTION="A repository of data files describing media player capabilities"
    HOMEPAGE="https://cgit.freedesktop.org/media-player-info/"
    SRC_URI="https://www.freedesktop.org/software/${PN}/${P}.tar.gz"

    LICENSE="BSD"
    SLOT="0"
    KEYWORDS="~alpha amd64 ~arm ~arm64 ~hppa ~ia64 ~mips ppc ppc64 ~sh ~sparc x86"
    IUSE=""

    RDEPEND=">=virtual/udev-208"
    DEPEND="${RDEPEND}"
    BDEPEND="
        ${PYTHON_DEPS}
        virtual/pkgconfig
    "

This ebuild demonstrates the absolute minimum working code.  Only
the three highlighted lines are specific to Python eclasses, plus
the implicitly exported ``pkg_setup`` phase.


.. index:: python_gen_any_dep; python-any-r1
.. index:: python_check_deps; python-any-r1
.. index:: PYTHON_USEDEP; python-any-r1
.. index:: python_has_version

Dependencies
============
When depending on other Python packages, USE dependencies need to be
declared in order to ensure that the dependencies would be built against
the Python implementation used for the package.  When Python
dependencies need to be specified, ``${PYTHON_DEPS}`` gets replaced
by a call to ``python_gen_any_dep`` generator and a matching
``python_check_deps()`` function.

The ``python_gen_any_dep`` function accepts a template where literal
``${PYTHON_USEDEP}`` is substituted with appropriate USE dependency.
It generates an any-of (``||``) dependency that requires all
the packages to use the same Python interpreter, for at least one
of the supported implementations.

The ``python_check_deps()`` function needs to be declared by ebuild
in order to test whether the implementation in question is suitable
for building the package.  In particular, it needs to verify whether
the particular branch of the any-of was satisfied, or whether all
dependencies were installed for the current interpreter.  For that
purpose, the function is called with ``PYTHON_USEDEP`` variable declared
to the USE dependency string for the currently tested implementation.

This is best explained using an example:

.. code-block:: bash
   :emphasize-lines: 19-22,25-28

    # Copyright 1999-2020 Gentoo Authors
    # Distributed under the terms of the GNU General Public License v2

    EAPI=6
    PYTHON_COMPAT=( python3_{6,7,8} )

    inherit meson python-any-r1

    DESCRIPTION="A file manager for Cinnamon, forked from Nautilus"
    HOMEPAGE="http://developer.linuxmint.com/projects/cinnamon-projects.html"
    SRC_URI="https://github.com/linuxmint/nemo/archive/${PV}.tar.gz -> ${P}.tar.gz"

    LICENSE="GPL-2+ LGPL-2+ FDL-1.1"
    SLOT="0"
    KEYWORDS="amd64 x86"
    IUSE=""

    DEPEND="
        $(python_gen_any_dep '
            dev-python/polib[${PYTHON_USEDEP}]
            dev-python/pygobject:3[${PYTHON_USEDEP}]
        ')
    "

    python_check_deps() {
        python_has_version "dev-python/polib[${PYTHON_USEDEP}]" &&
        python_has_version "dev-python/pygobject:3[${PYTHON_USEDEP}]"
    }

This means that the package will work with Python 3.6, 3.7 or 3.8,
provided that its both dependencies have the same implementation
enabled.  The generated ``||`` dep ensures that this is true for
at least one of them, while ``python_check_deps()`` verifies which
branch was satisfied.

The eclass provides a ``python_has_version`` wrapper that helps
verifying whether the dependencies are installed.  The wrapper takes
a single optional dependency class flag, followed by one or more package
dependencies.  Similarly to EAPI 7+ ``has_version``, the root flag
can be ``-b`` (for packages from ``BDEPEND``), ``-d`` (for ``DEPEND``)
or ``-r`` (for ``RDEPEND``, ``IDEPEND`` and ``PDEPEND``).  When no flag
is passed, ``-b`` is assumed.  The wrapper verifies whether
the specified packages are installed, verbosely printing the checks
performed and their results.  It returns success if all packages were
found, false otherwise.

Note that when multiple invocations are used, ``&&`` needs to be used
to chain the results.  The example above can be also written as::

    python_check_deps() {
        python_has_version \
            "dev-python/polib[${PYTHON_USEDEP}]" \
            "dev-python/pygobject:3[${PYTHON_USEDEP}]"
    }

It is important to understand that this works correctly only if
``python_gen_any_dep`` and ``python_check_deps()`` match exactly.
Furthermore, for any USE flag combination ``python_gen_any_dep`` must be
called at most once.  In particular, it is invalid to split the above
example into multiple ``python_gen_any_dep`` calls.


Conditional Python use
======================
In some packages, Python is only necessary with specific USE flag
combinations.  This is particularly common when Python is used for
the test suite.  In that case, the dependencies and ``pkg_setup`` call
need to be wrapped in appropriate USE conditions:

.. code-block:: bash
   :emphasize-lines: 16,17,21-27,35

    # Copyright 1999-2020 Gentoo Authors
    # Distributed under the terms of the GNU General Public License v2

    EAPI=7

    PYTHON_COMPAT=( python3_{6,7} )
    inherit python-any-r1

    DESCRIPTION="Programmable Completion for bash"
    HOMEPAGE="https://github.com/scop/bash-completion"
    SRC_URI="https://github.com/scop/bash-completion/releases/download/${PV}/${P}.tar.xz"

    LICENSE="GPL-2+"
    SLOT="0"
    KEYWORDS="~alpha amd64 arm ~arm64 ~hppa ia64 ~mips ppc ~ppc64 ~s390 ~sh sparc x86 ~amd64-linux ~x86-linux ~ppc-macos ~x64-macos ~x86-macos ~m68k-mint ~sparc-solaris ~sparc64-solaris"
    IUSE="test"
    RESTRICT="!test? ( test )"

    RDEPEND=">=app-shells/bash-4.3_p30-r1:0"
    DEPEND="
        test? (
            ${RDEPEND}
            $(python_gen_any_dep '
                dev-python/pexpect[${PYTHON_USEDEP}]
                dev-python/pytest[${PYTHON_USEDEP}]
            ')
        )"

    python_check_deps() {
        python_has_version -d "dev-python/pexpect[${PYTHON_USEDEP}]" &&
        python_has_version -d "dev-python/pytest[${PYTHON_USEDEP}]"
    }

    pkg_setup() {
        use test && python-any-r1_pkg_setup
    }


Additional conditional dependencies
===================================
Another possible case is that Python is required unconditionally
but some dependencies are required only conditionally to USE flags.
The simplest way to achieve that is to use ``${PYTHON_DEPS}`` globally
and ``python_gen_any_dep`` in USE-conditional block, then express
a similar condition in ``python_check_deps()``:

.. code-block:: bash
   :emphasize-lines: 16,19-24,27-30

    # Copyright 1999-2020 Gentoo Authors
    # Distributed under the terms of the GNU General Public License v2

    EAPI=7

    PYTHON_COMPAT=( python3_{6,7} )
    inherit python-any-r1 cmake

    DESCRIPTION="Qt bindings for the Telepathy D-Bus protocol"
    HOMEPAGE="https://telepathy.freedesktop.org/"
    SRC_URI="https://telepathy.freedesktop.org/releases/${PN}/${P}.tar.gz"

    LICENSE="LGPL-2.1"
    SLOT="0"
    KEYWORDS="amd64 ~arm arm64 x86"
    IUSE="test"
    RESTRICT="!test? ( test )"

    BDEPEND="${PYTHON_DEPS}
        test? (
            $(python_gen_any_dep '
                dev-python/dbus-python[${PYTHON_USEDEP}]
            ')
        )
    "

    python_check_deps() {
        use test || return 0
        python_has_version -b "dev-python/dbus-python[${PYTHON_USEDEP}]"
    }


Multiple sets of conditional dependencies
=========================================
The hardest case for this eclass is to declare multiple Python
dependencies conditional to different USE flags.  While there are
multiple possible ways of doing that, the least error-prone is to move
USE conditional blocks inside ``python_gen_any_dep``:

.. code-block:: bash
   :emphasize-lines: 15,21-27,30-36,39

    # Copyright 1999-2020 Gentoo Authors
    # Distributed under the terms of the GNU General Public License v2

    EAPI=6
    PYTHON_COMPAT=( python3_6 )

    inherit gnome2 python-any-r1

    DESCRIPTION="GObject library for accessing the freedesktop.org Secret Service API"
    HOMEPAGE="https://wiki.gnome.org/Projects/Libsecret"

    LICENSE="LGPL-2.1+ Apache-2.0" # Apache-2.0 license is used for tests only
    SLOT="0"
    KEYWORDS="~alpha amd64 arm arm64 ia64 ~mips ppc ppc64 sparc x86"
    IUSE="+introspection test"
    RESTRICT="!test? ( test )"
    # Tests fail with USE=-introspection, https://bugs.gentoo.org/655482
    REQUIRED_USE="test? ( introspection )"

    DEPEND="
        test? (
            $(python_gen_any_dep '
                dev-python/mock[${PYTHON_USEDEP}]
                dev-python/dbus-python[${PYTHON_USEDEP}]
                introspection? ( dev-python/pygobject:3[${PYTHON_USEDEP}] )
            ')
        )
    "

    python_check_deps() {
        if use introspection; then
            python_has_version "dev-python/pygobject:3[${PYTHON_USEDEP}]" || return 1
        fi
        python_has_version "dev-python/mock[${PYTHON_USEDEP}]" &&
        python_has_version --host-root "dev-python/dbus-python[${PYTHON_USEDEP}]"
    }

    pkg_setup() {
        use test && python-any-r1_pkg_setup
    }


.. _python-any-r1.eclass(5):
   https://devmanual.gentoo.org/eclass-reference/python-any-r1.eclass/index.html