aboutsummaryrefslogtreecommitdiffstats
path: root/python/servo/command_base.py
diff options
context:
space:
mode:
authorJonathan Schwender <55576758+jschwe@users.noreply.github.com>2024-06-17 13:27:23 +0200
committerGitHub <noreply@github.com>2024-06-17 11:27:23 +0000
commit3381f2a70442aa6a6c31a0bc4a4c3601299631f5 (patch)
tree03ab9519c9bc17b7070392a0bf8df6e37bbed810 /python/servo/command_base.py
parentbea181f5d52c8ac088328f72dc36ef503a5420a9 (diff)
downloadservo-3381f2a70442aa6a6c31a0bc4a4c3601299631f5.tar.gz
servo-3381f2a70442aa6a6c31a0bc4a4c3601299631f5.zip
Add OpenHarmony support to mach and CI (#32507)
* Add ohos to mach Signed-off-by: Jonathan Schwender <jonathan.schwender@huawei.com> * Add OpenHarmony build to CI * Rename ohos sdk action I decided to rename the upstream ohos sdk action to setup-ohos-sdk, making it clearer that is a github action repository. Signed-off-by: Jonathan Schwender <schwenderjonathan@gmail.com> * Remove commented line Signed-off-by: Jonathan Schwender <jonathan.schwender@huawei.com> --------- Signed-off-by: Jonathan Schwender <jonathan.schwender@huawei.com> Signed-off-by: Jonathan Schwender <schwenderjonathan@gmail.com>
Diffstat (limited to 'python/servo/command_base.py')
-rw-r--r--python/servo/command_base.py145
1 files changed, 145 insertions, 0 deletions
diff --git a/python/servo/command_base.py b/python/servo/command_base.py
index 2fd48512eb0..74ee2f475b4 100644
--- a/python/servo/command_base.py
+++ b/python/servo/command_base.py
@@ -10,6 +10,9 @@
from __future__ import annotations
import contextlib
+import errno
+import json
+import pathlib
from enum import Enum
from typing import Dict, List, Optional
import functools
@@ -32,6 +35,7 @@ from glob import glob
from os import path
from subprocess import PIPE
from xml.etree.ElementTree import XML
+from packaging.version import parse as parse_version
import toml
@@ -310,6 +314,9 @@ class CommandBase(object):
self.config["android"].setdefault("ndk", "")
self.config["android"].setdefault("toolchain", "")
+ self.config.setdefault("ohos", {})
+ self.config["ohos"].setdefault("ndk", "")
+
# Set default android target
self.setup_configuration_for_android_target("armv7-linux-androideabi")
@@ -343,6 +350,9 @@ class CommandBase(object):
elif target:
base_path = path.join(base_path, target)
+ if target is not None and "-ohos" in target:
+ return path.join(base_path, build_type.directory_name(), "libservoshell.so")
+
binary_name = f"servo{servo.platform.get().executable_suffix()}"
binary_path = path.join(base_path, build_type.directory_name(), binary_name)
@@ -524,6 +534,7 @@ class CommandBase(object):
env["LSAN_OPTIONS"] = f"{env.get('LSAN_OPTIONS', '')}:suppressions={ASAN_LEAK_SUPPRESSION_FILE}"
self.build_android_env_if_needed(env)
+ self.build_ohos_env_if_needed(env)
return env
@@ -658,6 +669,134 @@ class CommandBase(object):
env['PKG_CONFIG_SYSROOT_DIR'] = path.join(llvm_toolchain, 'sysroot')
+ def build_ohos_env_if_needed(self, env: Dict[str, str]):
+ if not (self.cross_compile_target and self.cross_compile_target.endswith('-ohos')):
+ return
+
+ # Paths to OpenHarmony SDK and build tools:
+ # Note: `OHOS_SDK_NATIVE` is the CMake variable name the `hvigor` build-system
+ # uses for the native directory of the SDK, so we use the same name to be consistent.
+ if "OHOS_SDK_NATIVE" not in env and self.config["ohos"]["ndk"]:
+ env["OHOS_SDK_NATIVE"] = self.config["ohos"]["ndk"]
+
+ if "OHOS_SDK_NATIVE" not in env:
+ print("Please set the OHOS_SDK_NATIVE environment variable to the location of the `native` directory "
+ "in the OpenHarmony SDK.")
+ sys.exit(1)
+
+ ndk_root = pathlib.Path(env["OHOS_SDK_NATIVE"])
+
+ if not ndk_root.is_dir():
+ print(f"OHOS_SDK_NATIVE is not set to a valid directory: `{ndk_root}`")
+ sys.exit(1)
+
+ ndk_root = ndk_root.resolve()
+ package_info = ndk_root.joinpath("oh-uni-package.json")
+ try:
+ with open(package_info) as meta_file:
+ meta = json.load(meta_file)
+ ohos_api_version = int(meta['apiVersion'])
+ ohos_sdk_version = parse_version(meta['version'])
+ if ohos_sdk_version < parse_version('4.0'):
+ print("Warning: mach build currently assumes at least the OpenHarmony 4.0 SDK is used.")
+ print(f"Info: The OpenHarmony SDK {ohos_sdk_version} is targeting API-level {ohos_api_version}")
+ except Exception as e:
+ print(f"Failed to read metadata information from {package_info}")
+ print(f"Exception: {e}")
+
+ # The OpenHarmony SDK for Windows hosts currently does not contain a libclang shared library,
+ # which is required by `bindgen` (see issue
+ # https://gitee.com/openharmony/third_party_llvm-project/issues/I8H50W). Using upstream `clang` is currently
+ # also not easily possible, since `libcxx` support still needs to be upstreamed (
+ # https://github.com/llvm/llvm-project/pull/73114).
+ os_type = platform.system().lower()
+ if os_type not in ["linux", "darwin"]:
+ raise Exception("OpenHarmony builds are currently only supported on Linux and macOS Hosts.")
+
+ llvm_toolchain = ndk_root.joinpath("llvm")
+ llvm_bin = llvm_toolchain.joinpath("bin")
+ ohos_sysroot = ndk_root.joinpath("sysroot")
+ if not (llvm_toolchain.is_dir() and llvm_bin.is_dir()):
+ print(f"Expected to find `llvm` and `llvm/bin` folder under $OHOS_SDK_NATIVE at `{llvm_toolchain}`")
+ sys.exit(1)
+ if not ohos_sysroot.is_dir():
+ print(f"Could not find OpenHarmony sysroot in {ndk_root}")
+ sys.exit(1)
+
+ # Note: We don't use the `<target_triple>-clang` wrappers on purpose, since
+ # a) the OH 4.0 SDK does not have them yet AND
+ # b) the wrappers in the newer SDKs are bash scripts, which can cause problems
+ # on windows, depending on how the wrapper is called.
+ # Instead, we ensure that all the necessary flags for the c-compiler are set
+ # via environment variables such as `TARGET_CFLAGS`.
+ def to_sdk_llvm_bin(prog: str):
+ if is_windows():
+ prog = prog + '.exe'
+ llvm_prog = llvm_bin.joinpath(prog)
+ if not llvm_prog.is_file():
+ raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), llvm_prog)
+ return str(llvm_bin.joinpath(prog))
+
+ # CC and CXX should already be set to appropriate host compilers by `build_env()`
+ env['HOST_CC'] = env['CC']
+ env['HOST_CXX'] = env['CXX']
+ env['TARGET_AR'] = to_sdk_llvm_bin("llvm-ar")
+ env['TARGET_RANLIB'] = to_sdk_llvm_bin("llvm-ranlib")
+ env['TARGET_READELF'] = to_sdk_llvm_bin("llvm-readelf")
+ env['TARGET_OBJCOPY'] = to_sdk_llvm_bin("llvm-objcopy")
+ env['TARGET_STRIP'] = to_sdk_llvm_bin("llvm-strip")
+
+ rust_target_triple = str(self.cross_compile_target).replace('-', '_')
+ ndk_clang = to_sdk_llvm_bin("clang")
+ ndk_clangxx = to_sdk_llvm_bin("clang++")
+ env[f'CC_{rust_target_triple}'] = ndk_clang
+ env[f'CXX_{rust_target_triple}'] = ndk_clangxx
+ # The clang target name is different from the LLVM target name
+ clang_target_triple = str(self.cross_compile_target).replace('-unknown-', '-')
+ clang_target_triple_underscore = clang_target_triple.replace('-', '_')
+ env[f'CC_{clang_target_triple_underscore}'] = ndk_clang
+ env[f'CXX_{clang_target_triple_underscore}'] = ndk_clangxx
+ # rustc linker
+ env[f'CARGO_TARGET_{rust_target_triple.upper()}_LINKER'] = ndk_clang
+ # We could also use a cross-compile wrapper
+ env["RUSTFLAGS"] += f' -Clink-arg=--target={clang_target_triple}'
+ env["RUSTFLAGS"] += f' -Clink-arg=--sysroot={ohos_sysroot}'
+
+ env['HOST_CFLAGS'] = ''
+ env['HOST_CXXFLAGS'] = ''
+ ohos_cflags = ['-D__MUSL__', f' --target={clang_target_triple}', f' --sysroot={ohos_sysroot}']
+ if clang_target_triple.startswith('armv7-'):
+ ohos_cflags.extend(['-march=armv7-a', '-mfloat-abi=softfp', '-mtune=generic-armv7-a', '-mthumb'])
+ ohos_cflags_str = " ".join(ohos_cflags)
+ env['TARGET_CFLAGS'] = ohos_cflags_str
+ env['TARGET_CPPFLAGS'] = '-D__MUSL__'
+ env['TARGET_CXXFLAGS'] = ohos_cflags_str
+
+ # CMake related flags
+ cmake_toolchain_file = ndk_root.joinpath("build", "cmake", "ohos.toolchain.cmake")
+ if cmake_toolchain_file.is_file():
+ env[f'CMAKE_TOOLCHAIN_FILE_{rust_target_triple}'] = str(cmake_toolchain_file)
+ else:
+ print(
+ f"Warning: Failed to find the OpenHarmony CMake Toolchain file - Expected it at {cmake_toolchain_file}")
+ env[f'CMAKE_C_COMPILER_{rust_target_triple}'] = ndk_clang
+ env[f'CMAKE_CXX_COMPILER_{rust_target_triple}'] = ndk_clangxx
+
+ # pkg-config
+ pkg_config_path = '{}:{}'.format(str(ohos_sysroot.joinpath("usr", "lib", "pkgconfig")),
+ str(ohos_sysroot.joinpath("usr", "share", "pkgconfig")))
+ env[f'PKG_CONFIG_SYSROOT_DIR_{rust_target_triple}'] = str(ohos_sysroot)
+ env[f'PKG_CONFIG_PATH_{rust_target_triple}'] = pkg_config_path
+
+ # bindgen / libclang-sys
+ env["LIBCLANG_PATH"] = path.join(llvm_toolchain, "lib")
+ env["CLANG_PATH"] = ndk_clangxx
+ env[f'CXXSTDLIB_{clang_target_triple_underscore}'] = "c++"
+ bindgen_extra_clangs_args_var = f'BINDGEN_EXTRA_CLANG_ARGS_{rust_target_triple}'
+ bindgen_extra_clangs_args = env.get(bindgen_extra_clangs_args_var, "")
+ bindgen_extra_clangs_args = bindgen_extra_clangs_args + " " + ohos_cflags_str
+ env[bindgen_extra_clangs_args_var] = bindgen_extra_clangs_args
+
@staticmethod
def common_command_arguments(build_configuration=False, build_type=False):
decorators = []
@@ -867,6 +1006,12 @@ class CommandBase(object):
args += ["--target", target_override]
elif self.cross_compile_target:
args += ["--target", self.cross_compile_target]
+ # The same would apply to android once we merge the jniapi into servoshell
+ if '-ohos' in self.cross_compile_target:
+ # Note: in practice `cargo rustc` should just be used unconditionally.
+ assert command != 'build', "For Android / OpenHarmony `cargo rustc` must be used instead of cargo build"
+ if command == 'rustc':
+ args += ["--lib", "--crate-type=cdylib"]
if "-p" not in cargo_args: # We're building specific package, that may not have features
features = list(self.features)