Skip to content

Commit 03c676a

Browse files
committed
More recipe doc
1 parent 3981103 commit 03c676a

File tree

1 file changed

+156
-1
lines changed

1 file changed

+156
-1
lines changed

doc/source/recipes.rst

Lines changed: 156 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,165 @@ though may need to use the arch name ``arch.arch``.
8484
.. note:: You can also implement arch-specific versions of each
8585
method, which are called (if they exist) by the superclass,
8686
e.g. ``def prebuild_armeabi(self, arch)``.
87+
8788

89+
This is the core of what's necessary to write a recipe, but has not
90+
covered any of the details of how one actually writes code to compile
91+
for android. This is covered in the next sections, including the
92+
`standard mechanisms <standard_mechanisms_>`_ used as part of the
93+
build, and the details of specific recipe classes for Python, Cython,
94+
and some generic compiled recipes. If your module is one of the
95+
latter, you should use these later classes rather than reimplementing
96+
the functionality from scratch.
8897

89-
.. _recipe_class:
98+
.. _standard_mechanisms:
99+
100+
Methods and tools to help with compilation
101+
------------------------------------------
102+
103+
Patching modules before installation
104+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
105+
106+
You can easily apply patches to your recipes with the ``apply_patch``
107+
method. For instance, you could do this in your prebuild method::
108+
109+
import sh
110+
def prebuild_arch(self, arch):
111+
super(YourRecipe, self).prebuild_arch(arch)
112+
build_dir = self.get_build_dir(arch.arch)
113+
if exists(join(build_dir, '.patched')):
114+
print('Your recipe is already patched, skipping')
115+
return
116+
self.apply_patch('some_patch.patch')
117+
shprint(sh.touch, join(build_dir, '.patched'))
118+
119+
The path to the patch should be in relation to your recipe code.
120+
In this case, ``some_path.patch`` must be in the same directory as the
121+
recipe.
122+
123+
This code also manually takes care to patch only once. You can use the
124+
same strategy yourself, though a more generic solution may be provided
125+
in the future.
126+
127+
Compiling for the Android architecture
128+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
129+
130+
When performing any compilation, it is vital to do so with appropriate
131+
environment variables set, ensuring that the Android libraries are
132+
properly linked and the compilation target is the correct
133+
architecture.
134+
135+
You can get a dictionary of appropriate environment variables with the
136+
``get_recipe_env`` method. You should make sure to set this
137+
environment for any processes that you call. It is convenient to do
138+
this using the ``sh`` module as follows::
139+
140+
def build_arch(self, arch):
141+
super(YourRecipe, self).build_arch(arch)
142+
env = self.get_recipe_env(arch)
143+
sh.echo('$PATH', _env=env) # Will print the PATH entry fron the
144+
# env dict
145+
146+
You can also use the ``shprint`` helper function from the p4a
147+
toolchain module, which will print information about the process and
148+
its current status::
149+
150+
from toolchain import shprint
151+
shprint(sh.echo, '$PATH', _env=env)
152+
153+
You can also override the ``get_recipe_env`` method to add new env
154+
vars for the use of your recipe. For instance, the Kivy recipe does
155+
the following when compiling for SDL2, in order to tell Kivy what
156+
backend to use::
157+
158+
def get_recipe_env(self, arch):
159+
env = super(KivySDL2Recipe, self).get_recipe_env(arch)
160+
env['USE_SDL2'] = '1'
161+
162+
env['KIVY_SDL2_PATH'] = ':'.join([
163+
join(self.ctx.bootstrap.build_dir, 'jni', 'SDL', 'include'),
164+
join(self.ctx.bootstrap.build_dir, 'jni', 'SDL2_image'),
165+
join(self.ctx.bootstrap.build_dir, 'jni', 'SDL2_mixer'),
166+
join(self.ctx.bootstrap.build_dir, 'jni', 'SDL2_ttf'),
167+
])
168+
return env
169+
170+
.. warning:: When using the sh module like this the new env *completely
171+
replaces* the normal environment, so you must define any env
172+
vars you want to access.
173+
174+
Including files with your recipe
175+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
176+
177+
The should_build method
178+
~~~~~~~~~~~~~~~~~~~~~~~
179+
180+
181+
Using a PythonRecipe
182+
--------------------
183+
184+
If your recipe is to install a Python module without compiled
185+
components, you should use a PythonRecipe. This overrides
186+
``build_arch`` to automatically call the normal ``python setup.py
187+
install`` with an appropriate environment.
188+
189+
For instance, the following is all that's necessary to create a recipe
190+
for the Vispy module::
191+
192+
from toolchain import PythonRecipe
193+
class VispyRecipe(PythonRecipe):
194+
version = 'master'
195+
url = 'https://github.com/vispy/vispy/archive/{version}.zip'
196+
197+
depends = ['python2', 'numpy']
198+
199+
site_packages_name = 'vispy'
200+
201+
recipe = VispyRecipe()
202+
203+
The ``site_packages_name`` is a new attribute that identifies the
204+
folder in which the module will be installed in the Python
205+
package. This is only essential to add if the name is different to the
206+
recipe name. It is used to check if the recipe installation can be
207+
skipped, which is the case if the folder is already present in the
208+
Python installation.
209+
210+
For reference, the code that accomplishes this is the following::
211+
212+
def build_arch(self, arch):
213+
super(PythonRecipe, self).build_arch(arch)
214+
self.install_python_package()
90215

216+
def install_python_package(self):
217+
'''Automate the installation of a Python package (or a cython
218+
package where the cython components are pre-built).'''
219+
arch = self.filtered_archs[0]
220+
env = self.get_recipe_env(arch)
221+
222+
info('Installing {} into site-packages'.format(self.name))
223+
224+
with current_directory(self.get_build_dir(arch.arch)):
225+
hostpython = sh.Command(self.ctx.hostpython)
226+
227+
shprint(hostpython, 'setup.py', 'install', '-O2', _env=env)
228+
229+
This combines techniques and tools from the above documentation to
230+
create a generic mechanism for all Python modules.
231+
232+
.. note:: The hostpython is the path to the Python binary that should
233+
be used for any kind of installation. You *must* run Python
234+
in a similar way if you need to do so in any of your own
235+
recipes.
236+
237+
238+
Using a CythonRecipe
239+
--------------------
240+
241+
Using a CompiledComponentsPythonRecipe
242+
--------------------------------------
243+
244+
245+
.. _recipe_class:
91246

92247
The ``Recipe`` class
93248
--------------------

0 commit comments

Comments
 (0)