diff --git a/kiwixbuild/buildenv.py b/kiwixbuild/buildenv.py index 15680903..fdca6484 100644 --- a/kiwixbuild/buildenv.py +++ b/kiwixbuild/buildenv.py @@ -100,6 +100,8 @@ def _is_debianlike(self): return os.path.isfile('/etc/debian_version') def _detect_libdir(self): + if getattr(self.platformInfo, 'build', '').startswith('mips'): + return 'lib/' + self.platformInfo.arch_full if self._is_debianlike(): try: pc = subprocess.Popen(['dpkg-architecture', '-qDEB_HOST_MULTIARCH'], diff --git a/kiwixbuild/dependencies/icu4c.py b/kiwixbuild/dependencies/icu4c.py index cc1587a1..ef29e528 100644 --- a/kiwixbuild/dependencies/icu4c.py +++ b/kiwixbuild/dependencies/icu4c.py @@ -20,7 +20,8 @@ class Source(SvnClone): "icu4c_custom_data.patch", "icu4c_noxlocale.patch", "icu4c_rpath.patch", - "icu4c_build_config.patch"] + "icu4c_build_config.patch", + "icu4c_run_tools_w_qemu_if_endianess_differs.patch"] class Builder(MakeBuilder): @@ -41,8 +42,10 @@ def configure_option(self): icu_native_builder = get_target_step( 'icu4c', 'native_static' if platformInfo.static else 'native_dyn') - options += " --with-cross-build={} --disable-tools".format( + options += " --with-cross-build={}".format( icu_native_builder.build_path) + if platformInfo.build == 'iOS': + options += " --disable-tools" if platformInfo.build == 'android': options += " --with-data-packaging=archive" return options diff --git a/kiwixbuild/patches/fixenv-nonstd-libdir b/kiwixbuild/patches/fixenv-nonstd-libdir new file mode 100644 index 00000000..0db8731c --- /dev/null +++ b/kiwixbuild/patches/fixenv-nonstd-libdir @@ -0,0 +1,27 @@ +#!/bin/sh + +BASENAME=`basename $0` +SCRIPT=`realpath $0` +SCRIPTPATH=`dirname $SCRIPT` + +if ! test -L "$0" +then + cd "$SCRIPTPATH" && find -type f | grep -v ".real$" | \ + while read b + do + if hexdump -C "$b" | head -1 | grep -q ELF + then + mv -iv "$b" "$b.real" + ln -s "$BASENAME" "$b" + fi + done +else + for fullarch in "" mips-linux-uclibc + do for libdir in usr/lib lib + do LD_LIBRARY_PATH="${SCRIPTPATH%/bin}/$libdir/$fullarch:$LD_LIBRARY_PATH" + done + done + + export LD_LIBRARY_PATH + exec ${SCRIPTPATH}/$BASENAME.real "$@" +fi diff --git a/kiwixbuild/patches/icu4c_run_tools_w_qemu_if_endianess_differs.patch b/kiwixbuild/patches/icu4c_run_tools_w_qemu_if_endianess_differs.patch new file mode 100644 index 00000000..6a3c35f7 --- /dev/null +++ b/kiwixbuild/patches/icu4c_run_tools_w_qemu_if_endianess_differs.patch @@ -0,0 +1,42 @@ +diff -ur icu4c/source/data/Makefile.in icu4c.patched/source/data/Makefile.in +--- icu4c/source/data/Makefile.in 2018-06-17 03:28:46.646446362 +0200 ++++ icu4c.patched/source/data/Makefile.in 2018-06-17 03:30:44.072860064 +0200 +@@ -577,9 +577,9 @@ + # There must be a nicer way to do this. + + $(CFU_FILES): $(ALL_CFU_SOURCE) $(TOOLBINDIR)/gencfu$(TOOLEXEEXT) $(DAT_FILES) +- $(INVOKE) echo ALL_CFU_SOURCE: $(ALL_CFU_SOURCE) +- $(INVOKE) echo CFU_FILES: $(CFU_FILES) +- $(INVOKE) echo CFU_FILES_SHORT: $(CFU_FILES_SHORT) ++ echo ALL_CFU_SOURCE: $(ALL_CFU_SOURCE) ++ echo CFU_FILES: $(CFU_FILES) ++ echo CFU_FILES_SHORT: $(CFU_FILES_SHORT) + $(INVOKE) $(TOOLBINDIR)/gencfu -c -i $(BUILDDIR) -r $(word 1,$(ALL_CFU_SOURCE)) -w $(word 2,$(ALL_CFU_SOURCE)) -o $@ + + +diff -ur icu4c/source/Makefile.in icu4c.patched/source/Makefile.in +--- icu4c/source/Makefile.in 2018-06-17 03:28:45.222465606 +0200 ++++ icu4c.patched/source/Makefile.in 2018-06-17 03:29:33.757809798 +0200 +@@ -243,9 +243,20 @@ + @(echo "CROSS_ICU_VERSION=$(VERSION)" ;\ + echo "TOOLEXEEXT=$(EXEEXT)" \ + ) > $@ +- @(echo 'TOOLBINDIR=$$(cross_buildroot)/bin' ;\ ++ @(echo '' ;\ ++ echo 'ifneq ($$(ICUDATA_PLATFORM_NAME),$(ICUDATA_PLATFORM_NAME))' ;\ ++ echo 'cross_buildroot=$$(top_builddir)' ;\ ++ echo 'endif' ;\ ++ echo '' ;\ ++ echo 'TOOLBINDIR=$$(cross_buildroot)/bin' ;\ + echo 'TOOLLIBDIR=$$(cross_buildroot)/lib' ;\ + echo "INVOKE=$(LDLIBRARYPATH_ENVVAR)=$(LIBRARY_PATH_PREFIX)"'$$(TOOLLIBDIR):$$(cross_buildroot)/stubdata:$$(cross_buildroot)/tools/ctestfw:$$$$'"$(LDLIBRARYPATH_ENVVAR)" ;\ + echo "PKGDATA_INVOKE=$(LDLIBRARYPATH_ENVVAR)=$(LIBRARY_PATH_PREFIX)"'$$(cross_buildroot)/stubdata:$$(cross_buildroot)/tools/ctestfw:$$(TOOLLIBDIR):$$$$'"$(LDLIBRARYPATH_ENVVAR) " ;\ ++ echo '' ;\ ++ echo 'ifneq ($$(ICUDATA_PLATFORM_NAME),$(ICUDATA_PLATFORM_NAME))' ;\ ++ echo 'export QEMU_SET_ENV:=$$(strip $$(subst $$$$'"$(LDLIBRARYPATH_ENVVAR)"',,$$(INVOKE)))$$(strip $$(subst LD_LIBRARY_PATH=,,$$(QEMU_SET_ENV)))' ;\ ++ echo '$$(eval $$(shell grep host_cpu $$(top_builddir)/config/Makefile.inc))' ;\ ++ echo 'INVOKE=qemu-$$(host_cpu)-static' ;\ ++ echo 'endif' ;\ + echo ) >> $@ + + config/icucross.inc: $(top_builddir)/icudefs.mk $(top_builddir)/Makefile @platform_make_fragment@ diff --git a/kiwixbuild/platforms/__init__.py b/kiwixbuild/platforms/__init__.py index 4b63719b..d7022420 100644 --- a/kiwixbuild/platforms/__init__.py +++ b/kiwixbuild/platforms/__init__.py @@ -6,6 +6,7 @@ armhf, i586, ios, + mips32r2, native, neutral, win32 diff --git a/kiwixbuild/platforms/mips32r2.py b/kiwixbuild/platforms/mips32r2.py new file mode 100644 index 00000000..2b2797ec --- /dev/null +++ b/kiwixbuild/platforms/mips32r2.py @@ -0,0 +1,195 @@ +from .base import PlatformInfo, _SCRIPT_DIR + +from kiwixbuild.utils import pj +from kiwixbuild._global import get_target_step + +from glob import glob +from os import makedirs, chmod, readlink, symlink +from os.path import basename, islink +from re import sub as subst +from shutil import copy2 + +def copy(src, dst, search=None, repl=None, mode=None): + if islink(src): + linkto = readlink(src) + symlink(linkto, dst) + else: + if search is None: + copy2(src, dst) + else: + with open(src, "r") as sources: + lines = sources.readlines() + with open(dst, "w") as sources: + for line in lines: + sources.write(subst(search, repl, line)) + if mode is not None: + chmod(dst, mode) + + +class MIPS32R2PlatformInfo(PlatformInfo): + build = 'mips32r2_glibc_glibcxx' + arch_full = 'mips-linux-gnu' + compatible_hosts = ['fedora', 'debian'] + + def get_cross_config(self): + return { + 'binaries': self.binaries, + 'exec_wrapper_def': '', + 'root_path': self.root_path, + 'extra_libs': [], + 'extra_cflags': [], + 'host_machine': { + 'system': 'linux', + 'lsystem': 'linux', + 'cpu_family': 'mips32r2', + 'cpu': '24kc', + 'endian': 'big', + 'abi': '' + } + } + + @property + def root_path(self): + # apt-get'able debian/ubuntu hard-float glibc glibcxx toolchain + return '/usr/mips-linux-gnu' + + @property + def tcbindir(self): + return pj(self.root_path, 'bin') + + @property + def tcbinprefix(self): + return '../../bin/' + self.arch_full + '-' + + @property + def tclibdir(self): + return pj(self.root_path, 'lib') + + @property + def binaries(self): + binaries = ((k,'{}{}'.format(self.tcbinprefix, v)) + for k, v in (('CC', 'gcc'), + ('CXX', 'g++'), + ('AR', 'ar'), + ('STRIP', 'strip'), + ('WINDRES', 'windres'), + ('RANLIB', 'ranlib'), + ('LD', 'ld')) + ) + return {k:pj(self.tcbindir, v) + for k,v in binaries} + + @property + def exec_wrapper_def(self): + try: + which('qemu-mips-static') + except subprocess.CalledProcessError: + return "" + else: + return "exec_wrapper = 'qemu-mips-static'" + + @property + def configure_option(self): + return '--host={}'.format(self.arch_full) + + def set_env(self, env): + env['PKG_CONFIG_LIBDIR'] = pj(self.tclibdir, 'pkgconfig') + env['CFLAGS'] = " -march=mips32r2 -mtune=24kc "+env['CFLAGS'] + env['CXXFLAGS'] = " -march=mips32r2 -mtune=24kc "+env['CXXFLAGS'] + env['QEMU_LD_PREFIX'] = pj(self.root_path) + env['QEMU_SET_ENV'] = "LD_LIBRARY_PATH={}".format( + ':'.join([ + pj(self.tclibdir), + env['LD_LIBRARY_PATH'] + ])) + + def set_compiler(self, env): + env['CC'] = self.binaries['CC'] + env['CXX'] = self.binaries['CXX'] + + def finalize_setup(self): + super().finalize_setup() + self.buildEnv.cmake_crossfile = self._gen_crossfile('cmake_cross_file.txt') + self.buildEnv.meson_crossfile = self._gen_crossfile('meson_cross_file.txt') + +class MIPS32R2Dyn(MIPS32R2PlatformInfo): + name = MIPS32R2PlatformInfo.build + '_dyn' + static = False + +class MIPS32R2Static(MIPS32R2PlatformInfo): + name = MIPS32R2PlatformInfo.build + '_static' + static = True + + + + +class MIPS32R2_UC_GCXXPlatformInfo(MIPS32R2PlatformInfo): + build = 'mips32r2_uclibc_glibcxx' # "shared, heterogeneous" + arch_full = 'mips-linux-uclibc' + + @property + def root_path(self): + return '/dev/shm/freetz/toolchain/build/mips_gcc-5.5.0_uClibc-0.9.33.2-nptl/mips-linux-uclibc' + + @property + def tcbinprefix(self): + return self.arch_full + '-' + + def set_env(self, env): + super().set_env(env) + env['CFLAGS'] = " -msoft-float -Os -pipe -Wa,--trap "+env['CFLAGS'] + env['CXXFLAGS'] = " -msoft-float -Os -pipe -Wa,--trap "+env['CXXFLAGS'] + +class MIPS32R2_UC_GCXXDyn(MIPS32R2_UC_GCXXPlatformInfo): + name = MIPS32R2_UC_GCXXPlatformInfo.build + '_dyn' + static = False + + def finalize_setup(self): + super().finalize_setup() + d = pj(_SCRIPT_DIR, '..', '..', 'BUILD_'+self.name, 'INSTALL') + + makedirs(pj(d, 'bin'), mode=0o755, exist_ok=True) + copy(pj(_SCRIPT_DIR, '..', 'patches', 'fixenv-nonstd-libdir'), + pj(d, 'bin', 'fixenv-nonstd-libdir'), + search=r'\$\{ARCH_FULL[^}]*\}', + repl=self.arch_full, + mode=0o755) + + d = pj(d, 'lib', self.arch_full) + makedirs(d, mode=0o755, exist_ok=True) + for f in glob(pj(self.tclibdir, 'libstdc++.so*')): + copy(f, pj(d, basename(f))) + +class MIPS32R2_UC_GCXXStatic(MIPS32R2_UC_GCXXPlatformInfo): + name = MIPS32R2_UC_GCXXPlatformInfo.build + '_static' + static = True + + + + +class MIPS32R2_UC_UCXXPlatformInfo(MIPS32R2_UC_GCXXPlatformInfo): + build = 'mips32r2_uclibc_uclibcxx' # "pure, homogeneous" + + def get_cross_config(self): + conf = super().get_cross_config() + conf['extra_libs'] += [ '-lm' ] + return conf + + @property + def binaries(self): + bins = super().binaries + bins['CXX'] += '-uc' + return bins + + def set_env(self, env): + super().set_env(env) + # for mips-linux-uclibc-g++-uc wrapper to find real binary + env['PATH'] = ':'.join([pj(self.tcbindir), env['PATH']]) + +class MIPS32R2_UC_UCXXDyn(MIPS32R2_UC_UCXXPlatformInfo): + name = MIPS32R2_UC_UCXXPlatformInfo.build + '_dyn' + static = False + +class MIPS32R2_UC_UCXXStatic(MIPS32R2_UC_UCXXPlatformInfo): + name = MIPS32R2_UC_UCXXPlatformInfo.build + '_static' + static = True