diff --git a/.github/scripts/build_definition.py b/.github/scripts/build_definition.py index 74617a2..4966314 100644 --- a/.github/scripts/build_definition.py +++ b/.github/scripts/build_definition.py @@ -30,6 +30,7 @@ BUILD_DEF = """ | macos | macOS_arm64_static | | | BP | BP | | macos-arm64 | | macos | macOS_arm64_mixed | BP | BP | | | | macos-arm64 | | macos | macOS_x86_64 | B | B | | | | | + | macos | apple_all_static | | BP | | | | xcframework | ---------------------------------------------------------------------------------------------- | | flatpak | | | | | BP | | | | native_static | d | d | dBPSD | dBPSD | | linux-x86_64 | diff --git a/.github/scripts/common.py b/.github/scripts/common.py index 26621a1..bf635cf 100644 --- a/.github/scripts/common.py +++ b/.github/scripts/common.py @@ -12,6 +12,7 @@ import requests from build_definition import get_platform_name +from kiwixbuild.dependencies.apple_xcframework import AppleXCFramework from kiwixbuild.versions import ( main_project_versions, release_versions, @@ -102,6 +103,7 @@ EXPORT_FILES = { "libkiwix": ( INSTALL_DIR, ( + "lib/CoreKiwix.xcframework/", "lib/*/libkiwix.so", "lib/*/libkiwix.so.{version}".format( version=main_project_versions["libkiwix"] @@ -279,6 +281,13 @@ def make_deps_archive(target=None, name=None, full=False): print_message("Create archive {}.", archive_name) files_to_archive = list(filter_install_dir(INSTALL_DIR)) files_to_archive += HOME.glob("BUILD_*/LOGS") + if PLATFORM_TARGET == "apple_all_static": + for subplatform in AppleXCFramework.subPlatformNames: + base_dir = HOME / "BUILD_{}".format(subplatform) + files_to_archive += filter_install_dir(base_dir / "INSTALL") + if (base_dir / "meson_cross_file.txt").exists(): + files_to_archive.append(base_dir / "meson_cross_file.txt") + if PLATFORM_TARGET.endswith("_mixed"): static_platform = PLATFORM_TARGET.replace("_mixed", "_static") files_to_archive += filter_install_dir(HOME / ("BUILD_" + static_platform) / "INSTALL") @@ -309,6 +318,8 @@ def make_deps_archive(target=None, name=None, full=False): files_to_archive += (HOME / "BUILD_native_dyn").glob("*/.*_ok") files_to_archive += (HOME / "BUILD_native_static").glob("*/.*_ok") files_to_archive += HOME.glob("BUILD_android*/**/.*_ok") + files_to_archive += HOME.glob("BUILD_macOS*/**/.*_ok") + files_to_archive += HOME.glob("BUILD_iOS*/**/.*_ok") files_to_archive += SOURCE_DIR.glob("*/.*_ok") files_to_archive += SOURCE_DIR.glob("zim-testing-suite-*/*") diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 77a0d44..ee295fe 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -151,6 +151,7 @@ jobs: - macOS_arm64_static - macOS_arm64_mixed - macOS_x86_64 + - apple_all_static runs-on: macos-13 env: SSH_KEY: /tmp/id_rsa diff --git a/.github/workflows/releaseNigthly.yml b/.github/workflows/releaseNigthly.yml index 2166e66..85be524 100644 --- a/.github/workflows/releaseNigthly.yml +++ b/.github/workflows/releaseNigthly.yml @@ -138,6 +138,7 @@ jobs: - native_mixed - macOS_arm64_static - macOS_arm64_mixed + - apple_all_static runs-on: macos-13 env: SSH_KEY: /tmp/id_rsa diff --git a/kiwixbuild/dependencies/apple_xcframework.py b/kiwixbuild/dependencies/apple_xcframework.py new file mode 100644 index 0000000..739bbb6 --- /dev/null +++ b/kiwixbuild/dependencies/apple_xcframework.py @@ -0,0 +1,101 @@ +import os +import shutil +from pathlib import Path + +from kiwixbuild.platforms import PlatformInfo +from kiwixbuild.utils import pj, run_command +from .base import Dependency, NoopSource, Builder as BaseBuilder + + +class AppleXCFramework(Dependency): + name = "apple_xcframework" + subPlatformNames = ["macOS_x86_64", "macOS_arm64_static", "iOS_x86_64", "iOS_arm64"] + Source = NoopSource + + class Builder(BaseBuilder): + @property + def all_subplatforms(self): + return self.buildEnv.platformInfo.subPlatformNames + + @property + def macos_subplatforms(self): + return [ + target for target in self.all_subplatforms if target.startswith("macOS") + ] + + @property + def ios_subplatforms(self): + return [ + target for target in self.all_subplatforms if target.startswith("iOS") + ] + + @classmethod + def get_dependencies(cls, platfomInfo, alldeps): + return [ + (target, "libkiwix") for target in AppleXCFramework.subPlatformNames + ] + + @property + def final_path(self): + return pj(self.buildEnv.install_dir, "lib", "CoreKiwix.xcframework") + + def _remove_if_exists(self, context): + if not os.path.exists(self.final_path): + return + + shutil.rmtree(self.final_path) + + def _merge_libs(self, context): + """create merged.a in all targets to bundle all static archives""" + xcf_libs = [] + for target in self.all_subplatforms: + static_ars = [] + + plt = PlatformInfo.get_platform(target) + lib_dir = pj(plt.buildEnv.install_dir, "lib") + static_ars = [str(f) for f in Path(lib_dir).glob("*.a")] + + # create merged.a from all *.a in install_dir/lib + command = "libtool -static -o merged.a " + command += " ".join(static_ars) + run_command(command, lib_dir, context) + + # will be included in xcframework + if target in self.ios_subplatforms: + xcf_libs.append(pj(lib_dir, "merged.a")) + + return xcf_libs + + def _make_macos_fat(self, context): + """create fat merged.a in fake macOS_fat install/lib with macOS archs""" + macos_libs = [] + for target in self.macos_subplatforms: + plt = PlatformInfo.get_platform(target) + macos_libs.append(pj(plt.buildEnv.install_dir, "lib", "merged.a")) + + fat_dir = pj(self.buildEnv.build_dir, "macOS_fat") + os.makedirs(fat_dir, exist_ok=True) + + command = "lipo -create -output {fat_dir}/merged.a ".format(fat_dir=fat_dir) + command += " ".join(macos_libs) + run_command(command, self.buildEnv.build_dir, context) + + return [pj(fat_dir, "merged.a")] + + def _build_xcframework(self, xcf_libs, context): + # create xcframework + ref_plat = PlatformInfo.get_platform(self.macos_subplatforms[0]) + command = "xcodebuild -create-xcframework " + for lib in xcf_libs: + command += " -library {lib} -headers {include}".format( + lib=lib, include=pj(ref_plat.buildEnv.install_dir, "include") + ) + command += " -output {dest}".format(dest=self.final_path) + run_command(command, self.buildEnv.build_dir, context) + + def build(self): + xcf_libs = [] + self.command("remove_if_exists", self._remove_if_exists) + xcf_libs += self.command("merge_libs", self._merge_libs) + xcf_libs += self.command("make_macos_fat", self._make_macos_fat) + self.command("build_xcframework", self._build_xcframework, xcf_libs) diff --git a/kiwixbuild/platforms/ios.py b/kiwixbuild/platforms/ios.py index 69cd54d..8256eef 100644 --- a/kiwixbuild/platforms/ios.py +++ b/kiwixbuild/platforms/ios.py @@ -3,6 +3,7 @@ import subprocess from kiwixbuild._global import option from kiwixbuild.utils import pj, xrun_find from .base import PlatformInfo, MetaPlatformInfo, MixedMixin +from kiwixbuild.dependencies.apple_xcframework import AppleXCFramework MIN_MACOS_VERSION = '12.0' @@ -183,3 +184,18 @@ class IOS(MetaPlatformInfo): def __str__(self): return self.name + +class AppleStaticAll(MetaPlatformInfo): + name = "apple_all_static" + compatible_hosts = ['Darwin'] + + @property + def subPlatformNames(self): + return AppleXCFramework.subPlatformNames + + def add_targets(self, targetName, targets): + super().add_targets(targetName, targets) + return PlatformInfo.add_targets(self, 'apple_xcframework', targets) + + def __str__(self): + return self.name