Skip to content

Commit 3596c2f

Browse files
committed
Improved dependency graph and merged recipes
1 parent dca5468 commit 3596c2f

File tree

7 files changed

+109
-41
lines changed

7 files changed

+109
-41
lines changed

pythonforandroid/recipes/kivy/__init__.py

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,33 @@
66

77

88
class KivyRecipe(CythonRecipe):
9-
version = 'stable'
9+
# version = 'stable'
10+
version = 'master'
1011
url = 'https://github.com/kivy/kivy/archive/{version}.zip'
1112
name = 'kivy'
1213

13-
depends = ['pygame', 'pyjnius', 'android']
14+
depends = [('sdl2', 'pygame'), 'pyjnius']
1415

16+
def prebuild_arch(self, arch):
17+
super(KivyRecipe, self).prebuild_arch(arch)
18+
if 'sdl2' in self.ctx.recipe_build_order:
19+
build_dir = self.get_build_dir(arch.arch)
20+
if exists(join(build_dir, '.patched')):
21+
print('kivysdl2 already patched, skipping')
22+
return
23+
self.apply_patch('android_sdl2_compat.patch')
24+
shprint(sh.touch, join(build_dir, '.patched'))
25+
26+
def get_recipe_env(self, arch):
27+
env = super(KivyRecipe, self).get_recipe_env(arch)
28+
if 'sdl2' in self.ctx.recipe_build_order:
29+
env['USE_SDL2'] = '1'
30+
env['KIVY_SDL2_PATH'] = ':'.join([
31+
join(self.ctx.bootstrap.build_dir, 'jni', 'SDL', 'include'),
32+
join(self.ctx.bootstrap.build_dir, 'jni', 'SDL2_image'),
33+
join(self.ctx.bootstrap.build_dir, 'jni', 'SDL2_mixer'),
34+
join(self.ctx.bootstrap.build_dir, 'jni', 'SDL2_ttf'),
35+
])
36+
return env
1537

1638
recipe = KivyRecipe()

pythonforandroid/recipes/pyjnius/__init__.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,17 @@ class PyjniusRecipe(CythonRecipe):
99
version = 'master'
1010
url = 'https://github.com/kivy/pyjnius/archive/{version}.zip'
1111
name = 'pyjnius'
12-
depends = ['python2', 'sdl']
12+
depends = ['python2', ('sdl2', 'sdl')]
1313
site_packages_name = 'jnius'
14+
def prebuild_arch(self, arch):
15+
super(PyjniusRecipe, self).prebuild_arch(arch)
16+
if 'sdl2' in self.ctx.recipe_build_order:
17+
build_dir = self.get_build_dir(arch.arch)
18+
if exists(join(build_dir, '.patched')):
19+
print('pyjniussdl2 already pathed, skipping')
20+
return
21+
self.apply_patch('sdl2_jnienv_getter.patch')
22+
shprint(sh.touch, join(build_dir, '.patched'))
1423

1524
def postbuild_arch(self, arch):
1625
super(PyjniusRecipe, self).postbuild_arch(arch)

pythonforandroid/recipes/sdl/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ class LibSDLRecipe(NDKRecipe):
77
url = None
88
name = 'sdl'
99
depends = ['python2', 'pygame_bootstrap_components']
10+
conflicts = ['sdl2']
1011

1112
def build_armeabi(self):
1213

pythonforandroid/recipes/sdl2/__init__.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,22 @@
1-
from pythonforandroid.toolchain import NDKRecipe, shprint, current_directory, info_main
1+
from pythonforandroid.toolchain import NDKRecipe, shprint, current_directory, info
22
from os.path import exists, join
33
import sh
44

55

6-
76
class LibSDL2Recipe(NDKRecipe):
87
version = "2.0.3"
98
url = "https://www.libsdl.org/release/SDL2-{version}.tar.gz"
109

1110
dir_name = 'SDL'
1211

1312
depends = ['python2', 'sdl2_image', 'sdl2_mixer', 'sdl2_ttf']
14-
conflicts = ['pygame', 'pygame_bootstrap_components']
13+
conflicts = ['sdl', 'pygame', 'pygame_bootstrap_components']
1514

1615
def prebuild_arch(self, arch):
1716
super(LibSDL2Recipe, self).prebuild_arch(arch)
1817
build_dir = self.get_build_dir(arch.arch)
1918
if exists(join(build_dir, '.patched')):
20-
print('SDL2 already patched, skipping')
19+
info('SDL2 already patched, skipping')
2120
return
2221
self.apply_patch('add_nativeSetEnv.patch')
2322
shprint(sh.touch, join(build_dir, '.patched'))

pythonforandroid/recipes/sdl2_image/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from pythonforandroid.toolchain import NDKRecipe, shprint
1+
from pythonforandroid.toolchain import NDKRecipe, shprint, info
22
from os.path import exists, join
33
import sh
44

@@ -11,7 +11,7 @@ def prebuild_arch(self, arch):
1111
super(LibSDL2Image, self).prebuild_arch(arch)
1212
build_dir = self.get_build_dir(arch.arch)
1313
if exists(join(build_dir, '.patched')):
14-
print('SDL2_image already patched, skipping')
14+
info('SDL2_image already patched, skipping')
1515
return
1616
self.apply_patch('disable_webp.patch')
1717
shprint(sh.touch, join(build_dir, '.patched'))

pythonforandroid/recipes/sdl2_mixer/__init__.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
2-
from pythonforandroid.toolchain import NDKRecipe, shprint
1+
from pythonforandroid.toolchain import NDKRecipe, shprint, info
32
from os.path import exists, join
43
import sh
54

@@ -13,7 +12,7 @@ def prebuild_arch(self, arch):
1312
build_dir = self.get_build_dir(arch.arch)
1413

1514
if exists(join(build_dir, '.patched')):
16-
print('SDL2_mixer already patched, skipping')
15+
info('SDL2_mixer already patched, skipping')
1716
return
1817
self.apply_patch('disable_modplug_mikmod_smpeg.patch')
1918
shprint(sh.touch, join(build_dir, '.patched'))

pythonforandroid/toolchain.py

Lines changed: 67 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,8 @@ def shprint(command, *args, **kwargs):
127127
need_closing_newline = False
128128
for line in output:
129129
if logger.level > logging.DEBUG:
130-
string = '\r' + ' '*11 + 'working ... ' + line[:100].replace('\n', '').rstrip() + ' ...'
130+
string = ''.join([Style.RESET_ALL, '\r', ' '*11, 'working ... ',
131+
line[:100].replace('\n', '').rstrip(), ' ...'])
131132
if len(string) < 20:
132133
continue
133134
if len(string) < 120:
@@ -431,18 +432,18 @@ def remove_redundant_graphs(self):
431432
for j in range(1, len(graphs)):
432433
comparison_graph = graphs[initial_num_graphs - 1 - j]
433434
if set(comparison_graph.keys()) == set(graph.keys()):
434-
graphs.pop([initial_num_graphs - 1 - i])
435+
graphs.pop(initial_num_graphs - 1 - i)
435436
break
436437

437438
def add(self, dependent, dependency):
438439
"""Add a dependency relationship to the graph"""
439440
if isinstance(dependency, (tuple, list)):
440-
for graph in self.graphs:
441-
self._add(graph, dependent, dependency[0])
441+
for graph in self.graphs[:]:
442442
for dep in dependency[1:]:
443443
new_graph = deepcopy(graph)
444444
self._add(new_graph, dependent, dep)
445445
self.graphs.append(new_graph)
446+
self._add(graph, dependent, dependency[0])
446447
else:
447448
for graph in self.graphs:
448449
self._add(graph, dependent, dependency)
@@ -462,10 +463,24 @@ def conflicts(self, conflict):
462463
for i in range(len(graphs)):
463464
graph = graphs[len(graphs) - 1 - i]
464465
if conflict in graph:
465-
print('conflict in graph', conflict, graph)
466-
graphs.pop([len(graphs) - 1 - i])
466+
graphs.pop(len(graphs) - 1 - i)
467467
return len(graphs) == 0
468468

469+
def remove_remaining_conflicts(self, ctx):
470+
# It's unpleasant to have to pass ctx as an argument...
471+
'''Checks all possible graphs for conflicts that have arisen during
472+
the additon of alternative repice branches, as these are not checked
473+
for conflicts at the time.'''
474+
new_graphs = []
475+
for i, graph in enumerate(self.graphs):
476+
for name in graph.keys():
477+
recipe = Recipe.get_recipe(name, ctx)
478+
if any([c in graph for c in recipe.conflicts]):
479+
break
480+
else:
481+
new_graphs.append(graph)
482+
self.graphs = new_graphs
483+
469484
def add_optional(self, dependent, dependency):
470485
"""Add an optional (ordering only) dependency relationship to the graph
471486
@@ -907,8 +922,6 @@ def get_libs_dir(self, arch):
907922
'''The libs dir for a given arch.'''
908923
ensure_dir(join(self.libs_dir, arch))
909924
# AND: See warning:
910-
warning('Ensuring libs dir in get_libs_dir, should fix this '
911-
'to ensure elsewhere')
912925
return join(self.libs_dir, arch)
913926

914927

@@ -1261,19 +1274,14 @@ class Recipe(object):
12611274
'''
12621275

12631276
conflicts = []
1264-
# AND: Not currently used, needs modifications to the dependency Graph
12651277
'''A list containing the names of any recipes that are known to be
12661278
incompatible with this one.'''
12671279

1268-
# patches = []
1269-
# '''Filepaths (relative to the recipe script) for any pathches that are
1270-
# to be applied. By default, these are applied in prebuild_arch, so
1271-
# if you override this but want to use patches then don't forget to
1272-
# call super().
1280+
opt_depends = []
1281+
'''A list of optional dependencies, that must be built before this
1282+
recipe if they are built at all, but whose presence is not essential.'''
12731283

1274-
# name = None # name for the recipe dir
1275-
1276-
archs = ['armeabi'] # will android use this?
1284+
archs = ['armeabi'] # Not currently implemented properly
12771285

12781286

12791287
@property
@@ -1417,9 +1425,32 @@ def filtered_archs(self):
14171425
result.append(arch)
14181426
return result
14191427

1428+
def check_recipe_choices(self):
1429+
'''Checks what recipes are being built to see which of the alternative
1430+
and optional dependencies are being used, and returns a list of these.'''
1431+
recipes = []
1432+
built_recipes = self.ctx.recipe_build_order
1433+
for recipe in self.depends:
1434+
if isinstance(recipe, (tuple, list)):
1435+
for alternative in recipe:
1436+
if alternative in built_recipes:
1437+
recipes.append(alternative)
1438+
break
1439+
for recipe in self.opt_depends:
1440+
if recipe in built_recipes:
1441+
recipes.append(recipe)
1442+
return sorted(recipes)
1443+
14201444
def get_build_container_dir(self, arch):
1421-
'''Given the arch name, returns the directory where it will be built.'''
1422-
return join(self.ctx.build_dir, 'other_builds', self.name, arch)
1445+
'''Given the arch name, returns the directory where it will be
1446+
built.
1447+
1448+
This returns a different directory depending on what
1449+
alternative or optional dependencies are being built.
1450+
'''
1451+
choices = self.check_recipe_choices()
1452+
dir_name = '-'.join([self.name] + choices)
1453+
return join(self.ctx.build_dir, 'other_builds', dir_name, arch)
14231454

14241455
def get_build_dir(self, arch):
14251456
'''Given the arch name, returns the directory where the
@@ -1616,7 +1647,7 @@ def prebuild_arch(self, arch):
16161647
if hasattr(self, prebuild):
16171648
getattr(self, prebuild)()
16181649
else:
1619-
print('{} has no {}, skipping'.format(self.name, prebuild))
1650+
info('{} has no {}, skipping'.format(self.name, prebuild))
16201651

16211652
def should_build(self):
16221653
'''Should perform any necessary test and return True only if it needs
@@ -1928,7 +1959,7 @@ def build_recipes(names, ctx):
19281959
python_modules = []
19291960
while recipes_to_load:
19301961
name = recipes_to_load.pop(0)
1931-
if name in recipe_loaded:
1962+
if name in recipe_loaded or isinstance(name, (list, tuple)):
19321963
continue
19331964
try:
19341965
recipe = Recipe.get_recipe(name, ctx)
@@ -1947,15 +1978,19 @@ def build_recipes(names, ctx):
19471978
if graph.conflicts(conflict):
19481979
warning(
19491980
('{} conflicts with {}, but both have been '
1950-
'included in the requirements.'.format(recipe.name, conflict)))
1981+
'included or pulled into the requirements.'.format(recipe.name, conflict)))
19511982
warning('Due to this conflict the build cannot continue, exiting.')
19521983
exit(1)
19531984
recipe_loaded.append(name)
1985+
graph.remove_remaining_conflicts(ctx)
19541986
if len(graph.graphs) > 1:
19551987
info('Found multiple valid recipe sets:')
1956-
for graph in graph.graphs:
1957-
info(' {}'.format(graph.keys()))
1988+
for g in graph.graphs:
1989+
info(' {}'.format(g.keys()))
19581990
info_notify('Using the first of these: {}'.format(graph.graphs[0].keys()))
1991+
elif len(graph.graphs) == 0:
1992+
warning('Didn\'t find any valid dependency graphs, exiting.')
1993+
exit(1)
19591994
else:
19601995
info('Found a single valid recipe set (this is good)')
19611996
build_order = list(graph.find_order(0))
@@ -2354,7 +2389,7 @@ def clean_all(self, args):
23542389
bootstrap builds and distributions.'''
23552390
parser = argparse.ArgumentParser(
23562391
description="Clean the build cache, downloads and dists")
2357-
args = parser.parse_args(args)
2392+
parsed_args = parser.parse_args(args)
23582393
ctx = Context()
23592394
self.clean_dists(args)
23602395
self.clean_builds(args)
@@ -2570,10 +2605,13 @@ def distributions(self, args):
25702605
ctx = Context()
25712606
dists = Distribution.get_distributions(ctx)
25722607

2573-
info('{Style.BRIGHT}Distributions currently installed are:'
2574-
'{Style.RESET_ALL}'.format(Style=Style, Fore=Fore))
2575-
2576-
pretty_log_dists(dists)
2608+
if dists:
2609+
info('{Style.BRIGHT}Distributions currently installed are:'
2610+
'{Style.RESET_ALL}'.format(Style=Style, Fore=Fore))
2611+
pretty_log_dists(dists)
2612+
else:
2613+
info('{Style.BRIGHT}There are no dists currently built.'
2614+
'{Style.RESET_ALL}'.format(Style=Style))
25772615

25782616
def delete_dist(self, args):
25792617
dist = self._dist

0 commit comments

Comments
 (0)