add alias for hostpython/python, that point to either 2 or 3 version depending of the previous compiled state.

This allows the recipe to point on an versionless python.
This commit is contained in:
Mathieu Virbel 2018-11-02 11:44:25 +01:00
parent 9762ee754c
commit 811cbd48a7
10 changed files with 130 additions and 40 deletions

15
recipes/hostpython.py Normal file
View file

@ -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()

View file

@ -5,7 +5,7 @@ import sh
import shutil import shutil
class HostpythonRecipe(Recipe): class Hostpython2Recipe(Recipe):
version = "2.7.1" version = "2.7.1"
url = "https://www.python.org/ftp/python/{version}/Python-{version}.tar.bz2" url = "https://www.python.org/ftp/python/{version}/Python-{version}.tar.bz2"
depends = ["hostlibffi"] depends = ["hostlibffi"]
@ -13,7 +13,9 @@ class HostpythonRecipe(Recipe):
archs = ["x86_64"] archs = ["x86_64"]
def init_with_ctx(self, ctx): 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.hostpython = join(self.ctx.dist_dir, "hostpython", "bin", "python")
self.ctx.hostpgen = join(self.ctx.dist_dir, "hostpython", "bin", "pgen") self.ctx.hostpgen = join(self.ctx.dist_dir, "hostpython", "bin", "pgen")
print("Global: hostpython located at {}".format(self.ctx.hostpython)) print("Global: hostpython located at {}".format(self.ctx.hostpython))
@ -110,4 +112,4 @@ class HostpythonRecipe(Recipe):
join(self.ctx.dist_dir, "hostpython", "bin", "pgen")) join(self.ctx.dist_dir, "hostpython", "bin", "pgen"))
recipe = HostpythonRecipe() recipe = Hostpython2Recipe()

View file

@ -14,6 +14,8 @@ class Hostpython3Recipe(Recipe):
def init_with_ctx(self, ctx): def init_with_ctx(self, ctx):
super(Hostpython3Recipe, self).init_with_ctx(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.hostpython = join(self.ctx.dist_dir, "hostpython3", "bin", "python")
self.ctx.hostpgen = join(self.ctx.dist_dir, "hostpython3", "bin", "pgen") self.ctx.hostpgen = join(self.ctx.dist_dir, "hostpython3", "bin", "pgen")
print("Global: hostpython located at {}".format(self.ctx.hostpython)) print("Global: hostpython located at {}".format(self.ctx.hostpython))

View file

@ -9,9 +9,8 @@ class IosRecipe(CythonRecipe):
pbx_frameworks = ["MessageUI", "CoreMotion", "UIKit"] pbx_frameworks = ["MessageUI", "CoreMotion", "UIKit"]
def install(self): 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() recipe = IosRecipe()

View file

@ -6,8 +6,8 @@ class KivyRecipe(CythonRecipe):
version = "1.10.1" version = "1.10.1"
url = "https://github.com/kivy/kivy/archive/{version}.zip" url = "https://github.com/kivy/kivy/archive/{version}.zip"
library = "libkivy.a" library = "libkivy.a"
depends = ["python", "sdl2", "sdl2_image", "sdl2_mixer", "sdl2_ttf", "ios", depends = ["sdl2", "sdl2_image", "sdl2_mixer", "sdl2_ttf", "ios",
"pyobjus"] "pyobjus", "python"]
pbx_frameworks = ["OpenGLES", "Accelerate"] pbx_frameworks = ["OpenGLES", "Accelerate"]
pre_build_ext = True pre_build_ext = True
@ -40,4 +40,3 @@ class KivyRecipe(CythonRecipe):
recipe = KivyRecipe() recipe = KivyRecipe()

View file

@ -18,8 +18,9 @@ class PyobjusRecipe(CythonRecipe):
def cythonize_build(self): def cythonize_build(self):
# don't use the cythonize, pyobjus don't support method rewriting # 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", shprint(sh.find, self.build_dir, "-iname", "*.pyx",
"-exec", "cython", "{}", ";") "-exec", "cython", pyver, "{}", ";")
# ffi is installed somewhere else, this include doesn't work # ffi is installed somewhere else, this include doesn't work
# XXX ideally, we need to fix libffi installation... # XXX ideally, we need to fix libffi installation...
shprint(sh.sed, shprint(sh.sed,
@ -28,5 +29,3 @@ class PyobjusRecipe(CythonRecipe):
"pyobjus/pyobjus.c") "pyobjus/pyobjus.c")
recipe = PyobjusRecipe() recipe = PyobjusRecipe()

15
recipes/python.py Normal file
View file

@ -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()

View file

@ -4,21 +4,21 @@ import sh
import os import os
class PythonRecipe(Recipe): class Python2Recipe(Recipe):
version = "2.7.1" version = "2.7.1"
url = "https://www.python.org/ftp/python/{version}/Python-{version}.tar.bz2" url = "https://www.python.org/ftp/python/{version}/Python-{version}.tar.bz2"
depends = ["hostpython", "libffi", ] depends = ["hostpython2", "libffi"]
optional_depends = ["openssl"] optional_depends = ["openssl"]
library = "libpython2.7.a" library = "libpython2.7.a"
pbx_libraries = ["libz", "libbz2", "libsqlite3"] pbx_libraries = ["libz", "libbz2", "libsqlite3"]
def init_with_ctx(self, ctx): def init_with_ctx(self, ctx):
super(PythonRecipe, self).init_with_ctx(ctx) super(Python2Recipe, self).init_with_ctx(ctx)
self.ctx.python_ver_dir = "python2.7" self.set_python(self, 2.7)
self.ctx.python_prefix = join(ctx.dist_dir, "root", "python") ctx.python_ver_dir = "python2.7"
self.ctx.site_packages_dir = join( ctx.python_prefix = join(ctx.dist_dir, "root", "python")
ctx.dist_dir, "root", "python", "lib", ctx.python_ver_dir, ctx.site_packages_dir = join(
"site-packages") ctx.python_prefix, "lib", ctx.python_ver_dir, "site-packages")
def prebuild_arch(self, arch): def prebuild_arch(self, arch):
# common to all archs # common to all archs
@ -149,4 +149,4 @@ class PythonRecipe(Recipe):
os.chdir(oldpwd) os.chdir(oldpwd)
recipe = PythonRecipe() recipe = Python2Recipe()

View file

@ -15,11 +15,11 @@ class Python3Recipe(Recipe):
def init_with_ctx(self, ctx): def init_with_ctx(self, ctx):
super(Python3Recipe, self).init_with_ctx(ctx) super(Python3Recipe, self).init_with_ctx(ctx)
self.ctx.python_ver_dir = "python3.7" self.set_python(self, 3.7)
self.ctx.python_prefix = join(ctx.dist_dir, "root", "python") ctx.python_ver_dir = "python3.7"
self.ctx.site_packages_dir = join( ctx.python_prefix = join(ctx.dist_dir, "root", "python3")
ctx.dist_dir, "root", "python", "lib", ctx.python_ver_dir, ctx.site_packages_dir = join(
"site-packages") ctx.python_prefix, "lib", ctx.python_ver_dir, "site-packages")
def prebuild_arch(self, arch): def prebuild_arch(self, arch):
# common to all archs # common to all archs

View file

@ -306,6 +306,7 @@ class Context(object):
cython = None cython = None
sdkver = None sdkver = None
sdksimver = None sdksimver = None
so_suffix = None # set by one of the hostpython
def __init__(self): def __init__(self):
super(Context, self).__init__() super(Context, self).__init__()
@ -413,20 +414,30 @@ class Context(object):
return "IDEBuildOperationMaxNumberOfConcurrentCompileTasks={}".format(self.num_cores) return "IDEBuildOperationMaxNumberOfConcurrentCompileTasks={}".format(self.num_cores)
class Recipe(object): class Recipe(object):
version = None props = {
url = None "is_alias": False,
archs = [] "version": None,
depends = [] "url": None,
optional_depends = [] "archs": [],
library = None "depends": [],
libraries = [] "optional_depends": [],
include_dir = None "library": None,
include_per_arch = False "libraries": [],
frameworks = [] "include_dir": None,
sources = [] "include_per_arch": False,
pbx_frameworks = [] "frameworks": [],
pbx_libraries = [] "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 # API available for recipes
def download_file(self, url, filename, cwd=None): def download_file(self, url, filename, cwd=None):
@ -560,6 +571,12 @@ class Recipe(object):
""" """
return join(self.ctx.include_dir, "common", self.name) 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 @property
def name(self): def name(self):
modname = self.__class__.__module__ modname = self.__class__.__module__
@ -619,6 +636,37 @@ class Recipe(object):
arch = self.filtered_archs[0] arch = self.filtered_archs[0]
return arch.get_env() 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 @property
def archive_root(self): def archive_root(self):
key = "{}.archive_root".format(self.name) key = "{}.archive_root".format(self.name)
@ -649,6 +697,12 @@ class Recipe(object):
raise ValueError("Invalid path passed into {}".format(envname)) raise ValueError("Invalid path passed into {}".format(envname))
return d return d
def init_after_import(cls, ctx):
"""This can be used to dynamically set some variables
depending of the state
"""
pass
@cache_execution @cache_execution
def download(self): def download(self):
key = "{}.archive_root".format(self.name) key = "{}.archive_root".format(self.name)
@ -875,6 +929,7 @@ class Recipe(object):
mod = importlib.import_module("recipes.{}".format(name)) mod = importlib.import_module("recipes.{}".format(name))
recipe = mod.recipe recipe = mod.recipe
recipe.recipe_dir = join(ctx.root_dir, "recipes", name) recipe.recipe_dir = join(ctx.root_dir, "recipes", name)
recipe.init_after_import(ctx)
if version: if version:
recipe.version = version recipe.version = version
@ -916,7 +971,7 @@ class PythonRecipe(Recipe):
"--prefix", iosbuild, "--prefix", iosbuild,
_env=env) _env=env)
dest_dir = join(self.ctx.site_packages_dir, name) dest_dir = join(self.ctx.site_packages_dir, name)
self.remove_junk(iosbuild) #self.remove_junk(iosbuild)
if is_dir: if is_dir:
if exists(dest_dir): if exists(dest_dir):
shutil.rmtree(dest_dir) shutil.rmtree(dest_dir)
@ -944,6 +999,7 @@ class CythonRecipe(PythonRecipe):
filename = filename[len(self.build_dir) + 1:] filename = filename[len(self.build_dir) + 1:]
print("Cythonize {}".format(filename)) print("Cythonize {}".format(filename))
cmd = sh.Command(join(self.ctx.root_dir, "tools", "cythonize.py")) cmd = sh.Command(join(self.ctx.root_dir, "tools", "cythonize.py"))
hostpython = self.ctx.state.get("hostpython")
shprint(cmd, filename) shprint(cmd, filename)
def cythonize_build(self): def cythonize_build(self):
@ -1021,6 +1077,9 @@ def build_recipes(names, ctx):
build_order = list(graph.find_order()) build_order = list(graph.find_order())
print("Build order is {}".format(build_order)) print("Build order is {}".format(build_order))
recipes = [Recipe.get_recipe(name, ctx) for name in 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: for recipe in recipes:
recipe.init_with_ctx(ctx) recipe.init_with_ctx(ctx)
for recipe in recipes: for recipe in recipes: