diff --git a/README.md b/README.md index b901f4a..4361e28 100644 --- a/README.md +++ b/README.md @@ -129,6 +129,27 @@ $ kiwix-build kiwix-android --android-arch arm # apk for arm architectures (equi $ kiwix-build kiwix-anrdoid --android-arch arm --android-arch arm64 # apk for arm and arm64 architectures ``` +## IOS + +When building for ios, we may want to compile a "fat library", a library +for several architectures. + +To do so, you should directly use the target-platfrom `ios_multi`. +As for `android`, `kiwix-build` will build the library several times +(once for each platform) and then create the fat library. + +``` +$ kiwix-build --target-platform iOS_multi kiwix-lib +``` + +You can specify the supported architectures with the option `--ios-arch`: + +``` +$ kiwix-build --target-platform iOS_multi kiwix-lib # all architetures +$ kiwix-build --target-platform iOS_multi --ios-arch arm --ios-arch arm64 # arm and arm64 arch only +``` + + # Outputs Kiwix-build.py will create several directories: diff --git a/kiwixbuild/__init__.py b/kiwixbuild/__init__.py index 47b3695..41855f9 100644 --- a/kiwixbuild/__init__.py +++ b/kiwixbuild/__init__.py @@ -41,6 +41,10 @@ def parse_args(): help=("Specify the architecture to build for android application/libraries.\n" "Can be specified several times to build for several architectures.\n" "If not specified, all architectures will be build.")) + subgroup.add_argument('--ios-arch', action='append', + help=("Specify the architecture to build for ios application/libraries.\n" + "Can be specified several times to build for several architectures.\n" + "If not specified, all architectures will be build.")) subgroup = parser.add_argument_group('custom app', description="Android custom app specific options") subgroup.add_argument('--android-custom-app', @@ -65,6 +69,9 @@ def parse_args(): sys.exit(1) if not options.android_arch: options.android_arch = ['arm', 'arm64', 'mips', 'mips64', 'x86', 'x86_64'] + if not options.ios_arch: + options.ios_arch = ['armv7', 'arm64', 'i386', 'x86_64'] + return options def main(): diff --git a/kiwixbuild/builder.py b/kiwixbuild/builder.py index 8b4ee44..4ee7dd5 100644 --- a/kiwixbuild/builder.py +++ b/kiwixbuild/builder.py @@ -24,6 +24,10 @@ class Builder: else: target_platform = 'native_dyn' platform = PlatformInfo.get_platform(target_platform, self._targets) + if neutralEnv('distname') not in platform.compatible_hosts: + print(('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): diff --git a/kiwixbuild/dependencies/__init__.py b/kiwixbuild/dependencies/__init__.py index b457188..5850450 100644 --- a/kiwixbuild/dependencies/__init__.py +++ b/kiwixbuild/dependencies/__init__.py @@ -9,6 +9,7 @@ from . import ( gradle, gumbo, icu4c, + ios_fat_lib, kiwix_android, kiwix_custom_app, kiwix_lib, diff --git a/kiwixbuild/dependencies/ios_fat_lib.py b/kiwixbuild/dependencies/ios_fat_lib.py new file mode 100644 index 0000000..fddf107 --- /dev/null +++ b/kiwixbuild/dependencies/ios_fat_lib.py @@ -0,0 +1,52 @@ +import os + +from kiwixbuild.platforms import PlatformInfo +from kiwixbuild.utils import pj, copy_tree, run_command +from kiwixbuild._global import option +from .base import ( + Dependency, + NoopSource, + Builder as BaseBuilder) + + + +class IOSFatLib(Dependency): + name = "_ios_fat_lib" + + Source = NoopSource + + class Builder(BaseBuilder): + + @classmethod + def get_dependencies(self, platfomInfo, alldeps): + base_target = option('target') + return [('iOS_{}'.format(arch), base_target) for arch in option('ios_arch')] + + def _copy_headers(self, context): + plt = PlatformInfo.get_platform('iOS_{}'.format(option('ios_arch')[0])) + include_src = pj(plt.buildEnv.install_dir, 'include') + include_dst = pj(self.buildEnv.install_dir, 'include') + copy_tree(include_src, include_dst) + + def _merge_libs(self, context): + lib_dirs = [] + for arch in option('ios_arch'): + plt = PlatformInfo.get_platform('iOS_{}'.format(arch)) + lib_dirs.append(pj(plt.buildEnv.install_dir, 'lib')) + libs = [] + for f in os.listdir(lib_dirs[0]): + if os.path.islink(pj(lib_dirs[0], f)): + continue + if f.endswith('.a') or f.endswith('.dylib'): + libs.append(f) + os.makedirs(pj(self.buildEnv.install_dir, 'lib'), exist_ok=True) + command_tmp = "lipo -create {input} -output {output}" + for l in libs: + command = command_tmp.format( + input=" ".join(pj(d, l) for d in lib_dirs), + output=pj(self.buildEnv.install_dir, 'lib', l)) + run_command(command, self.buildEnv.install_dir, context) + + def build(self): + self.command('copy_headers', self._copy_headers) + self.command('merge_libs', self._merge_libs) diff --git a/kiwixbuild/platforms/base.py b/kiwixbuild/platforms/base.py index 44af29b..71edc13 100644 --- a/kiwixbuild/platforms/base.py +++ b/kiwixbuild/platforms/base.py @@ -32,16 +32,10 @@ class PlatformInfo(metaclass=_MetaPlatform): print("Should not got there.") print(cls.all_running_platforms) raise KeyError(name) - sys.exit(-1) cls.all_running_platforms[name] = cls.all_platforms[name](targets) return cls.all_running_platforms[name] def __init__(self, targets): - if neutralEnv('distname') not in self.compatible_hosts: - print(('ERROR: The target platform {} cannot be build on host {}.\n' - 'Select another target platform, or change your host system.' - ).format(self.name, neutralEnv('distname'))) - sys.exit(-1) self.all_running_platforms[self.name] = self self.buildEnv = BuildEnv(self) self.setup_toolchains(targets) diff --git a/kiwixbuild/platforms/ios.py b/kiwixbuild/platforms/ios.py index 499a8b3..1459741 100644 --- a/kiwixbuild/platforms/ios.py +++ b/kiwixbuild/platforms/ios.py @@ -1,9 +1,9 @@ import subprocess -from .base import PlatformInfo +from .base import PlatformInfo, MetaPlatformInfo from kiwixbuild.utils import pj, xrun_find - +from kiwixbuild._global import option class iOSPlatformInfo(PlatformInfo): build = 'iOS' @@ -84,17 +84,32 @@ class iOSArmv7(iOSPlatformInfo): class iOSArm64(iOSPlatformInfo): name = 'iOS_arm64' arch = cpu = 'arm64' - arch_full = 'arm-apple-darwin' + arch_full = 'aarch64-apple-darwin' sdk_name = 'iphoneos' class iOSi386(iOSPlatformInfo): name = 'iOS_i386' arch = cpu = 'i386' - arch_full = '' + arch_full = 'i386-apple-darwin' sdk_name = 'iphonesimulator' class iOSx64(iOSPlatformInfo): name = 'iOS_x86_64' arch = cpu = 'x86_64' - arch_full = '' + arch_full = 'x86_64-apple-darwin' sdk_name = 'iphonesimulator' + +class IOS(MetaPlatformInfo): + name = "iOS_multi" + compatible_hosts = ['Darwin'] + + @property + def subPlatformNames(self): + return ['iOS_{}'.format(arch) for arch in option('ios_arch')] + + def add_targets(self, targetName, targets): + super().add_targets(targetName, targets) + return PlatformInfo.add_targets(self, '_ios_fat_lib', targets) + + def __str__(self): + return self.name