diff --git a/recipes/hostpython.py b/recipes/hostpython.py new file mode 100644 index 0000000..3291cc3 --- /dev/null +++ b/recipes/hostpython.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- +from toolchain import Recipe + +class HostpythonAliasRecipe(Recipe): + is_alias = True + + def init_after_import(self, ctx): + hostpython = ctx.state.get("hostpython") + if not hostpython: + print("WARNING: no hostpython set yet, so you need to specify") + print("WARNING: either hostpython2 or hostpython3 in your deps") + else: + self.depends = [hostpython] + +recipe = HostpythonAliasRecipe() diff --git a/recipes/hostpython2/__init__.py b/recipes/hostpython2/__init__.py index 3281a00..bccb7e8 100644 --- a/recipes/hostpython2/__init__.py +++ b/recipes/hostpython2/__init__.py @@ -5,7 +5,7 @@ import sh import shutil -class HostpythonRecipe(Recipe): +class Hostpython2Recipe(Recipe): version = "2.7.1" url = "https://www.python.org/ftp/python/{version}/Python-{version}.tar.bz2" depends = ["hostlibffi"] @@ -13,7 +13,9 @@ class HostpythonRecipe(Recipe): archs = ["x86_64"] def init_with_ctx(self, ctx): - super(HostpythonRecipe, self).init_with_ctx(ctx) + super(Hostpython2Recipe, self).init_with_ctx(ctx) + self.set_hostpython(self, 2.7) + self.ctx.so_suffix = ".so" self.ctx.hostpython = join(self.ctx.dist_dir, "hostpython", "bin", "python") self.ctx.hostpgen = join(self.ctx.dist_dir, "hostpython", "bin", "pgen") print("Global: hostpython located at {}".format(self.ctx.hostpython)) @@ -110,4 +112,4 @@ class HostpythonRecipe(Recipe): join(self.ctx.dist_dir, "hostpython", "bin", "pgen")) -recipe = HostpythonRecipe() +recipe = Hostpython2Recipe() diff --git a/recipes/hostpython3/__init__.py b/recipes/hostpython3/__init__.py index 7d99b86..740dcc9 100644 --- a/recipes/hostpython3/__init__.py +++ b/recipes/hostpython3/__init__.py @@ -14,6 +14,8 @@ class Hostpython3Recipe(Recipe): def init_with_ctx(self, ctx): super(Hostpython3Recipe, self).init_with_ctx(ctx) + self.set_hostpython(self, 3.7) + self.ctx.so_suffix = ".cpython-37m-darwin.so" self.ctx.hostpython = join(self.ctx.dist_dir, "hostpython3", "bin", "python") self.ctx.hostpgen = join(self.ctx.dist_dir, "hostpython3", "bin", "pgen") print("Global: hostpython located at {}".format(self.ctx.hostpython)) diff --git a/recipes/ios/__init__.py b/recipes/ios/__init__.py index af4264d..33a6678 100644 --- a/recipes/ios/__init__.py +++ b/recipes/ios/__init__.py @@ -9,9 +9,8 @@ class IosRecipe(CythonRecipe): pbx_frameworks = ["MessageUI", "CoreMotion", "UIKit"] def install(self): - self.install_python_package(name="ios.so", is_dir=False) + self.install_python_package( + name=self.so_filename("ios"), is_dir=False) recipe = IosRecipe() - - diff --git a/recipes/kivy/__init__.py b/recipes/kivy/__init__.py index 9b9b19d..559e1df 100644 --- a/recipes/kivy/__init__.py +++ b/recipes/kivy/__init__.py @@ -6,8 +6,8 @@ class KivyRecipe(CythonRecipe): version = "1.10.1" url = "https://github.com/kivy/kivy/archive/{version}.zip" library = "libkivy.a" - depends = ["python", "sdl2", "sdl2_image", "sdl2_mixer", "sdl2_ttf", "ios", - "pyobjus"] + depends = ["sdl2", "sdl2_image", "sdl2_mixer", "sdl2_ttf", "ios", + "pyobjus", "python"] pbx_frameworks = ["OpenGLES", "Accelerate"] pre_build_ext = True @@ -40,4 +40,3 @@ class KivyRecipe(CythonRecipe): recipe = KivyRecipe() - diff --git a/recipes/pyobjus/__init__.py b/recipes/pyobjus/__init__.py index 639b838..210aad4 100644 --- a/recipes/pyobjus/__init__.py +++ b/recipes/pyobjus/__init__.py @@ -18,8 +18,9 @@ class PyobjusRecipe(CythonRecipe): def cythonize_build(self): # don't use the cythonize, pyobjus don't support method rewriting + pyver = "-{}".format(self.ctx.python_major) shprint(sh.find, self.build_dir, "-iname", "*.pyx", - "-exec", "cython", "{}", ";") + "-exec", "cython", pyver, "{}", ";") # ffi is installed somewhere else, this include doesn't work # XXX ideally, we need to fix libffi installation... shprint(sh.sed, @@ -28,5 +29,3 @@ class PyobjusRecipe(CythonRecipe): "pyobjus/pyobjus.c") recipe = PyobjusRecipe() - - diff --git a/recipes/python.py b/recipes/python.py new file mode 100644 index 0000000..359f03f --- /dev/null +++ b/recipes/python.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- +from toolchain import Recipe + +class PythonAliasRecipe(Recipe): + is_alias = True + + def init_after_import(self, ctx): + python = ctx.state.get("python") + if not python: + print("WARNING: no python set yet, so you need to specify") + print("WARNING: either python2 or python3 in your deps") + else: + self.depends = [python] + +recipe = PythonAliasRecipe() diff --git a/recipes/python2/__init__.py b/recipes/python2/__init__.py index 24cde16..ac253e6 100644 --- a/recipes/python2/__init__.py +++ b/recipes/python2/__init__.py @@ -4,21 +4,21 @@ import sh import os -class PythonRecipe(Recipe): +class Python2Recipe(Recipe): version = "2.7.1" url = "https://www.python.org/ftp/python/{version}/Python-{version}.tar.bz2" - depends = ["hostpython", "libffi", ] + depends = ["hostpython2", "libffi"] optional_depends = ["openssl"] library = "libpython2.7.a" pbx_libraries = ["libz", "libbz2", "libsqlite3"] def init_with_ctx(self, ctx): - super(PythonRecipe, self).init_with_ctx(ctx) - self.ctx.python_ver_dir = "python2.7" - self.ctx.python_prefix = join(ctx.dist_dir, "root", "python") - self.ctx.site_packages_dir = join( - ctx.dist_dir, "root", "python", "lib", ctx.python_ver_dir, - "site-packages") + super(Python2Recipe, self).init_with_ctx(ctx) + self.set_python(self, 2.7) + ctx.python_ver_dir = "python2.7" + ctx.python_prefix = join(ctx.dist_dir, "root", "python") + ctx.site_packages_dir = join( + ctx.python_prefix, "lib", ctx.python_ver_dir, "site-packages") def prebuild_arch(self, arch): # common to all archs @@ -149,4 +149,4 @@ class PythonRecipe(Recipe): os.chdir(oldpwd) -recipe = PythonRecipe() +recipe = Python2Recipe() diff --git a/recipes/python3/__init__.py b/recipes/python3/__init__.py index 41ae1d1..0ad068a 100644 --- a/recipes/python3/__init__.py +++ b/recipes/python3/__init__.py @@ -15,11 +15,11 @@ class Python3Recipe(Recipe): def init_with_ctx(self, ctx): super(Python3Recipe, self).init_with_ctx(ctx) - self.ctx.python_ver_dir = "python3.7" - self.ctx.python_prefix = join(ctx.dist_dir, "root", "python") - self.ctx.site_packages_dir = join( - ctx.dist_dir, "root", "python", "lib", ctx.python_ver_dir, - "site-packages") + self.set_python(self, 3.7) + ctx.python_ver_dir = "python3.7" + ctx.python_prefix = join(ctx.dist_dir, "root", "python3") + ctx.site_packages_dir = join( + ctx.python_prefix, "lib", ctx.python_ver_dir, "site-packages") def prebuild_arch(self, arch): # common to all archs diff --git a/toolchain.py b/toolchain.py index 80a3961..922f85f 100755 --- a/toolchain.py +++ b/toolchain.py @@ -306,6 +306,7 @@ class Context(object): cython = None sdkver = None sdksimver = None + so_suffix = None # set by one of the hostpython def __init__(self): super(Context, self).__init__() @@ -413,20 +414,30 @@ class Context(object): return "IDEBuildOperationMaxNumberOfConcurrentCompileTasks={}".format(self.num_cores) + class Recipe(object): - version = None - url = None - archs = [] - depends = [] - optional_depends = [] - library = None - libraries = [] - include_dir = None - include_per_arch = False - frameworks = [] - sources = [] - pbx_frameworks = [] - pbx_libraries = [] + props = { + "is_alias": False, + "version": None, + "url": None, + "archs": [], + "depends": [], + "optional_depends": [], + "library": None, + "libraries": [], + "include_dir": None, + "include_per_arch": False, + "frameworks": [], + "sources": [], + "pbx_frameworks": [], + "pbx_libraries": [] + } + + def __new__(cls): + for prop, value in cls.props.items(): + if not hasattr(cls, prop): + setattr(cls, prop, value) + return super(Recipe, cls).__new__(cls) # API available for recipes def download_file(self, url, filename, cwd=None): @@ -560,6 +571,12 @@ class Recipe(object): """ return join(self.ctx.include_dir, "common", self.name) + def so_filename(self, name): + """Return the filename of a library with the appropriate so suffix + (.so for Python 2.7, .cpython-37m-darwin for Python 3.7) + """ + return "{}{}".format(name, self.ctx.so_suffix) + @property def name(self): modname = self.__class__.__module__ @@ -619,6 +636,37 @@ class Recipe(object): arch = self.filtered_archs[0] return arch.get_env() + def set_hostpython(self, instance, version): + state = self.ctx.state + hostpython = state.get("hostpython") + if hostpython is None: + state["hostpython"] = instance.name + state.sync() + elif hostpython != instance.name: + print("ERROR: Wanted to use {}".format(instance.name)) + print("ERROR: but hostpython is already provided by {}.".format( + hostpython)) + print("ERROR: You can have only one hostpython version compiled") + sys.exit(1) + self.ctx.python_major = int(version) + self.ctx.hostpython_ver = version + self.ctx.hostpython_recipe = instance + + def set_python(self, instance, version): + state = self.ctx.state + python = state.get("python") + if python is None: + state["python"] = instance.name + state.sync() + elif python != instance.name: + print("ERROR: Wanted to use {}".format(instance.name)) + print("ERROR: but python is already provided by {}.".format( + python)) + print("ERROR: You can have only one python version compiled") + sys.exit(1) + self.ctx.python_ver = version + self.ctx.python_recipe = instance + @property def archive_root(self): key = "{}.archive_root".format(self.name) @@ -649,6 +697,12 @@ class Recipe(object): raise ValueError("Invalid path passed into {}".format(envname)) return d + def init_after_import(cls, ctx): + """This can be used to dynamically set some variables + depending of the state + """ + pass + @cache_execution def download(self): key = "{}.archive_root".format(self.name) @@ -875,6 +929,7 @@ class Recipe(object): mod = importlib.import_module("recipes.{}".format(name)) recipe = mod.recipe recipe.recipe_dir = join(ctx.root_dir, "recipes", name) + recipe.init_after_import(ctx) if version: recipe.version = version @@ -916,7 +971,7 @@ class PythonRecipe(Recipe): "--prefix", iosbuild, _env=env) dest_dir = join(self.ctx.site_packages_dir, name) - self.remove_junk(iosbuild) + #self.remove_junk(iosbuild) if is_dir: if exists(dest_dir): shutil.rmtree(dest_dir) @@ -944,6 +999,7 @@ class CythonRecipe(PythonRecipe): filename = filename[len(self.build_dir) + 1:] print("Cythonize {}".format(filename)) cmd = sh.Command(join(self.ctx.root_dir, "tools", "cythonize.py")) + hostpython = self.ctx.state.get("hostpython") shprint(cmd, filename) def cythonize_build(self): @@ -1021,6 +1077,9 @@ def build_recipes(names, ctx): build_order = list(graph.find_order()) print("Build order is {}".format(build_order)) recipes = [Recipe.get_recipe(name, ctx) for name in build_order] + recipes = [recipe for recipe in recipes if not recipe.is_alias] + recipes_order = [recipe.name for recipe in recipes] + print("Recipe order is {}".format(recipes_order)) for recipe in recipes: recipe.init_with_ctx(ctx) for recipe in recipes: