Use a buildEnv to handle all kind of configuration stuff.

No real functional change but a first step to have a different buildEnv
to handle crosscompilation.
This commit is contained in:
Matthieu Gautier 2017-01-04 18:37:59 +01:00
parent ea725d0951
commit d26d6f46cd
1 changed files with 308 additions and 236 deletions

View File

@ -7,63 +7,15 @@ import tarfile
import subprocess import subprocess
import hashlib import hashlib
import shutil import shutil
from collections import defaultdict import tempfile
from collections import defaultdict, namedtuple
pj = os.path.join pj = os.path.join
REMOTE_PREFIX = 'http://download.kiwix.org/dev/' REMOTE_PREFIX = 'http://download.kiwix.org/dev/'
SOURCE_DIR = pj(os.getcwd(), "SOURCE")
ARCHIVE_DIR = pj(os.getcwd(), "ARCHIVE")
SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__)) SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
################################################################################
##### UTILS
################################################################################
# Some utils taken from meson
def is_debianlike():
return os.path.isfile('/etc/debian_version')
def default_libdir():
if is_debianlike():
try:
pc = subprocess.Popen(['dpkg-architecture', '-qDEB_HOST_MULTIARCH'],
stdout=subprocess.PIPE,
stderr=subprocess.DEVNULL)
(stdo, _) = pc.communicate()
if pc.returncode == 0:
archpath = stdo.decode().strip()
return 'lib/' + archpath
except Exception:
pass
if os.path.isdir('/usr/lib64') and not os.path.islink('/usr/lib64'):
return 'lib64'
return 'lib'
def detect_ninja():
for n in ['ninja', 'ninja-build']:
try:
retcode = subprocess.check_call([n, '--version'],
stdout=subprocess.DEVNULL)
except (FileNotFoundError, PermissionError):
# Doesn't exist in PATH or isn't executable
continue
if retcode == 0:
return n
def detect_meson():
for n in ['meson.py', 'meson']:
try:
retcode = subprocess.check_call([n, '--version'],
stdout=subprocess.DEVNULL)
except (FileNotFoundError, PermissionError):
# Doesn't exist in PATH or isn't executable
continue
if retcode == 0:
return n
class Defaultdict(defaultdict): class Defaultdict(defaultdict):
def __getattr__(self, name): def __getattr__(self, name):
@ -81,20 +33,34 @@ class SkipCommand(Exception):
class StopBuild(Exception): class StopBuild(Exception):
pass pass
def command(name, withlog='source_path', autoskip=False): Remotefile = namedtuple('Remotefile', ('name', 'sha256'))
class Context:
def __init__(self, command_name, log_file):
self.command_name = command_name
self.log_file = log_file
self.autoskip_file = None
def try_skip(self, path):
self.autoskip_file = pj(path, ".{}_ok".format(self.command_name))
if os.path.exists(self.autoskip_file):
raise SkipCommand()
def _finalise(self):
if self.autoskip_file is not None:
with open(self.autoskip_file, 'w') as f: pass
def command(name):
def decorator(function): def decorator(function):
def wrapper(self, *args): def wrapper(self, *args):
print(" {} {} : ".format(name, self.name), end="", flush=True) print(" {} {} : ".format(name, self.name), end="", flush=True)
if autoskip and os.path.exists(pj(self.source_path, ".{}_ok".format(name))): log = pj(self._log_dir, 'cmd_{}_{}.log'.format(name, self.name))
print("SKIP") context = Context(name, log)
return
log = pj(getattr(self, withlog), 'cmd_{}_{}.log'.format(name, self.name))
try: try:
with open(log, 'w') as _log: ret = function(self, *args, context=context)
ret = function(self, *args, log=_log) context._finalise()
print("OK") print("OK")
if autoskip:
with open(pj(self.source_path, ".{}_ok".format(name)), 'w') as f: pass
return ret return ret
except SkipCommand: except SkipCommand:
print("SKIP") print("SKIP")
@ -109,103 +75,206 @@ def command(name, withlog='source_path', autoskip=False):
return wrapper return wrapper
return decorator return decorator
def run_command(command, cwd, log, env=None, input=None):
log.write("run command '{}'\n".format(command))
if env:
log.write("env is :\n")
for k, v in env.items():
log.write(" {} : {!r}\n".format(k, v))
log.flush()
kwargs = dict() def extract_archive(archive_path, dest_dir, topdir=None, name=None):
if env: with tarfile.open(archive_path) as archive:
kwargs['env'] = env members = archive.getmembers()
if input: if not topdir:
kwargs['stdin'] = input for d in (m for m in members if m.isdir()):
return subprocess.check_call(command, shell=True, cwd=cwd, stdout=log, stderr=subprocess.STDOUT, **kwargs) if not os.path.dirname(d.name):
if topdir:
# There is already a top dir.
# Two topdirs in the same archive.
# Extract all
topdir = None
break
topdir = d
else:
topdir = archive.getmember(topdir)
if topdir:
members_to_extract = [m for m in members if m.name.startswith(topdir.name+'/')]
os.makedirs(dest_dir, exist_ok=True)
with tempfile.TemporaryDirectory(prefix=os.path.basename(archive_path), dir=dest_dir) as tmpdir:
archive.extractall(path=tmpdir, members=members_to_extract)
name = name or topdir.name
os.rename(pj(tmpdir, topdir.name), pj(dest_dir, name))
else:
if name:
dest_dir = pj(dest_dir, name)
os.makedirs(dest_dir)
archive.extractall(path=dest_dir)
class BuildEnv:
def __init__(self, options):
self.SOURCE_DIR = pj(os.getcwd(), "SOURCE")
self.ARCHIVE_DIR = pj(os.getcwd(), "ARCHIVE")
self.log_dir = pj(os.getcwd(), 'LOGS')
os.makedirs(self.SOURCE_DIR, exist_ok=True)
os.makedirs(self.ARCHIVE_DIR, exist_ok=True)
os.makedirs(self.log_dir, exist_ok=True)
self.ninja_command = self._detect_ninja()
self.meson_command = self._detect_meson()
self.options = options
self.libprefix = options.libprefix or self._detect_libdir()
def __getattr__(self, name):
return getattr(self.options, name)
def _is_debianlike(self):
return os.path.isfile('/etc/debian_version')
def _detect_libdir(self):
if self._is_debianlike():
try:
pc = subprocess.Popen(['dpkg-architecture', '-qDEB_HOST_MULTIARCH'],
stdout=subprocess.PIPE,
stderr=subprocess.DEVNULL)
(stdo, _) = pc.communicate()
if pc.returncode == 0:
archpath = stdo.decode().strip()
return 'lib/' + archpath
except Exception:
pass
if os.path.isdir('/usr/lib64') and not os.path.islink('/usr/lib64'):
return 'lib64'
return 'lib'
def _detect_ninja(self):
for n in ['ninja', 'ninja-build']:
try:
retcode = subprocess.check_call([n, '--version'],
stdout=subprocess.DEVNULL)
except (FileNotFoundError, PermissionError):
# Doesn't exist in PATH or isn't executable
continue
if retcode == 0:
return n
def _detect_meson(self):
for n in ['meson.py', 'meson']:
try:
retcode = subprocess.check_call([n, '--version'],
stdout=subprocess.DEVNULL)
except (FileNotFoundError, PermissionError):
# Doesn't exist in PATH or isn't executable
continue
if retcode == 0:
return n
def run_command(self, command, cwd, context, env=None, input=None):
with open(context.log_file, 'w') as log:
log.write("run command '{}'\n".format(command))
if env:
log.write("env is :\n")
for k, v in env.items():
log.write(" {} : {!r}\n".format(k, v))
log.flush()
kwargs = dict()
if env:
kwargs['env'] = env
if input:
kwargs['stdin'] = input
return subprocess.check_call(command, shell=True, cwd=cwd, stdout=log, stderr=subprocess.STDOUT, **kwargs)
def download(self, what, where=None):
where = where or self.ARCHIVE_DIR
file_path = pj(where, what.name)
file_url = REMOTE_PREFIX + what.name
if os.path.exists(file_path):
if what.sha256 == get_sha256(file_path):
raise SkipCommand()
os.remove(file_path)
urllib.request.urlretrieve(file_url, file_path)
if what.sha256 != get_sha256(file_path):
os.remove(file_path)
raise StopBuild()
################################################################################ ################################################################################
##### PROJECT ##### PROJECT
################################################################################ ################################################################################
class Dependency: class Dependency:
subsource_dir = None
def __init__(self, buildEnv):
self.buildEnv = buildEnv
@property @property
def source_path(self): def source_path(self):
return pj(SOURCE_DIR, self.source_dir) if self.subsource_dir:
return pj(self.buildEnv.SOURCE_DIR, self.source_dir, self.subsource_dir)
return pj(self.buildEnv.SOURCE_DIR, self.source_dir)
@property
def _log_dir(self):
return self.buildEnv.log_dir
class ReleaseDownloadMixin: class ReleaseDownloadMixin:
_log_download = ARCHIVE_DIR archive_top_dir = None
_log_source = SOURCE_DIR
archive_top_dir = ""
@property
def archive_path(self):
return pj(ARCHIVE_DIR, self.archive_name)
@property @property
def extract_path(self): def extract_path(self):
return SOURCE_DIR return pj(self.buildEnv.SOURCE_DIR, self.extract_dir)
@property @property
def archive_top_path(self): def source_dir(self):
return pj(SOURCE_DIR, self.archive_top_dir or self.source_dir) return "{}-{}".format(self.name, self.version)
@command("download", withlog='_log_download') @property
def _download(self, log): def extract_dir(self):
if os.path.exists(self.archive_path): return "{}-{}".format(self.name, self.version)
sha256 = get_sha256(self.archive_path)
if sha256 == self.archive_sha256:
raise SkipCommand()
os.remove(self.archive_path)
remote = REMOTE_PREFIX + self.archive_name
urllib.request.urlretrieve(remote, self.archive_path)
@command("extract", withlog='_log_source', autoskip=True) @command("download")
def _extract(self, log): def _download(self, context):
if os.path.exists(self.source_path): self.buildEnv.download(self.archive)
shutil.rmtree(self.source_path)
with tarfile.open(self.archive_path) as archive:
archive.extractall(self.extract_path)
@command("patch", autoskip=True) @command("extract")
def _patch(self, log): def _extract(self, context):
if not hasattr(self, 'patch'): context.try_skip(self.extract_path)
raise SkipCommand() if os.path.exists(self.extract_path):
shutil.rmtree(self.extract_path)
extract_archive(pj(self.buildEnv.ARCHIVE_DIR, self.archive.name),
self.buildEnv.SOURCE_DIR,
topdir=self.archive_top_dir,
name=self.extract_dir)
@command("patch")
def _patch(self, context):
context.try_skip(self.extract_path)
with open(pj(SCRIPT_DIR, 'patches', self.patch), 'r') as patch_input: with open(pj(SCRIPT_DIR, 'patches', self.patch), 'r') as patch_input:
run_command("patch -p1", self.source_path, log, input=patch_input) self.buildEnv.run_command("patch -p1", self.extract_path, context, input=patch_input)
def prepare(self, options): def prepare(self):
self._download() self._download()
self._extract() self._extract()
self._patch() if hasattr(self, 'patch'):
self._patch()
class GitCloneMixin: class GitCloneMixin:
_log_clone = SOURCE_DIR
git_ref = "master" git_ref = "master"
@property
def source_dir(self):
return self.git_dir
@property @property
def git_path(self): def git_path(self):
return pj(SOURCE_DIR, self.git_dir) return pj(self.buildEnv.SOURCE_DIR, self.git_dir)
@command("gitclone", withlog='_log_clone') @command("gitclone")
def _git_clone(self, log): def _git_clone(self, context):
if os.path.exists(self.git_path): if os.path.exists(self.git_path):
raise SkipCommand() raise SkipCommand()
command = "git clone " + self.git_remote command = "git clone " + self.git_remote
run_command(command, SOURCE_DIR, log) self.buildEnv.run_command(command, self.buildEnv.SOURCE_DIR, context)
@command("gitupdate") @command("gitupdate")
def _git_update(self, log): def _git_update(self, context):
run_command("git pull", self.git_path, log) self.buildEnv.run_command("git pull", self.git_path, context)
run_command("git checkout "+self.git_ref, self.git_path, log) self.buildEnv.run_command("git checkout "+self.git_ref, self.git_path, context)
def prepare(self, options): def prepare(self):
self._git_clone() self._git_clone()
self._git_update() self._git_update()
@ -217,116 +286,119 @@ class MakeMixin:
configure_script = "./configure" configure_script = "./configure"
configure_env = None configure_env = None
@command("configure", autoskip=True) @command("configure")
def _configure(self, options, log): def _configure(self, context):
context.try_skip(self.source_path)
command = "{configure_script} {configure_option} --prefix {install_dir} --libdir {libdir}" command = "{configure_script} {configure_option} --prefix {install_dir} --libdir {libdir}"
command = command.format( command = command.format(
configure_script = self.configure_script, configure_script = self.configure_script,
configure_option = self.configure_option, configure_option = self.configure_option,
install_dir = options.install_dir, install_dir = self.buildEnv.install_dir,
libdir = pj(options.install_dir, options.libprefix) libdir = pj(self.buildEnv.install_dir, self.buildEnv.libprefix)
) )
env = Defaultdict(str, os.environ) env = Defaultdict(str, os.environ)
if options.build_static: if self.buildEnv.build_static:
env['CFLAGS'] = env['CFLAGS'] + ' -fPIC' env['CFLAGS'] = env['CFLAGS'] + ' -fPIC'
if self.configure_env: if self.configure_env:
for k in self.configure_env: for k in self.configure_env:
if k.startswith('_format_'): if k.startswith('_format_'):
v = self.configure_env.pop(k) v = self.configure_env.pop(k)
v = v.format(options=options, env=env) v = v.format(buildEnv=self.buildEnv, env=env)
self.configure_env[k[8:]] = v self.configure_env[k[8:]] = v
env.update(self.configure_env) env.update(self.configure_env)
run_command(command, self.source_path, log, env=env) self.buildEnv.run_command(command, self.source_path, context, env=env)
@command("compile", autoskip=True) @command("compile")
def _compile(self, log): def _compile(self, context):
context.try_skip(self.source_path)
command = "make -j4 " + self.make_option command = "make -j4 " + self.make_option
run_command(command, self.source_path, log) self.buildEnv.run_command(command, self.source_path, context)
@command("install", autoskip=True) @command("install")
def _install(self, log): def _install(self, context):
context.try_skip(self.source_path)
command = "make install " + self.make_option command = "make install " + self.make_option
run_command(command, self.source_path, log) self.buildEnv.run_command(command, self.source_path, context)
def build(self, options): def build(self):
self._configure(options) self._configure()
self._compile() self._compile()
self._install() self._install()
class CMakeMixin(MakeMixin): class CMakeMixin(MakeMixin):
@command("configure", autoskip=True) @command("configure")
def _configure(self, options, log): def _configure(self, context):
context.try_skip(self.source_path)
command = "cmake {configure_option} -DCMAKE_INSTALL_PREFIX={install_dir} -DCMAKE_INSTALL_LIBDIR={libdir}" command = "cmake {configure_option} -DCMAKE_INSTALL_PREFIX={install_dir} -DCMAKE_INSTALL_LIBDIR={libdir}"
command = command.format( command = command.format(
configure_option = self.configure_option, configure_option = self.configure_option,
install_dir = options.install_dir, install_dir = self.buildEnv.install_dir,
libdir = options.libprefix libdir = self.buildEnv.libprefix
) )
env = Defaultdict(str, os.environ) env = Defaultdict(str, os.environ)
if options.build_static: if self.buildEnv.build_static:
env['CFLAGS'] = env['CFLAGS'] + ' -fPIC' env['CFLAGS'] = env['CFLAGS'] + ' -fPIC'
if self.configure_env: if self.configure_env:
for k in self.configure_env: for k in self.configure_env:
if k.startswith('_format_'): if k.startswith('_format_'):
v = self.configure_env.pop(k) v = self.configure_env.pop(k)
v = v.format(options=options, env=env) v = v.format(buildEnv=self.buildEnv, env=env)
self.configure_env[k[8:]] = v self.configure_env[k[8:]] = v
env.update(self.configure_env) env.update(self.configure_env)
run_command(command, self.source_path, log, env=env) self.buildEnv.run_command(command, self.source_path, context, env=env)
class MesonMixin(MakeMixin): class MesonMixin(MakeMixin):
meson_command = detect_meson()
ninja_command = detect_ninja()
@property @property
def build_path(self): def build_path(self):
return pj(self.source_path, 'build') return pj(self.source_path, 'build')
def _gen_env(self, options): def _gen_env(self):
env = Defaultdict(str, os.environ) env = Defaultdict(str, os.environ)
env['PKG_CONFIG_PATH'] = (env['PKG_CONFIG_PATH'] + ':' + pj(options.install_dir, options.libprefix, 'pkgconfig') env['PKG_CONFIG_PATH'] = (env['PKG_CONFIG_PATH'] + ':' + pj(self.buildEnv.install_dir, self.buildEnv.libprefix, 'pkgconfig')
if env['PKG_CONFIG_PATH'] if env['PKG_CONFIG_PATH']
else pj(options.install_dir, options.libprefix, 'pkgconfig') else pj(self.buildEnv.install_dir, self.buildEnv.libprefix, 'pkgconfig')
) )
env['PATH'] = ':'.join([pj(options.install_dir, 'bin'), env['PATH']]) env['PATH'] = ':'.join([pj(self.buildEnv.install_dir, 'bin'), env['PATH']])
if options.build_static: if self.buildEnv.build_static:
env['LDFLAGS'] = env['LDFLAGS'] + " -static-libstdc++ --static" env['LDFLAGS'] = env['LDFLAGS'] + " -static-libstdc++ --static"
return env return env
@command("configure", autoskip=True) @command("configure")
def _configure(self, options, log): def _configure(self, context):
context.try_skip(self.source_path)
if os.path.exists(self.build_path): if os.path.exists(self.build_path):
shutil.rmtree(self.build_path) shutil.rmtree(self.build_path)
os.makedirs(self.build_path) os.makedirs(self.build_path)
env = self._gen_env(options) env = self._gen_env()
if options.build_static: if self.buildEnv.build_static:
library_type = 'static' library_type = 'static'
else: else:
library_type = 'shared' library_type = 'shared'
configure_option = self.configure_option.format(options=options) configure_option = self.configure_option.format(buildEnv=self.buildEnv)
command = "{command} --default-library={library_type} {configure_option} . build --prefix={options.install_dir} --libdir={options.libprefix}".format( command = "{command} --default-library={library_type} {configure_option} . build --prefix={buildEnv.install_dir} --libdir={buildEnv.libprefix}".format(
command = self.meson_command, command = self.buildEnv.meson_command,
library_type=library_type, library_type=library_type,
configure_option=configure_option, configure_option=configure_option,
options=options) buildEnv=self.buildEnv)
run_command(command, self.source_path, log, env=env) self.buildEnv.run_command(command, self.source_path, context, env=env)
@command("compile") @command("compile")
def _compile(self, options, log): def _compile(self, context):
env = self._gen_env(options) env = self._gen_env()
command = "{} -v".format(self.ninja_command) command = "{} -v".format(self.buildEnv.ninja_command)
run_command(command, self.build_path, log, env=env) self.buildEnv.run_command(command, self.build_path, context, env=env)
@command("install") @command("install")
def _install(self, options, log): def _install(self, context):
env = self._gen_env(options) env = self._gen_env()
command = "{} -v install".format(self.ninja_command) command = "{} -v install".format(self.buildEnv.ninja_command)
run_command(command, self.build_path, log) self.buildEnv.run_command(command, self.build_path, context)
def build(self, options): def build(self):
self._configure(options) self._configure()
self._compile(options) self._compile()
self._install(options) self._install()
# ************************************* # *************************************
@ -347,91 +419,85 @@ class MesonMixin(MakeMixin):
class UUID(Dependency, ReleaseDownloadMixin, MakeMixin): class UUID(Dependency, ReleaseDownloadMixin, MakeMixin):
name = 'uuid' name = 'uuid'
archive_name = 'e2fsprogs-1.42.tar.gz' version = "1.42"
archive_sha256 = '55b46db0cec3e2eb0e5de14494a88b01ff6c0500edf8ca8927cad6da7b5e4a46' archive = Remotefile('e2fsprogs-1.42.tar.gz',
source_dir = 'e2fsprogs-1.42' '55b46db0cec3e2eb0e5de14494a88b01ff6c0500edf8ca8927cad6da7b5e4a46')
source_dir = extract_dir = 'e2fsprogs-1.42'
configure_option = "--enable-libuuid" configure_option = "--enable-libuuid"
configure_env = {'_format_CFLAGS' : "{env.CFLAGS} -fPIC"} configure_env = {'_format_CFLAGS' : "{env.CFLAGS} -fPIC"}
@command("compile", autoskip=True) @command("compile")
def _compile(self, log): def _compile(self, context):
context.try_skip(self.source_path)
command = "make -j4 libs " + self.make_option command = "make -j4 libs " + self.make_option
run_command(command, self.source_path, log) self.buildEnv.run_command(command, self.source_path, context)
@command("install", autoskip=True) @command("install")
def _install(self, log): def _install(self, context):
context.try_skip(self.source_path)
command = "make install-libs " + self.make_option command = "make install-libs " + self.make_option
run_command(command, self.source_path, log) self.buildEnv.run_command(command, self.source_path, context)
class Xapian(Dependency, ReleaseDownloadMixin, MakeMixin): class Xapian(Dependency, ReleaseDownloadMixin, MakeMixin):
name = "xapian" name = "xapian-core"
archive_name = 'xapian-core-1.4.0.tar.xz' version = "1.4.0"
source_dir = 'xapian-core-1.4.0' archive = Remotefile('xapian-core-1.4.0.tar.xz',
archive_sha256 = '10584f57112aa5e9c0e8a89e251aecbf7c582097638bfee79c1fe39a8b6a6477' '10584f57112aa5e9c0e8a89e251aecbf7c582097638bfee79c1fe39a8b6a6477')
configure_option = "--enable-shared --enable-static --disable-sse --disable-backend-inmemory" configure_option = "--enable-shared --enable-static --disable-sse --disable-backend-inmemory"
patch = "xapian_pkgconfig.patch" patch = "xapian_pkgconfig.patch"
configure_env = {'_format_LDFLAGS' : "-L{options.install_dir}/{options.libprefix}", configure_env = {'_format_LDFLAGS' : "-L{buildEnv.install_dir}/{buildEnv.libprefix}",
'_format_CXXFLAGS' : "-I{options.install_dir}/include"} '_format_CXXFLAGS' : "-I{buildEnv.install_dir}/include"}
class CTPP2(Dependency, ReleaseDownloadMixin, CMakeMixin): class CTPP2(Dependency, ReleaseDownloadMixin, CMakeMixin):
name = "ctpp2" name = "ctpp2"
archive_name = 'ctpp2-2.8.3.tar.gz' version = "2.8.3"
source_dir = 'ctpp2-2.8.3' archive = Remotefile('ctpp2-2.8.3.tar.gz',
archive_sha256 = 'a83ffd07817adb575295ef40fbf759892512e5a63059c520f9062d9ab8fb42fc' 'a83ffd07817adb575295ef40fbf759892512e5a63059c520f9062d9ab8fb42fc')
configure_option = "-DMD5_SUPPORT=OFF" configure_option = "-DMD5_SUPPORT=OFF"
patch = "ctpp2_include.patch" patch = "ctpp2_include.patch"
class Pugixml(Dependency, ReleaseDownloadMixin, MesonMixin): class Pugixml(Dependency, ReleaseDownloadMixin, MesonMixin):
name = "pugixml" name = "pugixml"
archive_name = 'pugixml-1.2.tar.gz' version = "1.2"
extract_path = pj(SOURCE_DIR, 'pugixml-1.2') archive = Remotefile('pugixml-1.2.tar.gz',
source_dir = 'pugixml-1.2' '0f422dad86da0a2e56a37fb2a88376aae6e931f22cc8b956978460c9db06136b')
archive_sha256 = '0f422dad86da0a2e56a37fb2a88376aae6e931f22cc8b956978460c9db06136b'
patch = "pugixml_meson.patch" patch = "pugixml_meson.patch"
class MicroHttpd(Dependency, ReleaseDownloadMixin, MakeMixin): class MicroHttpd(Dependency, ReleaseDownloadMixin, MakeMixin):
name = "microhttpd" name = "libmicrohttpd"
archive_name = 'libmicrohttpd-0.9.19.tar.gz' version = "0.9.19"
source_dir = 'libmicrohttpd-0.9.19' archive = Remotefile('libmicrohttpd-0.9.19.tar.gz',
archive_sha256 = 'dc418c7a595196f09d2f573212a0d794404fa4ac5311fc9588c1e7ad7a90fae6' 'dc418c7a595196f09d2f573212a0d794404fa4ac5311fc9588c1e7ad7a90fae6')
configure_option = "--enable-shared --enable-static --disable-https --without-libgcrypt --without-libcurl" configure_option = "--enable-shared --enable-static --disable-https --without-libgcrypt --without-libcurl"
class Icu(Dependency, ReleaseDownloadMixin, MakeMixin): class Icu(Dependency, ReleaseDownloadMixin, MakeMixin):
name = "icu" name = "icu4c"
archive_name = 'icu4c-56_1-src.tgz' version = "56_1"
archive_sha256 = '3a64e9105c734dcf631c0b3ed60404531bce6c0f5a64bfe1a6402a4cc2314816' archive = Remotefile('icu4c-56_1-src.tgz',
archive_top_dir = 'icu' '3a64e9105c734dcf631c0b3ed60404531bce6c0f5a64bfe1a6402a4cc2314816'
data_name = 'icudt56l.dat' )
data_sha256 = 'e23d85eee008f335fc49e8ef37b1bc2b222db105476111e3d16f0007d371cbca' data = Remotefile('icudt56l.dat',
source_dir = 'icu/source' 'e23d85eee008f335fc49e8ef37b1bc2b222db105476111e3d16f0007d371cbca')
configure_option = "Linux --disable-samples --disable-tests --disable-extras --enable-static --disable-dyload" configure_option = "Linux --disable-samples --disable-tests --disable-extras --enable-static --disable-dyload"
configure_script = "./runConfigureICU" configure_script = "./runConfigureICU"
subsource_dir = "source"
@property @command("download_data")
def data_path(self): def _download_data(self, context):
return pj(ARCHIVE_DIR, self.data_name) self.buildEnv.download(self.data)
@command("download_data", autoskip=True) @command("copy_data")
def _download_data(self, log): def _copy_data(self, context):
if os.path.exists(self.data_path): context.try_skip(self.source_path)
sha256 = get_sha256(self.data_path) shutil.copyfile(pj(self.buildEnv.ARCHIVE_DIR, self.data.name), pj(self.source_path, 'data', 'in', self.data.name))
if sha256 == self.data_sha256:
raise SkipCommand()
os.remove(self.data_path)
remote = REMOTE_PREFIX + self.data_name
urllib.request.urlretrieve(remote, self.data_path)
@command("copy_data", autoskip=True) def prepare(self):
def _copy_data(self, log): super().prepare()
shutil.copyfile(self.data_path, pj(self.source_path, 'data', 'in', self.data_name))
def prepare(self, options):
super().prepare(options)
self._download_data() self._download_data()
self._copy_data() self._copy_data()
@ -442,46 +508,51 @@ class Zimlib(Dependency, GitCloneMixin, MesonMixin):
git_remote = "https://github.com/mgautierfr/openzim" git_remote = "https://github.com/mgautierfr/openzim"
git_dir = "openzim" git_dir = "openzim"
git_ref = "meson" git_ref = "meson"
source_dir = "openzim/zimlib" subsource_dir = "zimlib"
class Kiwixlib(Dependency, GitCloneMixin, MesonMixin): class Kiwixlib(Dependency, GitCloneMixin, MesonMixin):
name = "kiwix-lib" name = "kiwix-lib"
git_remote = "https://github.com/kiwix/kiwix-lib.git" git_remote = "https://github.com/kiwix/kiwix-lib.git"
git_dir = "kiwix-lib" git_dir = "kiwix-lib"
source_dir = "kiwix-lib" configure_option = "-Dctpp2-install-prefix={buildEnv.install_dir}"
configure_option = "-Dctpp2-install-prefix={options.install_dir}"
class KiwixTools(Dependency, GitCloneMixin, MesonMixin): class KiwixTools(Dependency, GitCloneMixin, MesonMixin):
name = "kiwix-tools" name = "kiwix-tools"
git_remote = "https://github.com/kiwix/kiwix-tools.git" git_remote = "https://github.com/kiwix/kiwix-tools.git"
git_dir = "kiwix-tools" git_dir = "kiwix-tools"
source_dir = "kiwix-tools" configure_option = "-Dctpp2-install-prefix={buildEnv.install_dir}"
configure_option = "-Dctpp2-install-prefix={options.install_dir}"
class Project: class Builder:
def __init__(self, options): def __init__(self, buildEnv):
self.options = options self.buildEnv = buildEnv
self.dependencies = [UUID(), Xapian(), CTPP2(), Pugixml(), Zimlib(), MicroHttpd(), Icu(), Kiwixlib(), KiwixTools()] self.dependencies = [UUID(buildEnv),
os.makedirs(SOURCE_DIR, exist_ok=True) Xapian(buildEnv),
os.makedirs(ARCHIVE_DIR, exist_ok=True) CTPP2(buildEnv),
Pugixml(buildEnv),
Zimlib(buildEnv),
MicroHttpd(buildEnv),
Icu(buildEnv),
Kiwixlib(buildEnv),
KiwixTools(buildEnv)
]
def prepare(self): def prepare(self):
for dependency in self.dependencies: for dependency in self.dependencies:
print("prepare {} :".format(dependency.name)) print("prepare {} :".format(dependency.name))
dependency.prepare(self.options) dependency.prepare()
def build(self): def build(self):
for dependency in self.dependencies: for dependency in self.dependencies:
print("build {} :".format(dependency.name)) print("build {} :".format(dependency.name))
dependency.build(self.options) dependency.build()
def parse_args(): def parse_args():
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument('install_dir') parser.add_argument('install_dir')
parser.add_argument('--libprefix', default=default_libdir()) parser.add_argument('--libprefix', default=None)
parser.add_argument('--target_arch', default="x86_64") parser.add_argument('--target_arch', default="x86_64")
parser.add_argument('--build_static', action="store_true") parser.add_argument('--build_static', action="store_true")
return parser.parse_args() return parser.parse_args()
@ -489,11 +560,12 @@ def parse_args():
if __name__ == "__main__": if __name__ == "__main__":
options = parse_args() options = parse_args()
options.install_dir = os.path.abspath(options.install_dir) options.install_dir = os.path.abspath(options.install_dir)
project = Project(options) buildEnv = BuildEnv(options)
builder = Builder(buildEnv)
try: try:
print("[PREPARE]") print("[PREPARE]")
project.prepare() builder.prepare()
print("[BUILD]") print("[BUILD]")
project.build() builder.build()
except StopBuild: except StopBuild:
print("Stopping build due to errors") print("Stopping build due to errors")