def get_bootstrap_from_recipes(cls, recipes, ctx): '''Returns a bootstrap whose recipe requirements do not conflict with the given recipes.''' info('Trying to find a bootstrap that matches the given recipes.') bootstraps = [ cls.get_bootstrap(name, ctx) for name in cls.list_bootstraps() ] acceptable_bootstraps = [] for bs in bootstraps: ok = True if not bs.can_be_chosen_automatically: ok = False for recipe in bs.recipe_depends: recipe = Recipe.get_recipe(recipe, ctx) if any([conflict in recipes for conflict in recipe.conflicts]): ok = False break for recipe in recipes: recipe = Recipe.get_recipe(recipe, ctx) if any([ conflict in bs.recipe_depends for conflict in recipe.conflicts ]): ok = False break if ok: acceptable_bootstraps.append(bs) info('Found {} acceptable bootstraps: {}'.format( len(acceptable_bootstraps), [bs.name for bs in acceptable_bootstraps])) if acceptable_bootstraps: info('Using the first of these: {}'.format( acceptable_bootstraps[0].name)) return acceptable_bootstraps[0] return None
def set_libs_flags(self, env, arch): '''Takes care to properly link libraries with python depending on our requirements and the attribute :attr:`opt_depends`. ''' def add_flags(include_flags, link_dirs, link_libs): env['CPPFLAGS'] = env.get('CPPFLAGS', '') + include_flags env['LDFLAGS'] = env.get('LDFLAGS', '') + link_dirs env['LIBS'] = env.get('LIBS', '') + link_libs if 'sqlite3' in self.ctx.recipe_build_order: info('Activating flags for sqlite3') recipe = Recipe.get_recipe('sqlite3', self.ctx) add_flags(' -I' + recipe.get_build_dir(arch.arch), ' -L' + recipe.get_lib_dir(arch), ' -lsqlite3') if 'libffi' in self.ctx.recipe_build_order: info('Activating flags for libffi') recipe = Recipe.get_recipe('libffi', self.ctx) # In order to force the correct linkage for our libffi library, we # set the following variable to point where is our libffi.pc file, # because the python build system uses pkg-config to configure it. env['PKG_CONFIG_PATH'] = recipe.get_build_dir(arch.arch) add_flags(' -I' + ' -I'.join(recipe.get_include_dirs(arch)), ' -L' + join(recipe.get_build_dir(arch.arch), '.libs'), ' -lffi') if 'openssl' in self.ctx.recipe_build_order: info('Activating flags for openssl') recipe = Recipe.get_recipe('openssl', self.ctx) add_flags(recipe.include_flags(arch), recipe.link_dirs_flags(arch), recipe.link_libs_flags()) return env
def set_libs_flags(self, env, arch): '''Takes care to properly link libraries with python depending on our requirements and the attribute :attr:`opt_depends`. ''' def add_flags(include_flags, link_dirs, link_libs): env['CPPFLAGS'] = env.get('CPPFLAGS', '') + include_flags env['LDFLAGS'] = env.get('LDFLAGS', '') + link_dirs env['LIBS'] = env.get('LIBS', '') + link_libs if 'sqlite3' in self.ctx.recipe_build_order: info('Activating flags for sqlite3') recipe = Recipe.get_recipe('sqlite3', self.ctx) add_flags(' -I' + recipe.get_build_dir(arch.arch), ' -L' + recipe.get_lib_dir(arch), ' -lsqlite3') if 'libffi' in self.ctx.recipe_build_order: info('Activating flags for libffi') recipe = Recipe.get_recipe('libffi', self.ctx) # In order to force the correct linkage for our libffi library, we # set the following variable to point where is our libffi.pc file, # because the python build system uses pkg-config to configure it. env['PKG_CONFIG_PATH'] = recipe.get_build_dir(arch.arch) add_flags(' -I' + ' -I'.join(recipe.get_include_dirs(arch)), ' -L' + join(recipe.get_build_dir(arch.arch), '.libs'), ' -lffi') if 'openssl' in self.ctx.recipe_build_order: info('Activating flags for openssl') recipe = Recipe.get_recipe('openssl', self.ctx) add_flags(recipe.include_flags(arch), recipe.link_dirs_flags(arch), recipe.link_libs_flags()) return env
def set_libs_flags(self, env, arch): '''Takes care to properly link libraries with python depending on our requirements and the attribute :attr:`opt_depends`. ''' def add_flags(include_flags, link_dirs, link_libs): env['CPPFLAGS'] = env.get('CPPFLAGS', '') + include_flags env['LDFLAGS'] = env.get('LDFLAGS', '') + link_dirs env['LIBS'] = env.get('LIBS', '') + link_libs if 'sqlite3' in self.ctx.recipe_build_order: info('Activating flags for sqlite3') recipe = Recipe.get_recipe('sqlite3', self.ctx) add_flags(' -I' + recipe.get_build_dir(arch.arch), ' -L' + recipe.get_lib_dir(arch), ' -lsqlite3') if 'libffi' in self.ctx.recipe_build_order: info('Activating flags for libffi') recipe = Recipe.get_recipe('libffi', self.ctx) add_flags( ' -I' + ' -I'.join(recipe.get_include_dirs(arch)), ' -L' + join(recipe.get_build_dir(arch.arch), recipe.get_host(arch), '.libs'), ' -lffi') if 'openssl' in self.ctx.recipe_build_order: info('Activating flags for openssl') recipe = Recipe.get_recipe('openssl', self.ctx) add_flags(recipe.include_flags(arch), recipe.link_dirs_flags(arch), recipe.link_libs_flags()) return env
def set_libs_flags(self, env, arch): '''Takes care to properly link libraries with python depending on our requirements and the attribute :attr:`opt_depends`. ''' if 'libffi' in self.ctx.recipe_build_order: info('Activating flags for libffi') recipe = Recipe.get_recipe('libffi', self.ctx) include = ' -I' + ' -I'.join(recipe.get_include_dirs(arch)) ldflag = ' -L' + join(recipe.get_build_dir(arch.arch), recipe.get_host(arch), '.libs') + ' -lffi' env['CPPFLAGS'] = env.get('CPPFLAGS', '') + include env['LDFLAGS'] = env.get('LDFLAGS', '') + ldflag if 'openssl' in self.ctx.recipe_build_order: recipe = Recipe.get_recipe('openssl', self.ctx) openssl_build_dir = recipe.get_build_dir(arch.arch) setuplocal = join('Modules', 'Setup.local') shprint(sh.cp, join(self.get_recipe_dir(), 'Setup.local-ssl'), setuplocal) shprint(sh.sed, '-i.backup', 's#^SSL=.*#SSL={}#'.format(openssl_build_dir), setuplocal) env['OPENSSL_VERSION'] = recipe.version if 'sqlite3' in self.ctx.recipe_build_order: # Include sqlite3 in python2 build recipe = Recipe.get_recipe('sqlite3', self.ctx) include = ' -I' + recipe.get_build_dir(arch.arch) lib = ' -L' + recipe.get_lib_dir(arch) + ' -lsqlite3' # Insert or append to env flag = 'CPPFLAGS' env[flag] = env[flag] + include if flag in env else include flag = 'LDFLAGS' env[flag] = env[flag] + lib if flag in env else lib return env
def main(): target_python = TargetPython.python3 recipes = modified_recipes() logger.info('recipes modified: {}'.format(recipes)) recipes -= CORE_RECIPES logger.info('recipes to build: {}'.format(recipes)) context = Context() # removing the deleted recipes for the given target (if any) for recipe_name in recipes.copy(): try: Recipe.get_recipe(recipe_name, context) except ValueError: # recipe doesn't exist, so probably we remove it recipes.remove(recipe_name) logger.warning( 'removed {} from recipes because deleted'.format(recipe_name)) # forces the default target recipes_and_target = recipes | set([target_python.name]) try: build_order, python_modules, bs = get_recipe_order_and_bootstrap( context, recipes_and_target, None) except BuildInterruptingException: # fallback to python2 if default target is not compatible logger.info('incompatible with {}'.format(target_python.name)) target_python = TargetPython.python2 logger.info('falling back to {}'.format(target_python.name)) # removing the known broken recipe for the given target broken_recipes = BROKEN_RECIPES[target_python] recipes -= broken_recipes logger.info('recipes to build (no broken): {}'.format(recipes)) build(target_python, recipes)
def set_libs_flags(self, env, arch): '''Takes care to properly link libraries with python depending on our requirements and the attribute :attr:`opt_depends`. ''' if 'libffi' in self.ctx.recipe_build_order: info('Activating flags for libffi') recipe = Recipe.get_recipe('libffi', self.ctx) include = ' -I' + ' -I'.join(recipe.get_include_dirs(arch)) ldflag = ' -L' + join(recipe.get_build_dir(arch.arch), recipe.get_host(arch), '.libs') + ' -lffi' env['CPPFLAGS'] = env.get('CPPFLAGS', '') + include env['LDFLAGS'] = env.get('LDFLAGS', '') + ldflag if 'openssl' in self.ctx.recipe_build_order: recipe = Recipe.get_recipe('openssl', self.ctx) openssl_build_dir = recipe.get_build_dir(arch.arch) setuplocal = join('Modules', 'Setup.local') shprint(sh.cp, join(self.get_recipe_dir(), 'Setup.local-ssl'), setuplocal) shprint(sh.sed, '-i.backup', 's#^SSL=.*#SSL={}#'.format(openssl_build_dir), setuplocal) env['OPENSSL_VERSION'] = recipe.version if 'sqlite3' in self.ctx.recipe_build_order: # Include sqlite3 in python2 build recipe = Recipe.get_recipe('sqlite3', self.ctx) include = ' -I' + recipe.get_build_dir(arch.arch) lib = ' -L' + recipe.get_lib_dir(arch) + ' -lsqlite3' # Insert or append to env flag = 'CPPFLAGS' env[flag] = env[flag] + include if flag in env else include flag = 'LDFLAGS' env[flag] = env[flag] + lib if flag in env else lib return env
def get_bootstrap_from_recipes(cls, recipes, ctx): '''Returns a bootstrap whose recipe requirements do not conflict with the given recipes.''' info('Trying to find a bootstrap that matches the given recipes.') bootstraps = [cls.get_bootstrap(name, ctx) for name in cls.list_bootstraps()] acceptable_bootstraps = [] for bs in bootstraps: if not bs.can_be_chosen_automatically: continue possible_dependency_lists = expand_dependencies(bs.recipe_depends) for possible_dependencies in possible_dependency_lists: ok = True for recipe in possible_dependencies: recipe = Recipe.get_recipe(recipe, ctx) if any([conflict in recipes for conflict in recipe.conflicts]): ok = False break for recipe in recipes: recipe = Recipe.get_recipe(recipe, ctx) if any([conflict in possible_dependencies for conflict in recipe.conflicts]): ok = False break if ok: acceptable_bootstraps.append(bs) info('Found {} acceptable bootstraps: {}'.format( len(acceptable_bootstraps), [bs.name for bs in acceptable_bootstraps])) if acceptable_bootstraps: info('Using the first of these: {}' .format(acceptable_bootstraps[0].name)) return acceptable_bootstraps[0] return None
def set_libs_flags(self, env, arch): '''Takes care to properly link libraries with python depending on our requirements and the attribute :attr:`opt_depends`. ''' def add_flags(include_flags, link_dirs, link_libs): env['CPPFLAGS'] = env.get('CPPFLAGS', '') + include_flags env['LDFLAGS'] = env.get('LDFLAGS', '') + link_dirs env['LIBS'] = env.get('LIBS', '') + link_libs if 'sqlite3' in self.ctx.recipe_build_order: info('Activating flags for sqlite3') recipe = Recipe.get_recipe('sqlite3', self.ctx) add_flags(' -I' + recipe.get_build_dir(arch.arch), ' -L' + recipe.get_lib_dir(arch), ' -lsqlite3') if 'libffi' in self.ctx.recipe_build_order: info('Activating flags for libffi') recipe = Recipe.get_recipe('libffi', self.ctx) # In order to force the correct linkage for our libffi library, we # set the following variable to point where is our libffi.pc file, # because the python build system uses pkg-config to configure it. env['PKG_CONFIG_PATH'] = recipe.get_build_dir(arch.arch) add_flags(' -I' + ' -I'.join(recipe.get_include_dirs(arch)), ' -L' + join(recipe.get_build_dir(arch.arch), '.libs'), ' -lffi') if 'openssl' in self.ctx.recipe_build_order: info('Activating flags for openssl') recipe = Recipe.get_recipe('openssl', self.ctx) add_flags(recipe.include_flags(arch), recipe.link_dirs_flags(arch), recipe.link_libs_flags()) # python build system contains hardcoded zlib version which prevents # the build of zlib module, here we search for android's zlib version # and sets the right flags, so python can be build with android's zlib info("Activating flags for android's zlib") zlib_lib_path = join(self.ctx.ndk_platform, 'usr', 'lib') zlib_includes = join(self.ctx.ndk_dir, 'sysroot', 'usr', 'include') zlib_h = join(zlib_includes, 'zlib.h') try: with open(zlib_h) as fileh: zlib_data = fileh.read() except IOError: raise BuildInterruptingException( "Could not determine android's zlib version, no zlib.h ({}) in" " the NDK dir includes".format(zlib_h) ) for line in zlib_data.split('\n'): if line.startswith('#define ZLIB_VERSION '): break else: raise BuildInterruptingException( 'Could not parse zlib.h...so we cannot find zlib version,' 'required by python build,' ) env['ZLIB_VERSION'] = line.replace('#define ZLIB_VERSION ', '') add_flags(' -I' + zlib_includes, ' -L' + zlib_lib_path, ' -lz') return env
def test_built_libraries(self): """The openssl recipe is a library recipe, so it should have set the attribute `built_libraries`, but not the case of `pyopenssl` recipe. """ recipe = Recipe.get_recipe('openssl', self.ctx) self.assertTrue(recipe.built_libraries) recipe = Recipe.get_recipe('pyopenssl', self.ctx) self.assertFalse(recipe.built_libraries)
def test_get_recipe(self): """ Makes sure `get_recipe()` returns a `Recipe` object when possible. """ ctx = Context() recipe_name = 'python3' recipe = Recipe.get_recipe(recipe_name, ctx) self.assertTrue(isinstance(recipe, Recipe)) self.assertEqual(recipe.name, recipe_name) recipe_name = 'does_not_exist' with self.assertRaises(ValueError) as e: Recipe.get_recipe(recipe_name, ctx) self.assertEqual( e.exception.args[0], 'Recipe does not exist: {}'.format(recipe_name))
def test_get_recipe(self): """ Makes sure `get_recipe()` returns a `Recipe` object when possible. """ ctx = Context() recipe_name = 'python3' recipe = Recipe.get_recipe(recipe_name, ctx) self.assertTrue(isinstance(recipe, Recipe)) self.assertEqual(recipe.name, recipe_name) recipe_name = 'does_not_exist' with self.assertRaises(ValueError) as e: Recipe.get_recipe(recipe_name, ctx) self.assertEqual(e.exception.args[0], 'Recipe does not exist: {}'.format(recipe_name))
def recipes(self, args): ctx = self.ctx if args.compact: print(" ".join(set(Recipe.list_recipes(ctx)))) else: for name in sorted(Recipe.list_recipes(ctx)): try: recipe = Recipe.get_recipe(name, ctx) except IOError: warning('Recipe "{}" could not be loaded'.format(name)) except SyntaxError: import traceback traceback.print_exc() warning(('Recipe "{}" could not be loaded due to a ' 'syntax error').format(name)) version = str(recipe.version) print('{Fore.BLUE}{Style.BRIGHT}{recipe.name:<12} ' '{Style.RESET_ALL}{Fore.LIGHTBLUE_EX}' '{version:<8}{Style.RESET_ALL}'.format( recipe=recipe, Fore=Out_Fore, Style=Out_Style, version=version)) print(' {Fore.GREEN}depends: {recipe.depends}' '{Fore.RESET}'.format(recipe=recipe, Fore=Out_Fore)) if recipe.conflicts: print(' {Fore.RED}conflicts: {recipe.conflicts}' '{Fore.RESET}' .format(recipe=recipe, Fore=Out_Fore)) if recipe.opt_depends: print(' {Fore.YELLOW}optional depends: ' '{recipe.opt_depends}{Fore.RESET}' .format(recipe=recipe, Fore=Out_Fore))
def build_cython_components(self, arch): libzmq_recipe = Recipe.get_recipe('libzmq', self.ctx) libzmq_prefix = join(libzmq_recipe.get_build_dir(arch.arch), "install") self.setup_extra_args = ["--zmq={}".format(libzmq_prefix)] self.build_cmd = "configure" env = self.get_recipe_env(arch) setup_cfg = join(self.get_build_dir(arch.arch), "setup.cfg") with open(setup_cfg, "wb") as fd: fd.write(""" [global] zmq_prefix = {} skip_check_zmq = True """.format(libzmq_prefix).encode()) return super(PyZMQRecipe, self).build_cython_components(arch) with current_directory(self.get_build_dir(arch.arch)): hostpython = sh.Command(self.hostpython_location) shprint(hostpython, 'setup.py', 'configure', '-v', _env=env) shprint(hostpython, 'setup.py', 'build_ext', '-v', _env=env) build_dir = glob.glob('build/lib.*')[0] shprint(sh.find, build_dir, '-name', '"*.o"', '-exec', env['STRIP'], '{}', ';', _env=env)
def build_recipes(build_order, python_modules, ctx): # Put recipes in correct build order bs = ctx.bootstrap info_notify("Recipe build order is {}".format(build_order)) if python_modules: python_modules = sorted(set(python_modules)) info_notify( ('The requirements ({}) were not found as recipes, they will be ' 'installed with pip.').format(', '.join(python_modules))) recipes = [Recipe.get_recipe(name, ctx) for name in build_order] # download is arch independent info_main('# Downloading recipes ') for recipe in recipes: recipe.download_if_necessary() for arch in ctx.archs: info_main('# Building all recipes for arch {}'.format(arch.arch)) info_main('# Unpacking recipes') for recipe in recipes: ensure_dir(recipe.get_build_container_dir(arch.arch)) recipe.prepare_build_dir(arch.arch) info_main('# Prebuilding recipes') # 2) prebuild packages for recipe in recipes: info_main('Prebuilding {} for {}'.format(recipe.name, arch.arch)) recipe.prebuild_arch(arch) recipe.apply_patches(arch) # 3) build packages info_main('# Building recipes') for recipe in recipes: info_main('Building {} for {}'.format(recipe.name, arch.arch)) if recipe.should_build(arch): recipe.build_arch(arch) else: info('{} said it is already built, skipping' .format(recipe.name)) # 4) biglink everything # AND: Should make this optional info_main('# Biglinking object files') if not ctx.python_recipe or not ctx.python_recipe.from_crystax: biglink(ctx, arch) else: info('NDK is crystax, skipping biglink (will this work?)') # 5) postbuild packages info_main('# Postbuilding recipes') for recipe in recipes: info_main('Postbuilding {} for {}'.format(recipe.name, arch.arch)) recipe.postbuild_arch(arch) info_main('# Installing pure Python modules') run_pymodules_install(ctx, python_modules) return
def has_package(self, name, arch=None): # If this is a file path, it'll need special handling: if (name.find("/") >= 0 or name.find("\\") >= 0) and \ name.find("://") < 0: # (:// would indicate an url) if not os.path.exists(name): # Non-existing dir, cannot look this up. return False try: name = get_package_name(os.path.abspath(name)) except ValueError: # Failed to look up any meaningful name. return False # Try to look up recipe by name: try: recipe = Recipe.get_recipe(name, self) except ValueError: pass else: name = getattr(recipe, 'site_packages_name', None) or name name = name.replace('.', '/') site_packages_dir = self.get_site_packages_dir(arch) return (exists(join(site_packages_dir, name)) or exists(join(site_packages_dir, name + '.py')) or exists(join(site_packages_dir, name + '.pyc')) or exists(join(site_packages_dir, name + '.pyo')) or exists(join(site_packages_dir, name + '.so')) or glob.glob(join(site_packages_dir, name + '-*.egg')))
def has_package(self, name, arch=None): # If this is a file path, it'll need special handling: if (name.find("/") >= 0 or name.find("\\") >= 0) and \ name.find("://") < 0: # (:// would indicate an url) if not os.path.exists(name): # Non-existing dir, cannot look this up. return False try: name = get_package_name(os.path.abspath(name)) except ValueError: # Failed to look up any meaningful name. return False # Try to look up recipe by name: try: recipe = Recipe.get_recipe(name, self) except ValueError: pass else: name = getattr(recipe, 'site_packages_name', None) or name name = name.replace('.', '/') site_packages_dir = self.get_site_packages_dir(arch) return (exists(join(site_packages_dir, name)) or exists(join(site_packages_dir, name + '.py')) or exists(join(site_packages_dir, name + '.pyc')) or exists(join(site_packages_dir, name + '.pyo')) or exists(join(site_packages_dir, name + '.so')) or glob.glob(join(site_packages_dir, name + '-*.egg')))
def get_recipe_env(self, arch): env = super().get_recipe_env(arch) GCC_VER = '4.9' HOST = 'linux-x86_64' LIB = 'lib64' if '64' in arch.arch else 'lib' prefix = env['TOOLCHAIN_PREFIX'] lapack_dir = join( Recipe.get_recipe('lapack', self.ctx).get_build_dir(arch.arch), 'build', 'install') sysroot = f"{self.ctx.ndk_dir}/platforms/{env['NDK_API']}/{arch.platform_dir}" sysroot_include = f'{self.ctx.ndk_dir}/toolchains/llvm/prebuilt/{HOST}/sysroot/usr/include' libgfortran = f'{self.ctx.ndk_dir}/toolchains/{prefix}-{GCC_VER}/prebuilt/{HOST}/{prefix}/{LIB}' numpylib = self.ctx.get_python_install_dir() + '/numpy/core/lib' LDSHARED_opts = env['LDSHARED'].split('clang')[1] env['LAPACK'] = f'{lapack_dir}/lib' env['BLAS'] = env['LAPACK'] env['F90'] = f'{prefix}-gfortran' env['CXX'] += f' -Wl,-l{self.stl_lib_name} -Wl,-L{self.get_stl_lib_dir(arch)}' env['CPPFLAGS'] += f' --sysroot={sysroot} -I{sysroot_include}/c++/v1 -I{sysroot_include}' env['LDSHARED'] = 'clang' env['LDFLAGS'] += f' {LDSHARED_opts} --sysroot={sysroot} -L{libgfortran} -L{numpylib}' env['LDFLAGS'] += f' -L{self.ctx.ndk_dir}/sources/cxx-stl/llvm-libc++/libs/{arch.arch}/' return env
def build_arch(self, arch): super(LibxsltRecipe, self).build_arch(arch) env = self.get_recipe_env(arch) build_dir = self.get_build_dir(arch.arch) with current_directory(build_dir): # If the build is done with /bin/sh things blow up, # try really hard to use bash libxml2_recipe = Recipe.get_recipe('libxml2', self.ctx) libxml2_build_dir = libxml2_recipe.get_build_dir(arch.arch) build_arch = shprint(sh.gcc, '-dumpmachine').stdout.decode( 'utf-8').split('\n')[0] if not exists('configure'): shprint(sh.Command('./autogen.sh'), _env=env) shprint(sh.Command('autoreconf'), '-vif', _env=env) shprint(sh.Command('./configure'), '--build=' + build_arch, '--host=' + arch.command_prefix, '--target=' + arch.command_prefix, '--without-plugins', '--without-debug', '--without-python', '--without-crypto', '--with-libxml-src=' + libxml2_build_dir, '--disable-shared', _env=env) shprint(sh.make, "V=1", _env=env) shutil.copyfile('libxslt/.libs/libxslt.a', join(self.ctx.libs_dir, 'libxslt.a')) shutil.copyfile('libexslt/.libs/libexslt.a', join(self.ctx.libs_dir, 'libexslt.a'))
def test_install_stl_lib( self, mock_ensure_dir, mock_isfile, mock_install_lib ): """ Test that :meth:`~pythonforandroid.recipe.STLRecipe.install_stl_lib`, calls the method :meth:`~pythonforandroid.recipe.Recipe.install_libs` with the proper arguments: a subclass of :class:`~pythonforandroid.archs.Arch` and our stl lib (:attr:`~pythonforandroid.recipe.STLRecipe.stl_lib_name`) """ mock_isfile.return_value = False arch = ArchAarch_64(self.ctx) recipe = Recipe.get_recipe('icu', self.ctx) recipe.ctx = self.ctx assert recipe.need_stl_shared, True recipe.install_stl_lib(arch) mock_install_lib.assert_called_once_with( arch, '{ndk_dir}/sources/cxx-stl/llvm-libc++/' 'libs/{arch}/lib{stl_lib}.so'.format( ndk_dir=self.ctx.ndk_dir, arch=arch.arch, stl_lib=recipe.stl_lib_name, ), ) mock_ensure_dir.assert_called()
def recipes(self, args): parser = argparse.ArgumentParser( description="List all the available recipes") parser.add_argument( "--compact", action="store_true", default=False, help="Produce a compact list suitable for scripting") args = parser.parse_args(args) ctx = self.ctx if args.compact: print(" ".join(set(Recipe.list_recipes(ctx)))) else: for name in sorted(Recipe.list_recipes(ctx)): recipe = Recipe.get_recipe(name, ctx) version = str(recipe.version) print('{Fore.BLUE}{Style.BRIGHT}{recipe.name:<12} ' '{Style.RESET_ALL}{Fore.LIGHTBLUE_EX}' '{version:<8}{Style.RESET_ALL}'.format( recipe=recipe, Fore=Out_Fore, Style=Out_Style, version=version)) print(' {Fore.GREEN}depends: {recipe.depends}' '{Fore.RESET}'.format(recipe=recipe, Fore=Out_Fore)) if recipe.conflicts: print(' {Fore.RED}conflicts: {recipe.conflicts}' '{Fore.RESET}' .format(recipe=recipe, Fore=Out_Fore)) if recipe.opt_depends: print(' {Fore.YELLOW}optional depends: ' '{recipe.opt_depends}{Fore.RESET}' .format(recipe=recipe, Fore=Out_Fore))
def set_libs_flags(self, env, arch): env = super(Python3Recipe, self).set_libs_flags(env, arch) if 'openssl' in self.ctx.recipe_build_order: recipe = Recipe.get_recipe('openssl', self.ctx) self.configure_args += \ ('--with-openssl=' + recipe.get_build_dir(arch.arch),) return env
def get_recipe_env(self, arch, with_flags_in_cc=True): """ Add libgeos headers to path """ env = super(ShapelyRecipe, self).get_recipe_env(arch, with_flags_in_cc) libgeos_dir = Recipe.get_recipe('libgeos', self.ctx).get_build_dir(arch.arch) env['CFLAGS'] += " -I{}/dist/include".format(libgeos_dir) return env
def test_bootstrap_strip( self, mock_find_executable, mock_ensure_dir, mock_sh_command, mock_sh_print, ): mock_find_executable.return_value = "arm-linux-androideabi-gcc" # prepare arch, bootstrap, distribution and PythonRecipe arch = ArchARMv7_a(self.ctx) bs = Bootstrap().get_bootstrap(self.bootstrap_name, self.ctx) self.setUp_distribution_with_bootstrap(bs) self.ctx.python_recipe = Recipe.get_recipe("python3", self.ctx) # test that strip_libraries runs with a fake distribution bs.strip_libraries(arch) mock_find_executable.assert_called_once() self.assertEqual( mock_find_executable.call_args[0][0], mock_find_executable.return_value, ) mock_sh_command.assert_called_once_with("arm-linux-androideabi-strip") # check that the other mocks we made are actually called mock_ensure_dir.assert_called() mock_sh_print.assert_called()
def build_arch(self, arch): env = self.get_recipe_env(arch) build_dir = self.get_build_dir(arch.arch) with current_directory(build_dir): # If the build is done with /bin/sh things blow up, # try really hard to use bash libxml2_recipe = Recipe.get_recipe('libxml2', self.ctx) libxml2_build_dir = libxml2_recipe.get_build_dir(arch.arch) build_arch = shprint(sh.gcc, '-dumpmachine').stdout.decode( 'utf-8').split('\n')[0] if not exists('configure'): shprint(sh.Command('./autogen.sh'), _env=env) shprint(sh.Command('autoreconf'), '-vif', _env=env) shprint(sh.Command('./configure'), '--build=' + build_arch, '--host=' + arch.command_prefix, '--target=' + arch.command_prefix, '--without-plugins', '--without-debug', '--without-python', '--without-crypto', '--with-libxml-src=' + libxml2_build_dir, '--disable-shared', _env=env) shprint(sh.make, "V=1", _env=env)
def recipes(self, args): ctx = self.ctx if args.compact: print(" ".join(set(Recipe.list_recipes(ctx)))) else: for name in sorted(Recipe.list_recipes(ctx)): try: recipe = Recipe.get_recipe(name, ctx) except IOError: warning('Recipe "{}" could not be loaded'.format(name)) except SyntaxError: import traceback traceback.print_exc() warning(('Recipe "{}" could not be loaded due to a ' 'syntax error').format(name)) version = str(recipe.version) print('{Fore.BLUE}{Style.BRIGHT}{recipe.name:<12} ' '{Style.RESET_ALL}{Fore.LIGHTBLUE_EX}' '{version:<8}{Style.RESET_ALL}'.format( recipe=recipe, Fore=Out_Fore, Style=Out_Style, version=version)) print(' {Fore.GREEN}depends: {recipe.depends}' '{Fore.RESET}'.format(recipe=recipe, Fore=Out_Fore)) if recipe.conflicts: print(' {Fore.RED}conflicts: {recipe.conflicts}' '{Fore.RESET}' .format(recipe=recipe, Fore=Out_Fore)) if recipe.opt_depends: print(' {Fore.YELLOW}optional depends: ' '{recipe.opt_depends}{Fore.RESET}' .format(recipe=recipe, Fore=Out_Fore))
def test_bootstrap_strip( self, mock_find_executable, mock_glob, mock_ensure_dir, mock_sh_command, mock_sh_print, ): mock_find_executable.return_value = os.path.join( self.ctx._ndk_dir, f"toolchains/llvm/prebuilt/{system().lower()}-x86_64/bin/clang", ) mock_glob.return_value = [ os.path.join(self.ctx._ndk_dir, "toolchains", "llvm") ] # prepare arch, bootstrap, distribution and PythonRecipe arch = ArchARMv7_a(self.ctx) bs = Bootstrap().get_bootstrap(self.bootstrap_name, self.ctx) self.setUp_distribution_with_bootstrap(bs) self.ctx.python_recipe = Recipe.get_recipe("python3", self.ctx) # test that strip_libraries runs with a fake distribution bs.strip_libraries(arch) mock_find_executable.assert_called_once() self.assertEqual( mock_find_executable.call_args[0][0], mock_find_executable.return_value, ) mock_sh_command.assert_called_once_with("arm-linux-androideabi-strip") # check that the other mocks we made are actually called mock_ensure_dir.assert_called() mock_sh_print.assert_called()
def build_recipes(build_order, python_modules, ctx): # Put recipes in correct build order bs = ctx.bootstrap info_notify("Recipe build order is {}".format(build_order)) if python_modules: python_modules = sorted(set(python_modules)) info_notify( ('The requirements ({}) were not found as recipes, they will be ' 'installed with pip.').format(', '.join(python_modules))) recipes = [Recipe.get_recipe(name, ctx) for name in build_order] # download is arch independent info_main('# Downloading recipes ') for recipe in recipes: recipe.download_if_necessary() for arch in ctx.archs: info_main('# Building all recipes for arch {}'.format(arch.arch)) info_main('# Unpacking recipes') for recipe in recipes: ensure_dir(recipe.get_build_container_dir(arch.arch)) recipe.prepare_build_dir(arch.arch) info_main('# Prebuilding recipes') # 2) prebuild packages for recipe in recipes: info_main('Prebuilding {} for {}'.format(recipe.name, arch.arch)) recipe.prebuild_arch(arch) recipe.apply_patches(arch) # 3) build packages info_main('# Building recipes') for recipe in recipes: info_main('Building {} for {}'.format(recipe.name, arch.arch)) if recipe.should_build(arch): recipe.build_arch(arch) else: info('{} said it is already built, skipping'.format( recipe.name)) # 4) biglink everything # AND: Should make this optional info_main('# Biglinking object files') if not ctx.python_recipe or not ctx.python_recipe.from_crystax: biglink(ctx, arch) else: info('NDK is crystax, skipping biglink (will this work?)') # 5) postbuild packages info_main('# Postbuilding recipes') for recipe in recipes: info_main('Postbuilding {} for {}'.format(recipe.name, arch.arch)) recipe.postbuild_arch(arch) info_main('# Installing pure Python modules') run_pymodules_install(ctx, python_modules) return
def recipes(self, args): parser = argparse.ArgumentParser( description="List all the available recipes") parser.add_argument( "--compact", action="store_true", default=False, help="Produce a compact list suitable for scripting") args = parser.parse_args(args) ctx = self.ctx if args.compact: print(" ".join(set(Recipe.list_recipes(ctx)))) else: for name in sorted(Recipe.list_recipes(ctx)): recipe = Recipe.get_recipe(name, ctx) version = str(recipe.version) print('{Fore.BLUE}{Style.BRIGHT}{recipe.name:<12} ' '{Style.RESET_ALL}{Fore.LIGHTBLUE_EX}' '{version:<8}{Style.RESET_ALL}'.format(recipe=recipe, Fore=Out_Fore, Style=Out_Style, version=version)) print(' {Fore.GREEN}depends: {recipe.depends}' '{Fore.RESET}'.format(recipe=recipe, Fore=Out_Fore)) if recipe.conflicts: print(' {Fore.RED}conflicts: {recipe.conflicts}' '{Fore.RESET}'.format(recipe=recipe, Fore=Out_Fore)) if recipe.opt_depends: print(' {Fore.YELLOW}optional depends: ' '{recipe.opt_depends}{Fore.RESET}'.format( recipe=recipe, Fore=Out_Fore))
def get_usable_bootstraps_for_recipes(cls, recipes, ctx): '''Returns all bootstrap whose recipe requirements do not conflict with the given recipes, in no particular order.''' info('Trying to find a bootstrap that matches the given recipes.') bootstraps = [ cls.get_bootstrap(name, ctx) for name in cls.all_bootstraps() ] acceptable_bootstraps = set() # Find out which bootstraps are acceptable: for bs in bootstraps: if not bs.can_be_chosen_automatically: continue possible_dependency_lists = expand_dependencies( bs.recipe_depends, ctx) for possible_dependencies in possible_dependency_lists: ok = True # Check if the bootstap's dependencies have an internal conflict: for recipe in possible_dependencies: recipe = Recipe.get_recipe(recipe, ctx) if any( [conflict in recipes for conflict in recipe.conflicts]): ok = False break # Check if bootstrap's dependencies conflict with chosen # packages: for recipe in recipes: try: recipe = Recipe.get_recipe(recipe, ctx) except ValueError: conflicts = [] else: conflicts = recipe.conflicts if any([ conflict in possible_dependencies for conflict in conflicts ]): ok = False break if ok and bs not in acceptable_bootstraps: acceptable_bootstraps.add(bs) info('Found {} acceptable bootstraps: {}'.format( len(acceptable_bootstraps), [bs.name for bs in acceptable_bootstraps])) return acceptable_bootstraps
def set_libs_flags(self, env, arch): env = super(Python2Recipe, self).set_libs_flags(env, arch) if 'openssl' in self.ctx.recipe_build_order: recipe = Recipe.get_recipe('openssl', self.ctx) openssl_build = recipe.get_build_dir(arch.arch) env['OPENSSL_BUILD'] = openssl_build env['OPENSSL_VERSION'] = recipe.version return env
def test_should_build(self, mock_exists): arch = ArchAarch_64(self.ctx) recipe = Recipe.get_recipe('openssl', self.ctx) recipe.ctx = self.ctx self.assertFalse(recipe.should_build(arch)) mock_exists.return_value = False self.assertTrue(recipe.should_build(arch))
def get_env(self): env = {} env["CFLAGS"] = " ".join([ "-DANDROID", "-mandroid", "-fomit-frame-pointer", "--sysroot", self.ctx.ndk_platform]) env["CXXFLAGS"] = env["CFLAGS"] env["LDFLAGS"] = " ".join(['-lm']) py_platform = sys.platform if py_platform in ['linux2', 'linux3']: py_platform = 'linux' toolchain_prefix = self.ctx.toolchain_prefix toolchain_version = self.ctx.toolchain_version command_prefix = self.command_prefix env['TOOLCHAIN_PREFIX'] = toolchain_prefix env['TOOLCHAIN_VERSION'] = toolchain_version print('path is', environ['PATH']) cc = find_executable('{command_prefix}-gcc'.format( command_prefix=command_prefix), path=environ['PATH']) if cc is None: warning('Couldn\'t find executable for CC. This indicates a ' 'problem locating the {} executable in the Android ' 'NDK, not that you don\'t have a normal compiler ' 'installed. Exiting.') exit(1) env['CC'] = '{command_prefix}-gcc {cflags}'.format( command_prefix=command_prefix, cflags=env['CFLAGS']) env['CXX'] = '{command_prefix}-g++ {cxxflags}'.format( command_prefix=command_prefix, cxxflags=env['CXXFLAGS']) env['AR'] = '{}-ar'.format(command_prefix) env['RANLIB'] = '{}-ranlib'.format(command_prefix) env['LD'] = '{}-ld'.format(command_prefix) env['STRIP'] = '{}-strip --strip-unneeded'.format(command_prefix) env['MAKE'] = 'make -j5' env['READELF'] = '{}-readelf'.format(command_prefix) hostpython_recipe = Recipe.get_recipe('hostpython2', self.ctx) # AND: This hardcodes python version 2.7, needs fixing env['BUILDLIB_PATH'] = join( hostpython_recipe.get_build_dir(self.arch), 'build', 'lib.linux-{}-2.7'.format(uname()[-1])) env['PATH'] = environ['PATH'] env['ARCH'] = self.arch return env
def get_env(self): env = {} env["CFLAGS"] = " ".join([ "-DANDROID", "-mandroid", "-fomit-frame-pointer", "--sysroot", self.ctx.ndk_platform ]) env["CXXFLAGS"] = env["CFLAGS"] env["LDFLAGS"] = " ".join(['-lm']) py_platform = sys.platform if py_platform in ['linux2', 'linux3']: py_platform = 'linux' toolchain_prefix = self.ctx.toolchain_prefix toolchain_version = self.ctx.toolchain_version command_prefix = self.command_prefix env['TOOLCHAIN_PREFIX'] = toolchain_prefix env['TOOLCHAIN_VERSION'] = toolchain_version print('path is', environ['PATH']) cc = find_executable( '{command_prefix}-gcc'.format(command_prefix=command_prefix), path=environ['PATH']) if cc is None: warning('Couldn\'t find executable for CC. This indicates a ' 'problem locating the {} executable in the Android ' 'NDK, not that you don\'t have a normal compiler ' 'installed. Exiting.') exit(1) env['CC'] = '{command_prefix}-gcc {cflags}'.format( command_prefix=command_prefix, cflags=env['CFLAGS']) env['CXX'] = '{command_prefix}-g++ {cxxflags}'.format( command_prefix=command_prefix, cxxflags=env['CXXFLAGS']) env['AR'] = '{}-ar'.format(command_prefix) env['RANLIB'] = '{}-ranlib'.format(command_prefix) env['LD'] = '{}-ld'.format(command_prefix) env['STRIP'] = '{}-strip --strip-unneeded'.format(command_prefix) env['MAKE'] = 'make -j5' env['READELF'] = '{}-readelf'.format(command_prefix) hostpython_recipe = Recipe.get_recipe('hostpython2', self.ctx) # AND: This hardcodes python version 2.7, needs fixing env['BUILDLIB_PATH'] = join(hostpython_recipe.get_build_dir(self.arch), 'build', 'lib.linux-{}-2.7'.format(uname()[-1])) env['PATH'] = environ['PATH'] env['ARCH'] = self.arch return env
def setUp(self): """ Setups recipe and context. """ self.context = Context() self.context.ndk_api = 21 self.context.android_api = 27 self.arch = ArchARMv7_a(self.context) self.recipe = Recipe.get_recipe('gevent', self.context)
def get_recipe_env(self, arch): env = super(CryptographyRecipe, self).get_recipe_env(arch) openssl_recipe = Recipe.get_recipe('openssl', self.ctx) env['CFLAGS'] += openssl_recipe.include_flags(arch) env['LDFLAGS'] += openssl_recipe.link_dirs_flags(arch) env['LIBS'] = openssl_recipe.link_libs_flags() return env
def get_recipe_env(self, arch): env = super().get_recipe_env(arch) openssl_recipe = Recipe.get_recipe('openssl', self.ctx) env['CFLAGS'] += openssl_recipe.include_flags(arch) env['LDFLAGS'] += openssl_recipe.link_dirs_flags(arch) env['LIBS'] = openssl_recipe.link_libs_flags() return env
def recursively_collect_orders(name, ctx, all_inputs, orders=[]): '''For each possible recipe ordering, try to add the new recipe name to that order. Recursively do the same thing with all the dependencies of each recipe. ''' try: recipe = Recipe.get_recipe(name, ctx) if recipe.depends is None: dependencies = [] else: # make all dependencies into lists so that product will work dependencies = [ ([dependency] if not isinstance(dependency, (list, tuple)) else dependency) for dependency in recipe.depends ] # handle opt_depends: these impose requirements on the build # order only if already present in the list of recipes to build dependencies.extend( [[d] for d in recipe.get_opt_depends_in_list(all_inputs)]) if recipe.conflicts is None: conflicts = [] else: conflicts = recipe.conflicts except IOError: # The recipe does not exist, so we assume it can be installed # via pip with no extra dependencies dependencies = [] conflicts = [] new_orders = [] # for each existing recipe order, see if we can add the new recipe name for order in orders: if name in order: new_orders.append(deepcopy(order)) continue if order.conflicts(name): continue if any([conflict in order for conflict in conflicts]): continue for dependency_set in product(*dependencies): new_order = deepcopy(order) new_order[name] = set(dependency_set) dependency_new_orders = [new_order] for dependency in dependency_set: dependency_new_orders = recursively_collect_orders( dependency, ctx, all_inputs, dependency_new_orders) new_orders.extend(dependency_new_orders) return new_orders
def setUp(self): """ Initialize a Context with a Bootstrap and a Distribution to properly test a recipe which depends on android's STL library, to do so we reuse `BaseClassSetupBootstrap` """ super().setUp() self.ctx.bootstrap = Bootstrap().get_bootstrap('sdl2', self.ctx) self.setUp_distribution_with_bootstrap(self.ctx.bootstrap) self.ctx.python_recipe = Recipe.get_recipe('python3', self.ctx)
def conflicts(self, name): for name in self.keys(): try: recipe = Recipe.get_recipe(name, self.ctx) conflicts = recipe.conflicts except IOError: conflicts = [] if any([c in self for c in conflicts]): return True return False
def conflicts(self): for name in self.keys(): try: recipe = Recipe.get_recipe(name, self.ctx) conflicts = [dep.lower() for dep in recipe.conflicts] except ValueError: conflicts = [] if any([c in self for c in conflicts]): return True return False
def conflicts(self): for name in self.keys(): try: recipe = Recipe.get_recipe(name, self.ctx) conflicts = [dep.lower() for dep in recipe.conflicts] except ValueError: conflicts = [] if any([c in self for c in conflicts]): return True return False
def conflicts(self, name): for name in self.keys(): try: recipe = Recipe.get_recipe(name, self.ctx) conflicts = recipe.conflicts except IOError: conflicts = [] if any([c in self for c in conflicts]): return True return False
def get_recipe_env(self, arch=None): env = super(PyCryptoRecipe, self).get_recipe_env(arch) openssl_build_dir = Recipe.get_recipe('openssl', self.ctx).get_build_dir(arch.arch) env['CC'] = '%s -I%s' % (env['CC'], join(openssl_build_dir, 'include')) env['LDFLAGS'] = env['LDFLAGS'] + ' -L{}'.format( self.ctx.get_libs_dir(arch.arch) + '-L{}'.format(self.ctx.libs_dir)) + ' -L{}'.format( openssl_build_dir) env['EXTRA_CFLAGS'] = '--host linux-armv' env['ac_cv_func_malloc_0_nonnull'] = 'yes' return env
def clean_recipe_build(self, args): '''Deletes the build files of the given recipe. This is intended for debug purposes, you may experience strange behaviour or problems with some recipes (if their build has done unexpected state changes). If this happens, run clean_builds, or attempt to clean other recipes until things work again. ''' recipe = Recipe.get_recipe(args.recipe, self.ctx) info('Cleaning build for {} recipe.'.format(recipe.name)) recipe.clean_build()
def recursively_collect_orders(name, ctx, all_inputs, orders=[]): '''For each possible recipe ordering, try to add the new recipe name to that order. Recursively do the same thing with all the dependencies of each recipe. ''' try: recipe = Recipe.get_recipe(name, ctx) if recipe.depends is None: dependencies = [] else: # make all dependencies into lists so that product will work dependencies = [([dependency] if not isinstance( dependency, (list, tuple)) else dependency) for dependency in recipe.depends] # handle opt_depends: these impose requirements on the build # order only if already present in the list of recipes to build dependencies.extend([[d] for d in recipe.get_opt_depends_in_list(all_inputs)]) if recipe.conflicts is None: conflicts = [] else: conflicts = recipe.conflicts except IOError: # The recipe does not exist, so we assume it can be installed # via pip with no extra dependencies dependencies = [] conflicts = [] new_orders = [] # for each existing recipe order, see if we can add the new recipe name for order in orders: if name in order: new_orders.append(deepcopy(order)) continue if order.conflicts(name): continue if any([conflict in order for conflict in conflicts]): continue for dependency_set in product(*dependencies): new_order = deepcopy(order) new_order[name] = set(dependency_set) dependency_new_orders = [new_order] for dependency in dependency_set: dependency_new_orders = recursively_collect_orders( dependency, ctx, all_inputs, dependency_new_orders) new_orders.extend(dependency_new_orders) return new_orders
def get_recipe_env(self, arch=None, clang=True): env = super(PyCryptoRecipe, self).get_recipe_env(arch) openssl_recipe = Recipe.get_recipe('openssl', self.ctx) env['CC'] = env['CC'] + openssl_recipe.include_flags(arch) env['LDFLAGS'] += ' -L{}'.format(self.ctx.get_libs_dir(arch.arch)) env['LDFLAGS'] += ' -L{}'.format(self.ctx.libs_dir) env['LDFLAGS'] += openssl_recipe.link_dirs_flags(arch) env['LIBS'] = env.get('LIBS', '') + openssl_recipe.link_libs_flags() env['EXTRA_CFLAGS'] = '--host linux-armv' env['ac_cv_func_malloc_0_nonnull'] = 'yes' return env
def set_libs_flags(self, env, arch): env = super(Python2Recipe, self).set_libs_flags(env, arch) if 'libffi' in self.ctx.recipe_build_order: # For python2 we need to tell configure that we want to use our # compiled libffi, this step is not necessary for python3. self.configure_args += ('--with-system-ffi',) if 'openssl' in self.ctx.recipe_build_order: recipe = Recipe.get_recipe('openssl', self.ctx) openssl_build = recipe.get_build_dir(arch.arch) env['OPENSSL_BUILD'] = openssl_build env['OPENSSL_VERSION'] = recipe.version return env
def set_libs_flags(self, env, arch): '''Takes care to properly link libraries with python depending on our requirements and the attribute :attr:`opt_depends`. ''' if 'libffi' in self.ctx.recipe_build_order: info('Activating flags for libffi') recipe = Recipe.get_recipe('libffi', self.ctx) include = ' -I' + ' -I'.join(recipe.get_include_dirs(arch)) ldflag = ' -L' + join(recipe.get_build_dir(arch.arch), recipe.get_host(arch), '.libs') + ' -lffi' env['CPPFLAGS'] = env.get('CPPFLAGS', '') + include env['LDFLAGS'] = env.get('LDFLAGS', '') + ldflag return env
def has_package(self, name, arch=None): try: recipe = Recipe.get_recipe(name, self) except IOError: pass else: name = getattr(recipe, 'site_packages_name', None) or name name = name.replace('.', '/') site_packages_dir = self.get_site_packages_dir(arch) return (exists(join(site_packages_dir, name)) or exists(join(site_packages_dir, name + '.py')) or exists(join(site_packages_dir, name + '.pyc')) or exists(join(site_packages_dir, name + '.pyo')) or exists(join(site_packages_dir, name + '.so')))
def remove_remaining_conflicts(self, ctx): # It's unpleasant to have to pass ctx as an argument... '''Checks all possible graphs for conflicts that have arisen during the additon of alternative repice branches, as these are not checked for conflicts at the time.''' new_graphs = [] for i, graph in enumerate(self.graphs): for name in graph.keys(): recipe = Recipe.get_recipe(name, ctx) if any([c in graph for c in recipe.conflicts]): break else: new_graphs.append(graph) self.graphs = new_graphs
def clean_recipe_build(self, args): '''Deletes the build files of the given recipe. This is intended for debug purposes, you may experience strange behaviour or problems with some recipes (if their build has done unexpected state changes). If this happens, run clean_builds, or attempt to clean other recipes until things work again. ''' parser = argparse.ArgumentParser( description="Delete all build files for the given recipe name.") parser.add_argument('recipe', help='The recipe name') args = parser.parse_args(args) recipe = Recipe.get_recipe(args.recipe, self.ctx) info('Cleaning build for {} recipe.'.format(recipe.name)) recipe.clean_build()
def setUp(self): """ Setups recipe and context. """ self.context = Context() self.arch = ArchARMv7_a(self.context) self.recipe = Recipe.get_recipe('reportlab', self.context) self.recipe.ctx = self.context self.bootstrap = None recipe_build_order, python_modules, bootstrap = \ get_recipe_order_and_bootstrap( self.context, [self.recipe.name], self.bootstrap) self.context.recipe_build_order = recipe_build_order self.context.python_modules = python_modules self.context.setup_dirs(tempfile.gettempdir()) self.bootstrap = bootstrap self.recipe_dir = self.recipe.get_build_dir(self.arch.arch) ensure_dir(self.recipe_dir)
def biglink(ctx, arch): # First, collate object files from each recipe info('Collating object files from each recipe') obj_dir = join(ctx.bootstrap.build_dir, 'collated_objects') ensure_dir(obj_dir) recipes = [Recipe.get_recipe(name, ctx) for name in ctx.recipe_build_order] for recipe in recipes: recipe_obj_dir = join(recipe.get_build_container_dir(arch.arch), 'objects_{}'.format(recipe.name)) if not exists(recipe_obj_dir): info('{} recipe has no biglinkable files dir, skipping' .format(recipe.name)) continue files = glob.glob(join(recipe_obj_dir, '*')) if not len(files): info('{} recipe has no biglinkable files, skipping' .format(recipe.name)) continue info('{} recipe has object files, copying'.format(recipe.name)) files.append(obj_dir) shprint(sh.cp, '-r', *files) env = arch.get_env() env['LDFLAGS'] = env['LDFLAGS'] + ' -L{}'.format( join(ctx.bootstrap.build_dir, 'obj', 'local', arch.arch)) if not len(glob.glob(join(obj_dir, '*'))): info('There seem to be no libraries to biglink, skipping.') return info('Biglinking') info('target {}'.format(join(ctx.get_libs_dir(arch.arch), 'libpymodules.so'))) do_biglink = copylibs_function if ctx.copy_libs else biglink_function # Move to the directory containing crtstart_so.o and crtend_so.o # This is necessary with newer NDKs? A gcc bug? with current_directory(join(ctx.ndk_platform, 'usr', 'lib')): do_biglink( join(ctx.get_libs_dir(arch.arch), 'libpymodules.so'), obj_dir.split(' '), extra_link_dirs=[join(ctx.bootstrap.build_dir, 'obj', 'local', arch.arch), os.path.abspath('.')], env=env)
def get_recipe_env(self, arch): env = super(LibxsltRecipe, self).get_recipe_env(arch) env['CONFIG_SHELL'] = '/bin/bash' env['SHELL'] = '/bin/bash' libxml2_recipe = Recipe.get_recipe('libxml2', self.ctx) libxml2_build_dir = libxml2_recipe.get_build_dir(arch.arch) libxml2_libs_dir = join(libxml2_build_dir, '.libs') env['CFLAGS'] = ' '.join([ env['CFLAGS'], '-I' + libxml2_build_dir, '-I' + join(libxml2_build_dir, 'include', 'libxml'), '-I' + self.get_build_dir(arch.arch), ]) env['LDFLAGS'] += ' -L' + libxml2_libs_dir env['LIBS'] = '-lxml2 -lz -lm' return env
def has_package(self, name, arch=None): # If this is a file path, it'll need special handling: if (name.find("/") >= 0 or name.find("\\") >= 0) and \ name.find("://") < 0: # (:// would indicate an url) if not os.path.exists(name): # Non-existing dir, cannot look this up. return False if os.path.exists(os.path.join(name, "setup.py")): # Get name from setup.py: name = subprocess.check_output([ sys.executable, "setup.py", "--name"], cwd=name) try: name = name.decode('utf-8', 'replace') except AttributeError: pass name = name.strip() if len(name) == 0: # Failed to look up any meaningful name. return False else: # A folder with whatever, cannot look this up. return False # Try to look up recipe by name: try: recipe = Recipe.get_recipe(name, self) except IOError: pass else: name = getattr(recipe, 'site_packages_name', None) or name name = name.replace('.', '/') site_packages_dir = self.get_site_packages_dir(arch) return (exists(join(site_packages_dir, name)) or exists(join(site_packages_dir, name + '.py')) or exists(join(site_packages_dir, name + '.pyc')) or exists(join(site_packages_dir, name + '.pyo')) or exists(join(site_packages_dir, name + '.so')) or glob.glob(join(site_packages_dir, name + '-*.egg')))
def recipes(self, args): ctx = self.ctx if args.compact: print(" ".join(set(Recipe.list_recipes(ctx)))) else: for name in sorted(Recipe.list_recipes(ctx)): recipe = Recipe.get_recipe(name, ctx) version = str(recipe.version) print('{Fore.BLUE}{Style.BRIGHT}{recipe.name:<12} ' '{Style.RESET_ALL}{Fore.LIGHTBLUE_EX}' '{version:<8}{Style.RESET_ALL}'.format( recipe=recipe, Fore=Out_Fore, Style=Out_Style, version=version)) print(' {Fore.GREEN}depends: {recipe.depends}' '{Fore.RESET}'.format(recipe=recipe, Fore=Out_Fore)) if recipe.conflicts: print(' {Fore.RED}conflicts: {recipe.conflicts}' '{Fore.RESET}' .format(recipe=recipe, Fore=Out_Fore)) if recipe.opt_depends: print(' {Fore.YELLOW}optional depends: ' '{recipe.opt_depends}{Fore.RESET}' .format(recipe=recipe, Fore=Out_Fore))
def biglink(ctx, arch): # First, collate object files from each recipe info('Collating object files from each recipe') obj_dir = join(ctx.bootstrap.build_dir, 'collated_objects') ensure_dir(obj_dir) recipes = [Recipe.get_recipe(name, ctx) for name in ctx.recipe_build_order] for recipe in recipes: recipe_obj_dir = join(recipe.get_build_container_dir(arch.arch), 'objects_{}'.format(recipe.name)) if not exists(recipe_obj_dir): info('{} recipe has no biglinkable files dir, skipping' .format(recipe.name)) continue files = glob.glob(join(recipe_obj_dir, '*')) if not len(files): info('{} recipe has no biglinkable files, skipping' .format(recipe.name)) info('{} recipe has object files, copying'.format(recipe.name)) files.append(obj_dir) shprint(sh.cp, '-r', *files) env = arch.get_env() env['LDFLAGS'] = env['LDFLAGS'] + ' -L{}'.format( join(ctx.bootstrap.build_dir, 'obj', 'local', arch.arch)) if not len(glob.glob(join(obj_dir, '*'))): info('There seem to be no libraries to biglink, skipping.') return info('Biglinking') info('target {}'.format(join(ctx.get_libs_dir(arch.arch), 'libpymodules.so'))) biglink_function( join(ctx.get_libs_dir(arch.arch), 'libpymodules.so'), obj_dir.split(' '), extra_link_dirs=[join(ctx.bootstrap.build_dir, 'obj', 'local', arch.arch)], env=env)