@@ -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
92247The ``Recipe `` class
93248--------------------
0 commit comments