Skip to content

Commit 3981103

Browse files
committed
Added some more doc
1 parent c042198 commit 3981103

File tree

4 files changed

+195
-38
lines changed

4 files changed

+195
-38
lines changed

doc/source/commands.rst

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,47 @@ Commands
44

55
This page documents all the commands and options that can be passed to
66
toolchain.py.
7+
8+
9+
Main commands
10+
-------------
11+
12+
.. autoclass:: toolchain.ToolchainCL
13+
:members:
14+
15+
16+
General arguments
17+
-----------------
18+
19+
These arguments may be passed to any command in order to modify its behaviour.
20+
21+
``--debug``
22+
Print extra debug information about the build, including all compilation output.
23+
24+
25+
Distribution arguments
26+
----------------------
27+
28+
p4a supports several arguments used for specifying which compiled
29+
Android distribution you want to use. You may pass any of these
30+
arguments to any command, and if a distribution is required they will
31+
be used to load, or compile, or download this as necessary.
32+
33+
None of these options are essential, and in principle you need only
34+
supply those that you need.
35+
36+
37+
``--name NAME``
38+
The name of the distribution. Only one distribution with a given name can be created.
39+
40+
``--requirements LIST,OF,REQUIREMENTS``
41+
The recipes that your
42+
distribution must contain, as a comma separated list. These must be
43+
names of recipes or the pypi names of Python modules.
44+
45+
``--force_build BOOL``
46+
Whether the distribution must be compiled from scratch.
47+
48+
.. note:: These options are preliminary. Others will include toggles
49+
for allowing downloads, and setting additional directories
50+
from which to load user dists.

doc/source/conf.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
# documentation root, use os.path.abspath to make it absolute, like shown here.
2222
#sys.path.insert(0, os.path.abspath('.'))
2323
sys.path.append(os.path.abspath('ext/sphinx_rtd_theme'))
24+
sys.path.append(os.path.abspath('../../pythonforandroid'))
2425

2526
import sphinx_rtd_theme
2627

doc/source/recipes.rst

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,91 @@ compiled components; if you just want to build an APK, you can jump
1414
straight to the :doc:`quickstart` or :doc:`commands` documentation, or
1515
can use the :code:`recipes` command to list available recipes.
1616

17-
This page describes how recipes work, and how to make your own.
17+
18+
Creating your own Recipe
19+
------------------------
20+
21+
This documentation jumps straight to the practicalities of creating
22+
your own recipe. The formal reference documentation of the Recipe
23+
class can be found in the `Recipe class <recipe_class_>`_ section and below.
24+
25+
The basic declaration of a recipe is as follows::
26+
27+
class YourRecipe(Recipe):
28+
29+
url = 'http://example.com/example-{version}.tar.gz'
30+
version = '2.0.3'
31+
md5sum = '4f3dc9a9d857734a488bcbefd9cd64ed'
32+
33+
depends = ['kivy', 'sdl2'] # These are just examples
34+
conflicts = ['pygame']
35+
36+
See the `Recipe class documentation <recipe_class_>`_ for full
37+
information about each parameter.
38+
39+
These core options are vital for all recipes, though the url may be
40+
omitted if the source is somehow loaded from elsewhere.
41+
42+
.. note:: The url includes the ``{version}`` tag. You should only
43+
access the url with the ``versioned_url`` property, which
44+
replaces this with the version attribute.
45+
46+
The actual build process takes place via three core methods::
47+
48+
def prebuild_arch(self, arch):
49+
super(YourRecipe, self).prebuild_arch(arch)
50+
# Do any pre-initialisation
51+
52+
def build_arch(self, arch):
53+
super(YourRecipe, self).build_arch(arch)
54+
# Do the main recipe build
55+
56+
def postbuild_arch(self, arch):
57+
super(YourRecipe, self).build_arch(arch)
58+
# Do any clearing up
59+
60+
The prebuild of every recipe is run before the build of any recipe,
61+
and likewise the build of every recipe is run before the postbuild of
62+
any. This lets you strictly order the build process.
63+
64+
If you defined an url for your recipe, you do *not* need to manually
65+
download it, this is handled automatically.
66+
67+
The recipe will automatically be built in a special isolated build
68+
directory, which you can access with
69+
:code:`self.get_build_dir(arch.arch)`. You should only work within
70+
this directory. It may be convenient to use the ``current_directory``
71+
context manager defined in toolchain.py::
72+
73+
from toolchain import current_directory
74+
def build_arch(self, arch):
75+
super(YourRecipe, self).build_arch(arch)
76+
with current_directory(self.get_build_dir(arch.arch)):
77+
with open('example_file.txt', 'w'):
78+
fileh.write('This is written to a file within the build dir')
79+
80+
The argument to each method, ``arch``, is an object relating to the
81+
architecture currently being built for. You can mostly ignore it,
82+
though may need to use the arch name ``arch.arch``.
83+
84+
.. note:: You can also implement arch-specific versions of each
85+
method, which are called (if they exist) by the superclass,
86+
e.g. ``def prebuild_armeabi(self, arch)``.
87+
88+
89+
.. _recipe_class:
90+
91+
92+
The ``Recipe`` class
93+
--------------------
94+
95+
The ``Recipe`` is the base class for all p4a recipes. The core
96+
documentation of this class is given below, followed by discussion of
97+
how to create your own Recipe subclass.
98+
99+
.. autoclass:: toolchain.Recipe
100+
:members:
101+
:member-order: = 'bysource'
102+
103+
18104

pythonforandroid/toolchain.py

Lines changed: 63 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -684,8 +684,8 @@ def get_distribution(cls, ctx, name=None, recipes=[], allow_download=True,
684684
if force_build:
685685
continue
686686
if (set(dist.recipes) == set(recipes) or
687-
(set(recipes).issubset(set(dist.recipes) and not require_perfect_match))):
688-
info('{} has exactly the right recipes, using this one')
687+
(set(recipes).issubset(set(dist.recipes)) and not require_perfect_match)):
688+
info('{} has exactly the right recipes, using this one'.format(dist.name))
689689
return dist
690690

691691
assert len(possible_dists) < 2
@@ -894,33 +894,57 @@ def get_bootstrap(cls, name, ctx):
894894

895895

896896
class Recipe(object):
897-
version = None
898897
url = None
898+
'''The address from which the recipe may be downloaded. This is not
899+
essential, it may be omitted if the source is available some other
900+
way, such as via the :class:`IncludedFilesBehaviour` mixin.
901+
902+
If the url includes the version, you may (and probably should)
903+
replace this with ``{version}``, which will automatically be
904+
replaced by the :attr:`version` string during download.
905+
906+
.. note:: Methods marked (internal) are used internally and you
907+
probably don't need to call them, but they are available
908+
if you want.
909+
'''
910+
911+
version = None
912+
'''A string giving the version of the software the recipe describes,
913+
e.g. ``2.0.3`` or ``master``.'''
914+
915+
899916
md5sum = None
917+
'''The md5sum of the source from the :attr:`url`. Non-essential, but
918+
you should try to include this, it is used to check that the download
919+
finished correctly.
920+
'''
921+
900922
depends = []
923+
'''A list containing the names of any recipes that this recipe depends on.
924+
'''
925+
901926
conflicts = []
902-
903-
name = None # name for the recipe dir
927+
# AND: Not currently used
928+
'''A list containing the names of any recipes that are known to be
929+
incompatible with this one.'''
930+
931+
# name = None # name for the recipe dir
904932

905933
archs = ['armeabi'] # will android use this?
906934

907-
# library = None
908-
# libraries = []
909-
# include_dir = None
910-
# include_per_arch = False
911-
# frameworks = []
912-
# sources = []
913935

914936
@property
915937
def versioned_url(self):
938+
'''A property returning the url of the recipe with ``{version}``
939+
replaced by the :attr:`url`. If accessing the url, you should use this
940+
property, *not* access the url directly.'''
916941
if self.url is None:
917942
return None
918943
return self.url.format(version=self.version)
919944

920-
# API available for recipes
921945
def download_file(self, url, filename, cwd=None):
922946
"""
923-
Download an `url` to `outfn`
947+
(internal) Download an ``url`` to a ``filename``.
924948
"""
925949
if not url:
926950
return
@@ -944,7 +968,7 @@ def report_hook(index, blksize, size):
944968

945969
def extract_file(self, filename, cwd):
946970
"""
947-
Extract the `filename` into the directory `cwd`.
971+
(internal) Extract the `filename` into the directory `cwd`.
948972
"""
949973
if not filename:
950974
return
@@ -961,7 +985,7 @@ def extract_file(self, filename, cwd):
961985
zf.close()
962986

963987
else:
964-
warning("Error: cannot extract, unreconized extension for {}".format(
988+
warning("Error: cannot extract, unrecognized extension for {}".format(
965989
filename))
966990
raise Exception()
967991

@@ -1206,25 +1230,25 @@ def get_recipe_env(self, arch=None):
12061230
# self.ctx.state[key] = value
12071231
# return value
12081232

1209-
def execute(self):
1210-
if self.custom_dir:
1211-
self.ctx.state.remove_all(self.name)
1212-
self.download()
1213-
self.extract()
1214-
self.build_all()
1233+
# def execute(self):
1234+
# if self.custom_dir:
1235+
# self.ctx.state.remove_all(self.name)
1236+
# self.download()
1237+
# self.extract()
1238+
# self.build_all()
12151239

12161240
# AND: Will need to change how this works
1217-
@property
1218-
def custom_dir(self):
1219-
"""Check if there is a variable name to specify a custom version /
1220-
directory to use instead of the current url.
1221-
"""
1222-
d = environ.get("P4A_{}_DIR".format(self.name.lower()))
1223-
if not d:
1224-
return
1225-
if not exists(d):
1226-
return
1227-
return d
1241+
# @property
1242+
# def custom_dir(self):
1243+
# """Check if there is a variable name to specify a custom version /
1244+
# directory to use instead of the current url.
1245+
# """
1246+
# d = environ.get("P4A_{}_DIR".format(self.name.lower()))
1247+
# if not d:
1248+
# return
1249+
# if not exists(d):
1250+
# return
1251+
# return d
12281252

12291253
# def prebuild(self):
12301254
# self.prebuild_arch(self.ctx.archs[0]) # AND: Need to change
@@ -1738,6 +1762,7 @@ def dist_from_args(ctx, dist_args):
17381762
def split_argument_list(l):
17391763
return re.split(r'[ ,]*', l)
17401764

1765+
17411766
class ToolchainCL(object):
17421767
def __init__(self):
17431768
parser = argparse.ArgumentParser(
@@ -1926,13 +1951,14 @@ def create(self, args):
19261951

19271952
print('dists are', Distribution.get_distributions(ctx))
19281953
dist = dist_from_args(ctx, self.dist_args)
1929-
info('Ready to create dist {}, contains recipes {}'.format(
1930-
dist.name, ', '.join(dist.recipes)))
19311954
if not dist.needs_build:
1932-
info('This dist already exists! If you dont\'t want to use '
1933-
'it, you must delete it and rebuild with the new set of '
1934-
'recipes, or create your new dist with a different name.')
1955+
info('You asked to create a distribution, but a dist with this name '
1956+
'already exists. If you don\'t want to use '
1957+
'it, you must delete it and rebuild, or create your '
1958+
'new dist with a different name.')
19351959
exit(1)
1960+
info('Ready to create dist {}, contains recipes {}'.format(
1961+
dist.name, ', '.join(dist.recipes)))
19361962

19371963
bs = Bootstrap.get_bootstrap(args.bootstrap, ctx)
19381964
info_main('# Creating dist with with {} bootstrap'.format(bs.name))

0 commit comments

Comments
 (0)