Skip to content

Commit

Permalink
Add OpenHarmony support to mach and CI (#32507)
Browse files Browse the repository at this point in the history
* 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>
  • Loading branch information
jschwe committed Jun 17, 2024
1 parent bea181f commit 3381f2a
Show file tree
Hide file tree
Showing 6 changed files with 250 additions and 2 deletions.
7 changes: 7 additions & 0 deletions .github/workflows/dispatch-workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,10 @@ jobs:
secrets: inherit
with:
profile: ${{ inputs.profile }}

ohos:
if: ${{ inputs.workflow == 'ohos' }}
name: OpenHarmony
uses: ./.github/workflows/ohos.yml
with:
profile: ${{ inputs.profile }}
8 changes: 8 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ jobs:
profile: "release"
secrets: inherit

build-ohos:
name: OpenHarmony
if: ${{ github.event_name != 'pull_request' }}
uses: ./.github/workflows/ohos.yml
with:
profile: "release"

build-result:
name: Result
runs-on: ubuntu-latest
Expand All @@ -56,6 +63,7 @@ jobs:
- "build-mac"
- "build-linux"
- "build-android"
- "build-ohos"
steps:
- name: Merge build timings
uses: actions/upload-artifact/merge@v4
Expand Down
72 changes: 72 additions & 0 deletions .github/workflows/ohos.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
name: OpenHarmony
on:
workflow_call:
inputs:
profile:
required: false
default: "release"
type: string
workflow_dispatch:
inputs:
profile:
required: false
default: "release"
type: choice
description: "Cargo build profile"
options: [ "release", "debug", "production"]

env:
RUST_BACKTRACE: 1
SHELL: /bin/bash
SCCACHE_GHA_ENABLED: "true"
RUSTC_WRAPPER: "sccache"
CCACHE: "sccache"
CARGO_INCREMENTAL: 0

jobs:
build:
name: OpenHarmony Build
runs-on: ubuntu-22.04
strategy:
matrix:
arch: ['aarch64-unknown-linux-ohos']
steps:
- uses: actions/checkout@v4
if: github.event_name != 'issue_comment' && github.event_name != 'pull_request_target'
with:
fetch-depth: 2
# This is necessary to checkout the pull request if this run was triggered
# via an `issue_comment` action on a pull request.
- uses: actions/checkout@v4
if: github.event_name == 'issue_comment' || github.event_name == 'pull_request_target'
with:
ref: refs/pull/${{ github.event.issue.number || github.event.number }}/head
fetch-depth: 2
- name: Run sccache-cache
uses: mozilla-actions/sccache-action@v0.0.4
- name: Install taplo
uses: baptiste0928/cargo-install@v3
with:
crate: taplo-cli
locked: true
- name: Bootstrap Python
run: python3 -m pip install --upgrade pip virtualenv
- name: Bootstrap dependencies
run: sudo apt update && python3 ./mach bootstrap
- name: Setup OpenHarmony SDK
id: setup_sdk
uses: openharmony-rs/setup-ohos-sdk@v0.1
with:
version: "4.1"
- name: Build (arch ${{ matrix.arch }} profile ${{ inputs.profile }})
env:
OHOS_SDK_NATIVE: ${{ steps.setup_sdk.outputs.ohos_sdk_native }}
run: |
python3 ./mach build --locked --target ${{ matrix.arch }} --${{ inputs.profile }}
cp -r target/cargo-timings target/cargo-timings-ohos-${{ matrix.arch }}
- name: Archive build timing
uses: actions/upload-artifact@v4
with:
name: cargo-timings-ohos-${{ matrix.arch }}
# Using a wildcard here ensures that the archive includes the path.
path: target/cargo-timings-*
145 changes: 145 additions & 0 deletions python/servo/command_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -32,6 +35,7 @@
from os import path
from subprocess import PIPE
from xml.etree.ElementTree import XML
from packaging.version import parse as parse_version

import toml

Expand Down Expand Up @@ -310,6 +314,9 @@ def resolverelative(category, key):
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")

Expand Down Expand Up @@ -343,6 +350,9 @@ def get_binary_path(self, build_type: BuildType, target=None, android=False, asa
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)

Expand Down Expand Up @@ -524,6 +534,7 @@ def build_env(self):
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

Expand Down Expand Up @@ -658,6 +669,134 @@ def to_ndk_bin(prog):

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 = []
Expand Down Expand Up @@ -867,6 +1006,12 @@ def run_cargo_build_like_command(
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)
Expand Down
15 changes: 13 additions & 2 deletions python/servo/try_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class Workflow(str, Enum):
MACOS = "macos"
WINDOWS = "windows"
ANDROID = "android"
OHOS = "ohos"


@dataclass
Expand Down Expand Up @@ -95,6 +96,8 @@ def handle_preset(s: str) -> Optional[JobConfig]:
return JobConfig("MacOS WPT", Workflow.MACOS, wpt_layout=Layout.layout2020)
elif s == "android":
return JobConfig("Android", Workflow.ANDROID)
elif s in ["ohos", "openharmony"]:
return JobConfig("OpenHarmony", Workflow.OHOS)
elif s == "webgpu":
return JobConfig("WebGPU CTS", Workflow.LINUX,
wpt_layout=Layout.layout2020, # reftests are mode for new layout
Expand Down Expand Up @@ -135,7 +138,7 @@ def parse(self, input: str):
self.fail_fast = True
continue # skip over keyword
if word == "full":
words.extend(["linux-wpt", "macos", "windows", "android"])
words.extend(["linux-wpt", "macos", "windows", "android", "ohos"])
continue # skip over keyword

job = handle_preset(word)
Expand Down Expand Up @@ -211,6 +214,14 @@ def test_empty(self):
"profile": "release",
"unit_tests": False,
"wpt_tests_to_run": ""
},
{
"name": "OpenHarmony",
"workflow": "ohos",
"wpt_layout": "none",
"profile": "release",
"unit_tests": False,
"wpt_tests_to_run": ""
}
]})

Expand Down Expand Up @@ -248,7 +259,7 @@ def test_job_merging(self):
self.assertEqual(a, JobConfig("Linux", Workflow.LINUX, unit_tests=True))

def test_full(self):
self.assertDictEqual(json.loads(Config("linux-wpt macos windows android").to_json()),
self.assertDictEqual(json.loads(Config("linux-wpt macos windows android ohos").to_json()),
json.loads(Config("").to_json()))


Expand Down
5 changes: 5 additions & 0 deletions servobuild.example
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,8 @@ media-stack = "auto"
# Defaults to the value of $ANDROID_SDK_ROOT, $ANDROID_NDK_ROOT respectively
#sdk = "/opt/android-sdk"
#ndk = "/opt/android-ndk"

# OpenHarmony
[ohos]
# Defaults to the value of $OHOS_SDK_NATIVE
#ndk = "/path/to/ohos-sdk/<host-os>/native"

0 comments on commit 3381f2a

Please sign in to comment.