diff --git a/README.en.md b/README.en.md index 672d61668a7988da3434cbf11ca37dcfe7f063c1..7e9ebe46f2d69d46d1764187318b8fd547352320 100644 --- a/README.en.md +++ b/README.en.md @@ -56,7 +56,9 @@ This warehouse is based on the extension of Flutter's official engine warehouse 4. Download sdk: Download ohos-sdk-full in [the daily build](http://ci.openharmony.cn/workbench/cicd/dailybuild/dailylist), create a new folder ndk/linux/4.0 in the engine root directory, unzip the native folder in ohos-sdk-full and place it in ndk/linux/4.0 in folder; (For mac environment, please download mac-sdk-full or mac-sdk-m1-full, and the placement directory is ndk/mac/4.0;No need to download OpenHarmony SDK in Windows environment) -5. Start building: engine directory, execute `make` to start building the flutter engine that supports ohos devices. +5. Start building: In the engine directory, execute `make` to start building the flutter engine that supports ohos devices. + +6. Update project: In the engine directory, execute `./update_engine.sh` (Linux/Mac platform) or `update_engine.bat` (Windows platform) ## Embedding layer code construction guide diff --git a/README.md b/README.md index 2de040c7c2045979387b906721afff9574ab5de8..e02286dfc41ea0eaceca86ffa3be4ed440bde1b0 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,9 @@ Flutter Engine (mac环境,请下载mac-sdk-full或者mac-sdk-m1-full,放置目录为ndk/mac/4.0;Windows环境无需下载鸿蒙sdk,请参考《构建基础环境》配置Windows环境) -5. 开始构建:engine目录,执行`make`,即可开始构建支持ohos设备的flutter engine。 +5. 开始构建:在engine目录,执行`make`,即可开始构建支持ohos设备的flutter engine。 + +6. 更新代码:在engine目录,执行`./update_engine.sh`(Linux/Mac平台)或`update_engine.bat`(Windows平台) ## embedding层代码构建指导 diff --git a/attachment/repos/bootstrap/ohos.bat b/attachment/repos/bootstrap/ohos.bat index a52ff9e2971001734cf7d148fab694f00e6a3214..11f503836afb1c8cdb5f47b1f0ed8f3b802bec6d 100644 --- a/attachment/repos/bootstrap/ohos.bat +++ b/attachment/repos/bootstrap/ohos.bat @@ -14,25 +14,8 @@ @echo off setlocal EnableDelayedExpansion -:config_debug_env call python .\src\flutter\tools\gn --unoptimized --runtime-mode=debug --ohos --ohos-cpu=arm64 -EXIT /B 0 - - - -:config_release_env call python .\src\flutter\tools\gn --runtime-mode=release --ohos --unoptimized --ohos-cpu=arm64 -EXIT /B 0 - -:config_host_debug_env -src/flutter/tools/gn "!HOST_OPT!" "--runtime-mode" "!RT_MODE!" "--no-dart-version-git-info" "--full-dart-sdk" "--no-build-web-sdk" "--disable-desktop-embeddings" "--no-build-embedder-examples" "--verbose" "--trace-gn" -EXIT /B 0 - -:config -CALL :config_debug_env -@REM CALL :config_release_env -EXIT /B 0 +ninja -C .\src\out\ohos_debug_unopt_arm64 +ninja -C .\src\out\ohos_release_arm64 -:compile -REM UNKNOWN: {"type":"Pipeline","commands":[{"type":"Command","name":{"text":"find","type":"Word"},"suffix":[{"text":"src/out","type":"Word"},{"text":"-mindepth","type":"Word"},{"text":"1","type":"Word"},{"text":"-maxdepth","type":"Word"},{"text":"1","type":"Word"},{"text":"-type","type":"Word"},{"text":"d","type":"Word"}]},{"type":"Command","name":{"text":"xargs","type":"Word"},"suffix":[{"text":"-n","type":"Word"},{"text":"1","type":"Word"},{"text":"sh","type":"Word"},{"text":"-c","type":"Word"},{"text":"ninja -C $0 || exit 255","type":"Word"}]}]} -EXIT /B 0 diff --git a/attachment/repos/bootstrap/update_engine.bat b/attachment/repos/bootstrap/update_engine.bat new file mode 100644 index 0000000000000000000000000000000000000000..de3d208a6066f587143dbd6a9827dab6c73ffa21 --- /dev/null +++ b/attachment/repos/bootstrap/update_engine.bat @@ -0,0 +1,17 @@ +@rem Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd. +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem http://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. + +@echo off +py -3 .\src\flutter\attachment\scripts\ohos_reverse_patch.py %1 +call git -C .\src\flutter checkout master && git -C .\src\flutter pull origin master +py -3 .\src\flutter\attachment\scripts\ohos_setup.py %1 \ No newline at end of file diff --git a/attachment/repos/bootstrap/update_engine.sh b/attachment/repos/bootstrap/update_engine.sh new file mode 100644 index 0000000000000000000000000000000000000000..be214136b7a310d293b9a8dcefde6b62d21460b5 --- /dev/null +++ b/attachment/repos/bootstrap/update_engine.sh @@ -0,0 +1,17 @@ +# Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#! /bin/bash + +python3 ./src/flutter/attachment/scripts/ohos_reverse_patch.py $1 +git -C ./src/flutter checkout master && git -C ./src/flutter pull origin master +python3 ./src/flutter/attachment/scripts/ohos_setup.py $1 diff --git a/attachment/repos/dart.patch1 b/attachment/repos/dart.patch1 index 9daa97ba76dc97ad9aebc283af66a896b6787559..8ca85171645db046ebdc346d664898d671504a6a 100644 --- a/attachment/repos/dart.patch1 +++ b/attachment/repos/dart.patch1 @@ -102,6 +102,15 @@ index 36c7e9f4fb4..00a1cb64be8 100644 default_warning_flags += [ "-Wno-type-limits" ] } +diff --git a/build/config/gclient_args.gni b/build/config/gclient_args.gni +new file mode 100755 +index 00000000000..69d89776479 +--- /dev/null ++++ b/build/config/gclient_args.gni +@@ -0,0 +1,2 @@ ++# Generated from 'DEPS' ++checkout_llvm = false +\ No newline at end of file diff --git a/build/config/sanitizers/sanitizers.gni b/build/config/sanitizers/sanitizers.gni index c7da74b09fe..8c11b3401dc 100644 --- a/build/config/sanitizers/sanitizers.gni @@ -154,6 +163,22 @@ index e9f8c7a55cd..b1df3aef772 100644 # TODO(GYP): Figure out which of these work and are needed on other platforms. copy("copy_llvm_symbolizer") { if (is_win) { +diff --git a/runtime/BUILD.gn b/runtime/BUILD.gn +index 042b6a45f7e..7f89f9fcd06 100644 +--- a/runtime/BUILD.gn ++++ b/runtime/BUILD.gn +@@ -87,8 +87,10 @@ config("dart_precompiler_config") { + + config("dart_os_config") { + defines = [] +- if (target_os == "linux") { ++ if (target_os == "linux" && !is_mac) { + target_os = "ohos" ++ } else if (is_mac){ ++ target_os = "mac" + } + print("DART TARGET OS: "+target_os ) + if (target_os == "android") { diff --git a/runtime/bin/BUILD.gn b/runtime/bin/BUILD.gn index 5eecfb63c08..14548125acb 100644 --- a/runtime/bin/BUILD.gn @@ -561,14 +586,14 @@ index e04c881411e..fb5f9dd1993 100644 #else return DynamicLibrary::New(kWindowsDynamicLibraryProcessPtr); diff --git a/runtime/platform/globals.h b/runtime/platform/globals.h -index 7122f9f7d08..373e958a322 100644 +index 7122f9f7d08..f8a861e6c54 100644 --- a/runtime/platform/globals.h +++ b/runtime/platform/globals.h @@ -108,6 +108,10 @@ // Check for Android first, to determine its difference from Linux. #define DART_HOST_OS_ANDROID 1 -+#elif defined(DART_TARGET_OS_OHOS) && !defined(__APPLE__) && !defined(_WIN32) ++#elif defined(DART_TARGET_OS_OHOS) && !defined(_WIN32) + +#define DART_HOST_OS_OHOS 1 + diff --git a/attachment/scripts/excute_util.py b/attachment/scripts/excute_util.py index dc233031d974c49832227b4d7e05828e78c2efd5..17e7f28c7c1d7c4728b94c05171fdf09ba8e4318 100644 --- a/attachment/scripts/excute_util.py +++ b/attachment/scripts/excute_util.py @@ -29,26 +29,12 @@ def excute(cmdStr, path=".", log=True): try: proc = subprocess.Popen(cmdStr, cwd=path, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) - # 逐行读取输出结果 - for line in proc.stdout: - if line == b'' and proc.poll() is not None: - break - data = line.strip() - if log: - print(data) - result += data - error_output = proc.stderr.read().strip() - if error_output: - if log: - print("错误输出:", error_output) - err = True - if err: + out, err = proc.communicate() + if proc.returncode != 0: result = '-1' - if log: - print("执行失败", proc.returncode) - else: - if log: - print("执行成功") + if (log): + print("Executing: %s failed. Exit code: %s" % (cmdStr, proc.returncode)) + except subprocess.CalledProcessError as e: if log: print("命令执行错误:", str(e)) @@ -66,12 +52,9 @@ def excute(cmdStr, path=".", log=True): return result # 执行数组命令 - - -def excuteArr(cmdArr, path="."): +def excuteArr(cmdArr, path=".", log = True): str = ' '.join(cmdArr) - return excute(str, path) - + return excute(str, path, log) def getDateStr(date): hour = date.hour diff --git a/attachment/scripts/file_util.py b/attachment/scripts/file_util.py index 32ec08bd67ce49473cf88a7f0499bf7c9fd3678a..28d779a6929a84914da322b3ca6d44525322360c 100644 --- a/attachment/scripts/file_util.py +++ b/attachment/scripts/file_util.py @@ -35,16 +35,18 @@ def copytree(src, dst, symlinks=False, ignore=None): copy_file(s, d) -def copy_file(sourceFile, targetFile): - print("拷贝文件,从{}到{}".format(sourceFile, targetFile)) +def copy_file(sourceFile, targetFile, log=False): + if log: + print("拷贝文件,从{}到{}".format(sourceFile, targetFile)) if os.path.exists(targetFile): os.remove(targetFile) shutil.copy2(sourceFile, targetFile) # 拷贝文件夹 -def copy_dir(sourceFiles, targetFiles): - print("拷贝文件夹,从{}到{}".format(sourceFiles, targetFiles)) +def copy_dir(sourceFiles, targetFiles, log=False): + if log: + print("拷贝文件夹,从{}到{}".format(sourceFiles, targetFiles)) if os.path.exists(targetFiles): print("目标文件夹已存在,退出") pass @@ -54,8 +56,9 @@ def copy_dir(sourceFiles, targetFiles): # 拷贝文件夹中所有文件到目标目录(必须存在),不拷贝文件夹本身 -def copy_files(source_folder, destination_folder): - print("拷贝文件夹内所有文件,从{}到{}".format(source_folder, destination_folder)) +def copy_files(source_folder, destination_folder, log=False): + if log: + print("拷贝文件夹内所有文件,从{}到{}".format(source_folder, destination_folder)) # 获取源文件夹中的所有文件 files = os.listdir(source_folder) diff --git a/attachment/scripts/ohos_reverse_patch.py b/attachment/scripts/ohos_reverse_patch.py index 2930711e75d663ac0ea52e83e00438066c3e2b19..c43013503816f47fdca3bbb1df549c0fee3848f5 100644 --- a/attachment/scripts/ohos_reverse_patch.py +++ b/attachment/scripts/ohos_reverse_patch.py @@ -12,8 +12,9 @@ # limitations under the License. #!/usr/bin/python +import sys import json -import excute_util +import sub_process_with_timeout from operator import itemgetter """ @@ -24,22 +25,48 @@ from operator import itemgetter """ ROOT = './src/flutter/attachment' -def apply_reverse_patch(task): +def apply_reverse_patch(task, log=False): file_path = task['file_path'] target_path = task['target'] - excute_util.excuteArr(['git', 'apply', '-R', file_path], target_path) + retcode,stdout,stderr = sub_process_with_timeout.excuteArr( + ['git', 'apply', '-R', '--ignore-whitespace','--whitespace=nowarn', file_path], target_path, log, timeout=20) + if retcode == 0 and log: + print("Apply reverse succeded. file path:" + file_path) + if log: + print(str(stdout)) + print(str(stderr)) + if retcode != 0 and log: + print("Apply reverse failed. file path:" + file_path + " Error:" + str(stderr)) pass -def doTask(task): +def apply_reverse_check(task, log=False): + file_path = task['file_path'] + target_path = task['target'] + retcode,stdout,stderr = sub_process_with_timeout.excuteArr( + ['git', 'apply', '-R', '--check', '--ignore-whitespace', file_path], target_path, log, timeout=20) + if log: + print("retcode:" + str(retcode)) + print(str(stdout)) + print(str(stderr)) + if retcode != 0 and log: + print("Apply reverse check failed. file path:" + file_path + " Error:" + str(stderr)) + return retcode != '-1' and 'error' not in str(stderr) + +def doTask(task, log=False): if (task['type'] == 'patch'): - apply_reverse_patch(task) + if (apply_reverse_check(task, False)): + apply_reverse_patch(task, log) def parse_config(config_file="{}/scripts/config.json".format(ROOT)): + log = False + if (len(sys.argv) > 1): + if(sys.argv[1] == '-v'): + log = True with open(config_file) as json_file: data = json.load(json_file) data = sorted(data, key=itemgetter('name'), reverse=True) for task in data: - doTask(task) + doTask(task, log) if __name__ == "__main__": parse_config() diff --git a/attachment/scripts/ohos_setup.py b/attachment/scripts/ohos_setup.py index 99ca997854a2c3cffe069bae9aaec0a6144aee8d..a129b955e73a3a1a0a031123af6aebae565ed0fb 100644 --- a/attachment/scripts/ohos_setup.py +++ b/attachment/scripts/ohos_setup.py @@ -12,9 +12,10 @@ # limitations under the License. #!/usr/bin/python +import sys import json import file_util -import excute_util +import sub_process_with_timeout import os """ @@ -28,42 +29,58 @@ import os ROOT = './src/flutter/attachment' REPOS_ROOT = ROOT + '/repos' - -def apply_patch(task): +def apply_patch(task, log=False): file_path = task['file_path'] target_path = task['target'] - excute_util.excuteArr(['git', 'apply', file_path], target_path) + retcode,stdout,stderr = sub_process_with_timeout.excuteArr( + ['git', 'apply', '--ignore-whitespace', '--whitespace=nowarn', file_path], target_path, log, timeout=20) + if retcode == 0 and log: + print("Apply succeded. file path:" + file_path) + if log: + print(str(stdout)) + print(str(stderr)) + if retcode != 0: + print("Apply failed. file path:" + file_path + " Error:" + str(stderr)) pass - -def apply_check(task): +def apply_check(task, log=False): file_path = task['file_path'] target_path = task['target'] - result = excute_util.excuteArr( - ['git', 'apply', '--check', file_path], target_path) - return result != '-1' and 'error' not in result + retcode,stdout,stderr = sub_process_with_timeout.excuteArr( + ['git', 'apply', '--check', '--ignore-whitespace', file_path], target_path, log, timeout=20) + if log: + print("retcode:" + str(retcode)) + print(str(stdout)) + print(str(stderr)) + if retcode != 0: + print("Apply check failed. file path:" + file_path + " Error:" + str(stderr)) + return retcode != -1 and 'error' not in str(stderr) -def doTask(task): +def doTask(task, log=False): sourceFile = "{}/repos/{}".format(ROOT, task['name']) targetFile = task['target'] if (task['type'] == 'dir'): - file_util.copy_dir(sourceFile, targetFile) + file_util.copy_dir(sourceFile, targetFile, log) elif (task['type'] == 'files'): - file_util.copy_files(sourceFile, targetFile) + file_util.copy_files(sourceFile, targetFile, log) elif (task['type'] == 'file'): - file_util.copy_file(sourceFile, targetFile) + file_util.copy_file(sourceFile, targetFile, log) elif (task['type'] == 'patch'): - if apply_check(task): - apply_patch(task) + if apply_check(task, log): + apply_patch(task, log) + pass def parse_config(config_file="{}/scripts/config.json".format(ROOT)): + log = False + if (len(sys.argv) > 1): + if(sys.argv[1] == '-v'): + log = True with open(config_file) as json_file: data = json.load(json_file) for task in data: - doTask(task) - + doTask(task, log) if __name__ == "__main__": parse_config() diff --git a/attachment/scripts/sub_process_with_timeout.py b/attachment/scripts/sub_process_with_timeout.py new file mode 100644 index 0000000000000000000000000000000000000000..36ab5b0bb01cc580df63802625a8b35f668d7f0a --- /dev/null +++ b/attachment/scripts/sub_process_with_timeout.py @@ -0,0 +1,74 @@ +import subprocess +import threading +import time +import os +import signal +import inspect +import ctypes +import tempfile + + +class TimeoutError(Exception): + pass + +class SubProcess(threading.Thread): + + def __init__(self, cmd, path, timeout=5, log = False): + super(SubProcess,self).__init__() + self.cmd = cmd + self.event = threading.Event() + self.stdout = "" + self.stderr = "" + self.retcode = None + self.timeout = timeout + self.path = path + self.log = log + self.sub = None + + def run(self): + try: + start_time = time.time() + read_flag = end_flag = False + PIPE = subprocess.PIPE + self.sub = subprocess.Popen(self.cmd, cwd=self.path, shell=True, stderr=PIPE, stdout=PIPE, text=True) + while not self.event.is_set() and self.sub.poll() is None: + self.stdout += self.sub.stdout.read() + time.sleep(0.05) + self.stderr +=self.sub.stderr.read() + if (time.time()-start_time) > self.timeout: + self.retcode = -2 + self.sub.stderr = TimeoutError('执行超时:' + self.cmd) + return + self.sub.stdout.close() + self.sub.stderr.close() + self.retcode = self.sub.returncode + except Exception as ex: + self.retcode = -1 + self.stderr = ex + self.event.set() + self.sub.stdout.close() + self.sub.stderr.close() + + def stop(self): + self.event.set() + +# 执行数组命令 +def excuteArr(cmdArr, path=".", log = True, timeout=10): + str = ' '.join(cmdArr) + return execCommandEx(str, path, log, timeout) + +def execCommandEx(cmd, path = ".", log = False, timeout=10): + start_time = end_time = time.time() + sub = SubProcess(cmd, path, 10, log) + sub.daemon = True + sub.start() + while True: + if int(time.time() - start_time) > int(timeout): + sub.retcode = -1 + sub.stderr = TimeoutError('执行超时:' + cmd) + sub.stop() + if not sub.is_alive() or sub.event.is_set(): + break + time.sleep(0.1) + end_time = time.time() + return sub.retcode,sub.stdout,sub.stderr