mirror of
https://github.com/kiwix/kiwix-build.git
synced 2025-04-21 21:27:06 -04:00
The target_platform option has always be wrongly named. This is not the platform we are targeted but how we compile. This was ok at beginning as specifying how we compile somehow define for what we compile but this is not a one to one mapping.
213 lines
8.2 KiB
Python
213 lines
8.2 KiB
Python
import sys
|
|
from collections import OrderedDict
|
|
from .buildenv import *
|
|
|
|
from .configs import ConfigInfo
|
|
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,
|
|
)
|
|
from . import _global
|
|
|
|
|
|
class Builder:
|
|
def __init__(self):
|
|
self._targets = {}
|
|
ConfigInfo.get_config("neutral", self._targets)
|
|
|
|
config_name = option("config")
|
|
config = ConfigInfo.get_config(config_name, self._targets)
|
|
if neutralEnv("distname") not in config.compatible_hosts:
|
|
print(
|
|
(
|
|
colorize("ERROR") + ": The config {} cannot be build on host {}.\n"
|
|
"Select another config or change your host system."
|
|
).format(config.name, neutralEnv("distname"))
|
|
)
|
|
self.targetDefs = config.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 config 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 cfgName in ConfigInfo.all_running_configs:
|
|
cfg = ConfigInfo.all_configs[cfgName]
|
|
for tlcName in cfg.toolchain_names:
|
|
tlc = Dependency.all_deps[tlcName]
|
|
yield ("source", tlcName)
|
|
yield ("neutral" if tlc.neutral else cfgName, tlcName)
|
|
_targets = dict(self._targets)
|
|
yield from self.order_dependencies(targetDef, _targets)
|
|
|
|
def order_dependencies(self, targetDef, targets):
|
|
targetConfigName, targetName = targetDef
|
|
if targetConfigName == "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
|
|
|
|
targetConfig = ConfigInfo.get_config(targetConfigName)
|
|
for dep in target.get_dependencies(targetConfig, True):
|
|
depConfig, depName = targetConfig.get_fully_qualified_dep(dep)
|
|
if (depConfig, depName) in targets:
|
|
yield from self.order_dependencies((depConfig, depName), targets)
|
|
yield ("source", targetName)
|
|
yield targetDef
|
|
|
|
def instanciate_steps(self):
|
|
for stepDef in list(target_steps()):
|
|
stepConfig, stepName = stepDef
|
|
stepClass = Dependency.all_deps[stepName]
|
|
if stepConfig == "source":
|
|
source = get_target_step(stepDef)(stepClass)
|
|
add_target_step(stepDef, source)
|
|
else:
|
|
source = get_target_step(stepName, "source")
|
|
env = ConfigInfo.get_config(stepConfig).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 config in ConfigInfo.all_running_configs.values():
|
|
mapper_name = "{host}_{config}".format(
|
|
host=neutralEnv("distname"), config=config
|
|
)
|
|
package_name_mapper = PACKAGE_NAME_MAPPERS.get(mapper_name, {})
|
|
packages_list += package_name_mapper.get("COMMON", [])
|
|
|
|
to_drop = []
|
|
for builderDef in self._targets:
|
|
configName, builderName = builderDef
|
|
mapper_name = "{host}_{config}".format(
|
|
host=neutralEnv("distname"), config=configName
|
|
)
|
|
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 TOOLCHAINS]")
|
|
for config in ConfigInfo.all_running_configs.values():
|
|
config.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 config in ConfigInfo.all_running_configs.values():
|
|
config.clean_intermediate_directories()
|
|
else:
|
|
print(colorize("SKIP"))
|
|
except StopBuild as e:
|
|
print(e)
|
|
sys.exit("Stopping build due to errors")
|