kiwix-build/kiwixbuild/builder.py
Matthieu Gautier 76aa746f84 Add the dont_skip attribute on dependency.
Instead of explicitly add the target associated to the toolchain
if we use `build_nodeps` option let add an attribute base ourself on it
to know if we need to add it or not.

This way, we may have other dependency we must not skip.
2021-04-12 18:09:52 +02:00

206 lines
8.2 KiB
Python

import sys
from collections import OrderedDict
from .buildenv import *
from .platforms import PlatformInfo
from .utils import remove_duplicates, StopBuild, colorize
from .dependencies import Dependency
from .packages import PACKAGE_NAME_MAPPERS
from ._global import (
neutralEnv, option,
add_target_step, get_target_step, target_steps,
backend)
from . import _global
class Builder:
def __init__(self):
self._targets = {}
PlatformInfo.get_platform('neutral', self._targets)
target_platform = option('target_platform')
platform = PlatformInfo.get_platform(target_platform, self._targets)
if neutralEnv('distname') not in platform.compatible_hosts:
print((colorize('ERROR')+': The target platform {} cannot be build on host {}.\n'
'Select another target platform or change your host system.'
).format(platform.name, neutralEnv('distname')))
self.targetDefs = platform.add_targets(option('target'), self._targets)
def finalize_target_steps(self):
steps = []
for targetDef in self.targetDefs:
steps += self.order_steps(targetDef)
steps = list(remove_duplicates(steps))
if option('build_nodeps'):
# add all platform steps
for dep in steps:
stepClass = Dependency.all_deps[dep[1]]
if stepClass.dont_skip:
add_target_step(dep, self._targets[dep])
src_targetDef = ('source', targetDef[1])
add_target_step(src_targetDef, self._targets[src_targetDef])
add_target_step(targetDef, self._targets[targetDef])
else:
for dep in steps:
if option('build_deps_only') and dep[1] == targetDef[1]:
continue
add_target_step(dep, self._targets[dep])
self.instanciate_steps()
def order_steps(self, targetDef):
for pltName in PlatformInfo.all_running_platforms:
plt = PlatformInfo.all_platforms[pltName]
for tlcName in plt.toolchain_names:
tlc = Dependency.all_deps[tlcName]
yield('source', tlcName)
yield('neutral' if tlc.neutral else pltName, tlcName)
_targets =dict(self._targets)
yield from self.order_dependencies(targetDef, _targets)
def order_dependencies(self, targetDef, targets):
targetPlatformName, targetName = targetDef
if targetPlatformName == 'source':
# Do not try to order sources, they will be added as dep by the
# build step two lines later.
return
try:
target = targets.pop(targetDef)
except KeyError:
return
targetPlatform = PlatformInfo.get_platform(targetPlatformName)
for dep in target.get_dependencies(targetPlatform, True):
depPlatform, depName = targetPlatform.get_fully_qualified_dep(dep)
if (depPlatform, depName) in targets:
yield from self.order_dependencies((depPlatform, depName), targets)
yield ('source', targetName)
yield targetDef
def instanciate_steps(self):
for stepDef in list(target_steps()):
stepPlatform, stepName = stepDef
stepClass = Dependency.all_deps[stepName]
if stepPlatform == 'source':
source = get_target_step(stepDef)(stepClass)
add_target_step(stepDef, source)
else:
source = get_target_step(stepName, 'source')
env = PlatformInfo.get_platform(stepPlatform).buildEnv
builder = get_target_step(stepDef)(stepClass, source, env)
add_target_step(stepDef, builder)
def prepare_sources(self):
if option('skip_source_prepare'):
print(colorize("SKIP"))
return
sourceDefs = remove_duplicates(tDef for tDef in target_steps() if tDef[0]=='source')
for sourceDef in sourceDefs:
print("prepare sources {} :".format(sourceDef[1]))
source = get_target_step(sourceDef)
source.prepare()
def build(self):
builderDefs = (tDef for tDef in target_steps() if tDef[0] != 'source')
for builderDef in builderDefs:
builder = get_target_step(builderDef)
if option('make_dist') and builderDef[1] == option('target'):
print("make dist {} ({}):".format(builder.name, builderDef[0]))
builder.make_dist()
continue
print("build {} ({}):".format(builder.name, builderDef[0]))
add_target_step(builderDef, builder)
builder.build()
def _get_packages(self):
packages_list = []
for platform in PlatformInfo.all_running_platforms.values():
mapper_name = "{host}_{target}".format(
host=neutralEnv('distname'),
target=platform)
package_name_mapper = PACKAGE_NAME_MAPPERS.get(mapper_name, {})
packages_list += package_name_mapper.get('COMMON', [])
to_drop = []
for builderDef in self._targets:
platformName, builderName = builderDef
mapper_name = "{host}_{target}".format(
host=neutralEnv('distname'),
target=platformName)
package_name_mapper = PACKAGE_NAME_MAPPERS.get(mapper_name, {})
packages = package_name_mapper.get(builderName)
if packages:
to_drop.append(builderDef)
if packages is not True:
# True means "assume the dependency is install but do not try to install anything for it"
packages_list += packages
for dep in to_drop:
del self._targets[dep]
return packages_list
def install_packages(self):
packages_to_have = self._get_packages()
packages_to_have = remove_duplicates(packages_to_have)
if option('assume_packages_installed'):
print(colorize("SKIP") + ", Assume package installed")
return
distname = neutralEnv('distname')
if distname in ('fedora', 'redhat', 'centos'):
package_installer = 'sudo dnf install {}'
package_checker = 'rpm -q --quiet {}'
elif distname in ('debian', 'Ubuntu'):
package_installer = 'sudo apt-get install {}'
package_checker = 'LANG=C dpkg -s {} 2>&1 | grep Status | grep "ok installed" 1>/dev/null 2>&1'
elif distname == 'Darwin':
package_installer = 'brew install {}'
package_checker = 'brew ls --version {} > /dev/null'
packages_to_install = []
for package in packages_to_have:
print(" - {} : ".format(package), end="")
command = package_checker.format(package)
try:
subprocess.check_call(command, shell=True)
except subprocess.CalledProcessError:
print(colorize("NEEDED"))
packages_to_install.append(package)
else:
print(colorize("SKIP"))
if packages_to_install:
command = package_installer.format(" ".join(packages_to_install))
print(command)
subprocess.check_call(command, shell=True)
else:
print(colorize("SKIP")+ ", No package to install.")
def run(self):
try:
print("[INSTALL PACKAGES]")
if option('dont_install_packages'):
print(colorize("SKIP"))
else:
self.install_packages()
self.finalize_target_steps()
print("[SETUP PLATFORMS]")
for platform in PlatformInfo.all_running_platforms.values():
platform.finalize_setup()
print("[PREPARE]")
self.prepare_sources()
print("[BUILD]")
self.build()
# No error, clean intermediate file at end of build if needed.
print("[CLEAN]")
if option('clean_at_end'):
for platform in PlatformInfo.all_running_platforms.values():
platform.clean_intermediate_directories()
else:
print(colorize("SKIP"))
except StopBuild as e:
print(e)
sys.exit("Stopping build due to errors")