mirror of
https://github.com/kiwix/kiwix-build.git
synced 2025-04-24 06:37:07 -04:00
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.
206 lines
8.2 KiB
Python
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")
|
|
|