• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3#
4# Copyright (c) 2022-2024 Huawei Device Co., Ltd.
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#     http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17
18from __future__ import print_function
19from datetime import datetime
20from fnmatch import fnmatch
21import errno
22import json
23import os
24import platform
25import subprocess
26import sys
27from typing import List, Any, Tuple, Union, Optional
28
29CURRENT_FILENAME = os.path.basename(__file__)
30
31
32def str_of_time_now() -> str:
33    return datetime.now().strftime("%Y-%m-%d-%H-%M-%S-%f")[:-3]
34
35
36def _call(cmd: str):
37    print("# %s" % cmd)
38    return subprocess.call(cmd, shell=True)
39
40
41def _write(filename: str, content: str, mode: str):
42    with open(filename, mode) as f:
43        f.write(content)
44
45
46def call_with_output(cmd: str, file: str):
47    print("# %s" % cmd)
48    host = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
49    while True:
50        try:
51            build_data = host.stdout.readline().decode('utf-8')
52            sys.stdout.flush()
53            print(build_data)
54            _write(file, build_data, "a")
55        except OSError as error:
56            if error == errno.ENOENT:
57                print("no such file")
58            elif error == errno.EPERM:
59                print("permission denied")
60            break
61        if not build_data:
62            break
63    host.wait()
64    return host.returncode
65
66
67def enable_ccache():
68    try:
69        ccache_path = subprocess.check_output(['which', 'ccache']).strip().decode()
70    except subprocess.CalledProcessError:
71        print("Error: ccache not found.")
72        return
73    os.environ['CCACHE_EXEC'] = ccache_path
74    os.environ['USE_CCACHE'] = "1"
75
76
77def backup(file: str, mode: str):
78    if os.path.exists(file):
79        with open(file, 'r+') as src_file:
80            src_content = src_file.read()
81            src_file.seek(0)
82            src_file.truncate()
83
84        with open(file[:-4] + "_last.log", mode) as dst_file:
85            dst_file.write(src_content)
86
87
88class ArkPy:
89    # constants determined by designer of this class
90    NAME_OF_OUT_DIR_OF_FIRST_LEVEL = "out"
91    DELIMITER_BETWEEN_OS_CPU_MODE_FOR_COMMAND = "."
92    DELIMITER_FOR_SECOND_OUT_DIR_NAME = "."
93    GN_TARGET_LOG_FILE_NAME = "build.log"
94    UNITTEST_LOG_FILE_NAME = "unittest.log"
95    RUNTIME_CORE_UNITTEST_LOG_FILE_NAME = "runtime_core_unittest.log"
96    TEST262_LOG_FILE_NAME = "test262.log"
97    REGRESS_TEST_LOG_FILE_NAME = "regresstest.log"
98    PREBUILTS_DOWNLOAD_CONFIG_FILE_PATH = \
99        "./arkcompiler/toolchain/build/prebuilts_download/prebuilts_download_config.json"
100    INDENTATION_STRING_PER_LEVEL = "  "  # for help message
101    # In ARG_DICT, "flags" and "description" are must-keys for the leaf-dicts in it.
102    # (Future designer need know.)
103    ARG_DICT = {
104        "os_cpu": {
105            "linux_x64": {
106                "flags": ["linux_x64", "x64"],
107                "description":
108                    "Build for arkcompiler target of target-operating-system linux and "
109                    "target-central-processing-unit x64.",
110                "gn_args": ["target_os=\"linux\"", "target_cpu=\"x64\""],
111                "prefix_of_name_of_out_dir_of_second_level": "x64",
112            },
113            "linux_x86": {
114                "flags": ["linux_x86", "x86"],
115                "description":
116                    "Build for arkcompiler target of target-operating-system linux and "
117                    "target-central-processing-unit x86.",
118                "gn_args": ["target_os=\"linux\"", "target_cpu=\"x86\""],
119                "prefix_of_name_of_out_dir_of_second_level": "x86",
120            },
121            "ohos_arm": {
122                "flags": ["ohos_arm", "arm"],
123                "description":
124                    "Build for arkcompiler target of target-operating-system ohos and "
125                    "target-central-processing-unit arm.",
126                "gn_args": ["target_os=\"ohos\"", "target_cpu=\"arm\""],
127                "prefix_of_name_of_out_dir_of_second_level": "arm",
128            },
129            "ohos_arm64": {
130                "flags": ["ohos_arm64", "arm64"],
131                "description":
132                    "Build for arkcompiler target of target-operating-system ohos and "
133                    "target-central-processing-unit arm64.",
134                "gn_args": ["target_os=\"ohos\"", "target_cpu=\"arm64\""],
135                "prefix_of_name_of_out_dir_of_second_level": "arm64",
136            },
137            "android_arm64": {
138                "flags": ["android_arm64"],
139                "description":
140                    "Build for arkcompiler target of target-operating-system android and "
141                    "target-central-processing-unit arm64.",
142                "gn_args": ["target_os=\"android\"", "target_cpu=\"arm64\""],
143                "prefix_of_name_of_out_dir_of_second_level": "android_arm64",
144            },
145            "mingw_x86_64": {
146                "flags": ["mingw_x86_64"],
147                "description":
148                    "Build for arkcompiler target of target-operating-system MinGW(Minimalist GNU on Windows) and "
149                    "target-central-processing-unit x86_64.",
150                "gn_args": ["target_os=\"mingw\"", "target_cpu=\"x86_64\""],
151                "prefix_of_name_of_out_dir_of_second_level": "mingw_x86_64",
152            },
153            "ohos_mipsel": {
154                "flags": ["ohos_mipsel", "mipsel"],
155                "description":
156                    "Build for arkcompiler target of target-operating-system ohos and "
157                    "target-central-processing-unit mipsel(32-bit little-endian mips).",
158                "gn_args": ["target_os=\"ohos\"", "target_cpu=\"mipsel\""],
159                "prefix_of_name_of_out_dir_of_second_level": "mipsel",
160            },
161            "mac_arm64": {
162                "flags": ["mac_arm64", "arm64"],
163                "description":
164                    "Build for arkcompiler target of target-operating-system linux and "
165                    "target-central-processing-unit arm64.",
166                "gn_args": ["target_os=\"mac\"", "target_cpu=\"arm64\""],
167                "prefix_of_name_of_out_dir_of_second_level": "mac_arm64",
168            },
169            "mac_x86": {
170                "flags": ["mac_x86", "x86"],
171                "description":
172                    "Build for arkcompiler target of target-operating-system mac and "
173                    "target-central-processing-unit x86.",
174                "gn_args": ["target_os=\"mac\"", "target_cpu=\"x86\""],
175                "prefix_of_name_of_out_dir_of_second_level": "mac_x86",
176            },
177        },
178        "mode": {
179            "release": {
180                "flags": ["release", "r"],
181                "description": "Build for arkcompiler target(executables and libraries) for distribution.",
182                "gn_args": ["is_debug=false"],
183                "suffix_of_name_of_out_dir_of_second_level": "release",
184            },
185            "debug": {
186                "flags": ["debug", "d"],
187                "description": "Build for arkcompiler target(executables and libraries) for debugging.",
188                "gn_args": ["is_debug=true"],
189                "suffix_of_name_of_out_dir_of_second_level": "debug",
190            },
191            "fastverify": {
192                "flags": ["fastverify", "fv"],
193                "description": "Build for arkcompiler target(executables and libraries) for fastverify.",
194                "gn_args": ["is_debug=true is_fastverify=true"],
195                "suffix_of_name_of_out_dir_of_second_level": "fastverify",
196            },
197        },
198        "target": {
199            "test262": {
200                "flags": ["test262", "test-262", "test_262", "262test", "262-test", "262_test", "262"],
201                "description": "Compile arkcompiler target and run test262 with arkcompiler target.",
202                "gn_targets_depend_on": ["default"],
203                "arm64_gn_targets_depend_on": ["ark_js_packages"],
204            },
205            "unittest": {
206                "flags": ["unittest", "ut"],
207                "description":
208                    "Compile and run unittest of arkcompiler target. "
209                    "Add --keep-going=N to keep running unittest when errors occured less than N. "
210                    "Add --gn-args=\"run_with_qemu=true\" timeout=\"1200\"\
211                    \"disable_force_gc=true\" to command when running unittest of non-host type with qemu.",
212                "gn_targets_depend_on": ["unittest_packages"],
213            },
214            "runtime_core_unittest": {
215                "flags": ["runtime_core_unittest"],
216                "description":
217                    "Compile and run runtime_core_unittest of arkcompiler target. "
218                    "Add --keep-going=N to keep running runtime_core_unittest when errors occured less than N. ",
219                "gn_targets_depend_on": ["runtime_core_unittest_packages"],
220            },
221            "workload": {
222                "flags": ["workload", "work-load", "work_load"],
223                "description": "Compile arkcompiler target and run workload with arkcompiler target.",
224                "gn_targets_depend_on": ["default"],
225            },
226            "regresstest": {
227                "flags": ["regresstest", "regress_test", "regress", "testregress", "test_regress"],
228                "description": "Compile arkcompiler target and run regresstest with arkcompiler target.",
229                "gn_targets_depend_on": ["default"],
230            },
231            "gn_target": {
232                "flags": ["<name of target in \"*.gn*\" file>"],  # any other flags
233                "description":
234                    "Build for arkcompiler target assigned by user. Targets include group(ets_runtime), "
235                    "ohos_executable(ark_js_vm), ohos_shared_library(libark_jsruntime), "
236                    "ohos_static_library(static_icuuc), ohos_source_set(libark_jsruntime_set), "
237                    "ohos_unittest(EcmaVm_001_Test), action(EcmaVm_001_TestAction) and other target of user-defined "
238                    "template type in \"*.gn*\" file.",
239                "gn_targets_depend_on": [],  # not need, depend on deps of itself in "*.gn*" file
240            },
241        },
242        "option": {
243            "clean": {
244                "flags": ["--clean", "-clean"],
245                "description":
246                    "Clean the root-out-dir(x64.release-->out/x64.release) execept for file args.gn. "
247                    "Then exit.",
248            },
249            "clean-continue": {
250                "flags": ["--clean-continue", "-clean-continue"],
251                "description":
252                    "Clean the root-out-dir(x64.release-->out/x64.release) execept for file args.gn. "
253                    "Then continue to build.",
254            },
255            "gn-args": {
256                "flags": ["--gn-args=*", "-gn-args=*"],
257                "description":
258                    "Pass args(*) to gn command. Example: python3 ark.py x64.release "
259                    "--gn-args=\"bool_declared_in_src_gn=true string_declared_in_src_gn=\\\"abcd\\\" "
260                    "list_declared_in_src_gn=[ \\\"element0\\\", \\\"element1\\\" ] print(list_declared_in_src_gn) "
261                    "exec_script(\\\"script_in_src\\\", [ \\\"arg_to_script\\\" ])\"  .",
262            },
263            "keepdepfile": {
264                "flags": ["--keepdepfile", "-keepdepfile"],
265                "description":
266                    "Keep depfile(\"*.o.d\") generated by commands(CXX, CC ...) called by ninja during compilation.",
267            },
268            "verbose": {
269                "flags": ["--verbose", "-verbose"],
270                "description": "Print full commands(CXX, CC, LINK ...) called by ninja during compilation.",
271            },
272            "keep-going": {
273                "flags": ["--keep-going=*", "-keep-going=*"],
274                "description": "Keep running unittest etc. until errors occured less than N times"
275                               " (use 0 to ignore all errors).",
276            },
277        },
278        "help": {
279            "flags": ["help", "--help", "--h", "-help", "-h"],
280            "description": "Show the usage of ark.py.",
281        },
282    }
283
284    # variables which would change with the change of host_os or host_cpu
285    gn_binary_path = ""
286    ninja_binary_path = ""
287
288    # variables which would change with the change of ark.py command
289    has_cleaned = False
290    enable_verbose = False
291    enable_keepdepfile = False
292    ignore_errors = 1
293
294    def __main__(self, arg_list: list):
295        enable_ccache()
296        # delete duplicate arg in arg_list
297        arg_list = list(dict.fromkeys(arg_list))
298        # match [help] flag
299        if len(arg_list) == 0 or (
300                True in [self.is_dict_flags_match_arg(self.ARG_DICT.get("help"), arg) for arg in arg_list]):
301            print(self.get_help_msg_of_all())
302            return
303        # match [[os_cpu].[mode]] flag
304        [match_success, key_to_dict_in_os_cpu, key_to_dict_in_mode] = self.dict_in_os_cpu_mode_match_arg(arg_list[0])
305        if match_success:
306            self.start_for_matched_os_cpu_mode(key_to_dict_in_os_cpu, key_to_dict_in_mode, arg_list[1:])
307        else:
308            print("\033[92mThe command is not supported! Help message shows below.\033[0m\n{}".format(
309                self.get_help_msg_of_all()))
310        return
311
312    @staticmethod
313    def is_dict_flags_match_arg(dict_to_match: dict, arg_to_match: str) -> bool:
314        for flag in dict_to_match["flags"]:
315            if fnmatch(arg_to_match, flag):
316                return True
317        return False
318
319    @staticmethod
320    def libs_dir(is_arm, is_aot, is_pgo, out_dir, x64_out_dir) -> str:
321        if is_arm and is_aot and is_pgo:
322            return (f"--libs-dir ../../{out_dir}/arkcompiler/ets_runtime:"
323                    f"../../{out_dir}/thirdparty/icu:"
324                    f"../../{out_dir}/third_party/icu:"
325                    f"../../thirdparty/zlib:"
326                    f"../../prebuilts/clang/ohos/linux-x86_64/llvm/lib")
327        if is_arm and is_aot and not is_pgo:
328            return ("--libs-dir ../../prebuilts/clang/ohos/linux-x86_64/llvm/lib"
329                    f":../../{x64_out_dir}/thirdparty/icu/")
330        if not is_arm and is_aot:
331            return (f"--libs-dir ../../{out_dir}/arkcompiler/ets_runtime"
332                    f":../../{out_dir}/thirdparty/icu:"
333                    f"../../{out_dir}/third_party/icu:"
334                    f"../../thirdparty/zlib:"
335                    f"../../prebuilts/clang/ohos/linux-x86_64/llvm/lib")
336        # not is_arm and not is_aot
337        return " --libs-dir ../../prebuilts/clang/ohos/linux-x86_64/llvm/lib"
338
339    @staticmethod
340    def get_cmd(test_suite, test_script_name, test_script_path, gn_args, out_path, x64_out_path, aot_mode, run_pgo,
341                enable_litecg, args_to_cmd, timeout, ignore_list: Optional[str] = None):
342        cmd = [
343            f"cd {test_script_path}",
344            f"&& python3 {test_script_name} {args_to_cmd}",
345            f"--timeout {timeout}",
346            f"--ark-tool=../../{out_path}/arkcompiler/ets_runtime/ark_js_vm",
347            "--ark-frontend=es2panda"
348        ]
349        is_arm = any('target_cpu="arm64"' in arg for arg in gn_args)
350        if is_arm:
351            cmd.append("--ark-arch aarch64")
352            cmd.append(f"--ark-arch-root=../../{out_path}/common/common/libc/")
353            cmd.append(f"--ark-frontend-binary=../../{x64_out_path}/arkcompiler/ets_frontend/es2abc")
354            cmd.append(f"--merge-abc-binary=../../{x64_out_path}/arkcompiler/ets_frontend/merge_abc")
355            if aot_mode:
356                cmd.append(f"--ark-aot-tool=../../{out_path}/arkcompiler/ets_runtime/ark_aot_compiler")
357                if test_suite == "regresstest":
358                    cmd.append(f"--stub-path=../../{out_path}/gen/arkcompiler/ets_runtime/stub.an")
359        else:
360            cmd.append(f"--ark-frontend-binary=../../{out_path}/arkcompiler/ets_frontend/es2abc")
361            cmd.append(f"--merge-abc-binary=../../{out_path}/arkcompiler/ets_frontend/merge_abc")
362            if aot_mode:
363                cmd.append(f"--ark-aot-tool=../../{out_path}/arkcompiler/ets_runtime/ark_aot_compiler")
364                if test_suite == "regresstest":
365                    cmd.append(f"--stub-path=../../{out_path}/gen/arkcompiler/ets_runtime/stub.an")
366
367        cmd.append(ArkPy.libs_dir(
368            is_arm=is_arm,
369            is_aot=aot_mode,
370            is_pgo=run_pgo,
371            out_dir=out_path,
372            x64_out_dir=x64_out_path
373        ))
374
375        if aot_mode:
376            cmd.append("--ark-aot")
377            mode = ["AOT"]
378            if run_pgo:
379                cmd.append("--run-pgo")
380                mode.append("PGO")
381            if enable_litecg:
382                cmd.append("--enable-litecg")
383                mode.append("LiteCG")
384            mode_str = " ".join(mode)
385            print(f"Running {test_suite} in {mode_str} Mode\n")
386
387        if test_suite == "regresstest" and ignore_list:
388            cmd.append(f"--ignore-list {ignore_list}")
389
390        if test_suite == "regresstest":
391            cmd.append(f"--out-dir ../../{out_path}")
392
393        return " ".join(cmd)
394
395    @staticmethod
396    def get_test262_aot_cmd(gn_args, out_path, x64_out_path, run_pgo, enable_litecg, args_to_test262_cmd,
397                            timeout):
398        print("running test262 in AotMode\n")
399        if any('target_cpu="arm64"' in arg for arg in gn_args):
400            if run_pgo:
401                test262_cmd = f"cd arkcompiler/ets_frontend && python3 test262/run_test262.py {args_to_test262_cmd}" \
402                              f" --timeout {timeout}" \
403                              f" --libs-dir ../../{out_path}/arkcompiler/ets_runtime:../../{out_path}/thirdparty/icu:" \
404                              f"../../{out_path}/thirdparty/zlib:../../prebuilts/clang/ohos/linux-x86_64/llvm/lib" \
405                              " --ark-arch aarch64" \
406                              f" --ark-arch-root=../../{out_path}/common/common/libc/" \
407                              f" --ark-tool=../../{out_path}/arkcompiler/ets_runtime/ark_js_vm" \
408                              f" --ark-aot-tool=../../{out_path}/arkcompiler/ets_runtime/ark_aot_compiler" \
409                              f" --ark-frontend-binary=../../{x64_out_path}/arkcompiler/ets_frontend/es2abc" \
410                              f" --merge-abc-binary=../../{x64_out_path}/arkcompiler/ets_frontend/merge_abc" \
411                              " --ark-aot" \
412                              " --ark-frontend=es2panda" \
413                              " --run-pgo"
414            else:
415                test262_cmd = "cd arkcompiler/ets_frontend && python3 test262/run_test262.py {0} --timeout {3}" \
416                              " --libs-dir ../../prebuilts/clang/ohos/linux-x86_64/llvm/lib:../../{2}/thirdparty/icu/" \
417                              " --ark-arch aarch64" \
418                              " --ark-arch-root=../../{1}/common/common/libc/" \
419                              " --ark-aot" \
420                              " --ark-aot-tool=../../{2}/arkcompiler/ets_runtime/ark_aot_compiler" \
421                              " --ark-tool=../../{1}/arkcompiler/ets_runtime/ark_js_vm" \
422                              " --ark-frontend-binary=../../{2}/arkcompiler/ets_frontend/es2abc" \
423                              " --merge-abc-binary=../../{2}/arkcompiler/ets_frontend/merge_abc" \
424                              " --ark-frontend=es2panda".format(args_to_test262_cmd, out_path, x64_out_path, timeout)
425        else:
426            run_pgo_arg = " --run-pgo" if run_pgo else ""
427            test262_cmd = f"cd arkcompiler/ets_frontend && python3 test262/run_test262.py {args_to_test262_cmd}" \
428                          f" --timeout {timeout}" \
429                          f" --libs-dir ../../{out_path}/arkcompiler/ets_runtime:../../{out_path}/thirdparty/icu" \
430                          f":../../{out_path}/thirdparty/zlib:../../prebuilts/clang/ohos/linux-x86_64/llvm/lib" \
431                          f" --ark-tool=../../{out_path}/arkcompiler/ets_runtime/ark_js_vm" \
432                          f" --ark-aot-tool=../../{out_path}/arkcompiler/ets_runtime/ark_aot_compiler" \
433                          f" --ark-frontend-binary=../../{out_path}/arkcompiler/ets_frontend/es2abc" \
434                          f" --merge-abc-binary=../../{out_path}/arkcompiler/ets_frontend/merge_abc" \
435                          " --ark-aot" \
436                          " --ark-frontend=es2panda" \
437                          f" {run_pgo_arg}"
438        if enable_litecg:
439            test262_cmd = test262_cmd + " --enable-litecg"
440        return test262_cmd
441
442    @staticmethod
443    def get_jit_cmd(test_suite, test_script_name, test_script_path, gn_args, out_path, x64_out_path, args_to_cmd,
444                    timeout):
445        print(f"running {test_suite} in JIT mode\n")
446        if any('target_cpu="arm64"' in arg for arg in gn_args):
447            cmd = f"cd {test_script_path} && python3 {test_script_name} {args_to_cmd} --timeout {timeout}" \
448                  f" --libs-dir ../../prebuilts/clang/ohos/linux-x86_64/llvm/lib:../../{out_path}/thirdparty/icu/" \
449                  f":../../{out_path}/thirdparty/bounds_checking_function" \
450                  f":../../{out_path}/arkcompiler/ets_runtime:" \
451                  " --ark-arch aarch64" \
452                  " --run-jit" \
453                  f" --ark-arch-root=../../{out_path}/common/common/libc/" \
454                  f" --ark-aot-tool=../../{x64_out_path}/arkcompiler/ets_runtime/ark_aot_compiler" \
455                  f" --ark-tool=../../{out_path}/arkcompiler/ets_runtime/ark_js_vm" \
456                  f" --ark-frontend-binary=../../{x64_out_path}/arkcompiler/ets_frontend/es2abc" \
457                  f" --merge-abc-binary=../../{x64_out_path}/arkcompiler/ets_frontend/merge_abc" \
458                  " --ark-frontend=es2panda"
459        else:
460            cmd = f"cd arkcompiler/ets_frontend && python3 {test_script_name} {args_to_cmd} --timeout {timeout}" \
461                  f" --libs-dir ../../{out_path}/arkcompiler/ets_runtime:../../{out_path}/thirdparty/icu" \
462                  f":../../{out_path}/thirdparty/zlib:../../prebuilts/clang/ohos/linux-x86_64/llvm/lib" \
463                  " --run-jit" \
464                  f" --ark-tool=../../{out_path}/arkcompiler/ets_runtime/ark_js_vm" \
465                  f" --ark-frontend-binary=../../{out_path}/arkcompiler/ets_frontend/es2abc" \
466                  f" --merge-abc-binary=../../{out_path}/arkcompiler/ets_frontend/merge_abc" \
467                  " --ark-frontend=es2panda"
468        return cmd
469
470    @staticmethod
471    def get_baseline_jit_cmd(test_suite, test_script_name, test_script_path, gn_args, out_path, x64_out_path,
472                             args_to_test262_cmd, timeout):
473        print(f"running {test_suite} in baseline JIT mode\n")
474        if any('target_cpu="arm64"' in arg for arg in gn_args):
475            cmd = f"cd {test_script_path} && python3 {test_script_name} {args_to_test262_cmd} --timeout {timeout}" \
476                  f" --libs-dir ../../prebuilts/clang/ohos/linux-x86_64/llvm/lib" \
477                  f":../../{out_path}/thirdparty/icu" \
478                  f":../../prebuilts/clang/ohos/linux-x86_64/llvm/lib/aarch64-linux-ohos" \
479                  f":../../{out_path}/thirdparty/bounds_checking_function" \
480                  f":../../{out_path}/arkcompiler/ets_runtime" \
481                  f":../../{out_path}/common/common/libc/lib" \
482                  " --ark-arch aarch64" \
483                  " --run-baseline-jit" \
484                  f" --ark-arch-root=../../{out_path}/common/common/libc/" \
485                  f" --ark-aot-tool=../../{x64_out_path}/arkcompiler/ets_runtime/ark_aot_compiler" \
486                  f" --ark-tool=../../{out_path}/arkcompiler/ets_runtime/ark_js_vm" \
487                  f" --ark-frontend-binary=../../{x64_out_path}/arkcompiler/ets_frontend/es2abc" \
488                  f" --merge-abc-binary=../../{x64_out_path}/arkcompiler/ets_frontend/merge_abc" \
489                  " --ark-frontend=es2panda"
490        else:
491            cmd = f"cd {test_script_path} && python3 {test_script_name} {args_to_test262_cmd} --timeout {timeout}" \
492                  f" --libs-dir ../../{out_path}/lib.unstripped/arkcompiler/ets_runtime" \
493                  f":../../{out_path}/thirdparty/icu" \
494                  ":../../prebuilts/clang/ohos/linux-x86_64/llvm/lib" \
495                  f":../../{out_path}/thirdparty/bounds_checking_function/" \
496                  " --run-baseline-jit" \
497                  f" --ark-tool=../../{out_path}/arkcompiler/ets_runtime/ark_js_vm" \
498                  f" --ark-frontend-binary=../../{out_path}/arkcompiler/ets_frontend/es2abc" \
499                  f" --merge-abc-binary=../../{out_path}/arkcompiler/ets_frontend/merge_abc" \
500                  " --ark-frontend=es2panda"
501        return cmd
502
503    @staticmethod
504    def build_args_to_test262_cmd(arg_list):
505        args_to_test262_cmd = []
506
507        disable_force_gc_name = "--disable-force-gc"
508        disable_force_gc_value, arg_list = ArkPy.parse_bool_option(
509            arg_list, option_name=disable_force_gc_name, default_value=False
510        )
511        if disable_force_gc_value:
512            args_to_test262_cmd.extend([disable_force_gc_name])
513
514        threads_name = "--threads"
515        threads_value, arg_list = ArkPy.parse_option(arg_list, option_name=threads_name, default_value=None)
516        if threads_value:
517            args_to_test262_cmd.extend([threads_name, threads_value])
518
519        test_list_name = "--test-list"
520        test_list_value, arg_list = ArkPy.parse_option(arg_list, option_name=test_list_name, default_value=None)
521        if test_list_value is not None:
522            args_to_test262_cmd.extend([test_list_name, test_list_value])
523
524        enable_rm = [arg for arg in arg_list if "enable-rm" in arg]
525        if enable_rm:
526            args_to_test262_cmd.append("--enable-rm")
527            arg_list.remove(enable_rm[0])
528
529        skip_list_name = "--skip-list"
530        skip_list_value, arg_list = ArkPy.parse_option(arg_list, option_name=skip_list_name, default_value=None)
531        if skip_list_value is not None:
532            args_to_test262_cmd.extend([skip_list_name, skip_list_value])
533
534        if len(arg_list) == 0:
535            args_to_test262_cmd.append("--es2021 all")
536        elif len(arg_list) == 1:
537            arg = arg_list[0]
538            if arg == "sendable":
539                args_to_test262_cmd.append("--sendable sendable")
540            elif ".js" in arg:
541                args_to_test262_cmd.append("--file test262/data/test_es2021/{}".format(arg))
542            elif "--abc2program" in arg:
543                args_to_test262_cmd.append("--abc2program --es2021 all")
544            else:
545                args_to_test262_cmd.append("--dir test262/data/test_es2021/{}".format(arg))
546        else:
547            print("\033[92m\"test262\" not support multiple additional arguments.\033[0m\n".format())
548            sys.exit(0)
549
550        return " ".join(args_to_test262_cmd)
551
552    @staticmethod
553    def build_args_to_regress_cmd(arg_list):
554        args_to_regress_cmd = []
555
556        disable_force_gc_name = "--disable-force-gc"
557        disable_force_gc_value, arg_list = ArkPy.parse_bool_option(
558            arg_list, option_name=disable_force_gc_name, default_value=False
559        )
560        if disable_force_gc_value:
561            args_to_regress_cmd.extend([disable_force_gc_name])
562
563        processes_name = "--processes"
564        processes_value, arg_list = ArkPy.parse_option(arg_list, option_name=processes_name, default_value=1)
565        args_to_regress_cmd.extend([processes_name, processes_value])
566
567        test_list_name = "--test-list"
568        test_list_value, arg_list = ArkPy.parse_option(arg_list, option_name=test_list_name, default_value=None)
569        if test_list_value is not None:
570            args_to_regress_cmd.extend([test_list_name, test_list_value])
571        compiler_opt_track_field_name = "--compiler-opt-track-field"
572        compiler_opt_track_field_value, arg_list = ArkPy.parse_bool_option(
573            arg_list, option_name=compiler_opt_track_field_name, default_value=False
574        )
575        if compiler_opt_track_field_value:
576            args_to_regress_cmd.append(f"{compiler_opt_track_field_name}={compiler_opt_track_field_value}")
577        if len(arg_list) == 1:
578            arg = arg_list[0]
579            if ".js" in arg:
580                args_to_regress_cmd.append(f"--test-file {arg}")
581            else:
582                args_to_regress_cmd.append(f"--test-dir {arg}")
583        elif len(arg_list) > 1:
584            print("\033[92m\"regresstest\" not support multiple additional arguments.\033[0m\n".format())
585            sys.exit(0)
586
587        return " ".join([str(arg) for arg in args_to_regress_cmd])
588
589    @staticmethod
590    def parse_option(arg_list: List[str], option_name: str, default_value: Optional[Union[str, int]]) \
591            -> Tuple[Optional[Union[str, int]], List[str]]:
592        option_value, arg_list = ArkPy.__parse_option_with_space(arg_list, option_name)
593        if option_value is None:
594            option_value, arg_list = ArkPy.__parse_option_with_equal(arg_list, option_name)
595        if option_value is None and default_value is not None:
596            option_value = default_value
597        return option_value, arg_list
598
599    @staticmethod
600    def parse_bool_option(arg_list: List[str], option_name: str, default_value: bool) \
601            -> Tuple[bool, List[str]]:
602        if option_name in arg_list:
603            option_index = arg_list.index(option_name)
604            option_value = not default_value
605            arg_list = arg_list[:option_index] + arg_list[option_index + 1:]
606        else:
607            option_value = default_value
608
609        return option_value, arg_list
610
611    @staticmethod
612    def __is_option_value_int(value: Optional[Union[str, int]]) -> Tuple[bool, Optional[int]]:
613        if isinstance(value, int):
614            return True, int(value)
615        else:
616            return False, None
617
618    @staticmethod
619    def __is_option_value_str(value: Optional[Union[str, int]]) -> Tuple[bool, Optional[str]]:
620        if isinstance(value, str):
621            return True, str(value)
622        else:
623            return False, None
624
625    @staticmethod
626    def __get_option_value(option_name: str, value: Optional[Union[str, int]]) -> Union[str, int]:
627        result, res_value = ArkPy.__is_option_value_int(value)
628        if result:
629            return res_value
630        result, res_value = ArkPy.__is_option_value_str(value)
631        if result:
632            return res_value
633        print(f"Invalid '{option_name}' value.")
634        sys.exit(1)
635
636    @staticmethod
637    def __parse_option_with_space(arg_list: List[str], option_name: str) \
638            -> Tuple[Optional[Union[str, int]], List[str]]:
639        if option_name in arg_list:
640            option_index = arg_list.index(option_name)
641            if len(arg_list) > option_index + 1:
642                option_value = ArkPy.__get_option_value(option_name, arg_list[option_index + 1])
643                arg_list = arg_list[:option_index] + arg_list[option_index + 2:]
644            else:
645                print(f"Missing {option_name} value.")
646                sys.exit(1)
647
648            return option_value, arg_list
649        return None, arg_list
650
651    @staticmethod
652    def __parse_option_with_equal(arg_list: List[str], option_name: str) \
653            -> Tuple[Optional[Union[str, int]], List[str]]:
654        for index, arg in enumerate(arg_list):
655            local_option_name = f"{option_name}="
656            if arg.startswith(local_option_name):
657                option_value = arg[len(local_option_name):]
658                if option_value:
659                    option_value = ArkPy.__get_option_value(option_name, option_value)
660                    arg_list = arg_list[:index] + arg_list[index + 1:]
661                    return option_value, arg_list
662                else:
663                    print(f"Missing {option_name} value.")
664                    sys.exit(1)
665        return None, arg_list
666
667    @staticmethod
668    def __get_x64_out_path(out_path) -> str:
669        if 'release' in out_path:
670            return 'out/x64.release'
671        if 'debug' in out_path:
672            return 'out/x64.debug'
673        if 'fastverify' in out_path:
674            return 'out/x64.fastverify'
675        return ""
676
677    def get_binaries(self):
678        host_os = sys.platform
679        host_cpu = platform.machine()
680        try:
681            with open(self.PREBUILTS_DOWNLOAD_CONFIG_FILE_PATH) as file_prebuilts_download_config:
682                prebuilts_download_config_dict = json.load(file_prebuilts_download_config)
683                file_prebuilts_download_config.close()
684            for element in prebuilts_download_config_dict[host_os][host_cpu]["copy_config"]:
685                if element["unzip_filename"] == "gn":
686                    self.gn_binary_path = os.path.join(element["unzip_dir"], element["unzip_filename"])
687                elif element["unzip_filename"] == "ninja":
688                    self.ninja_binary_path = os.path.join(element["unzip_dir"], element["unzip_filename"])
689        except Exception as error:
690            print("\nLogic of getting gn binary or ninja binary does not match logic of prebuilts_download." \
691                  "\nCheck func \033[92m{0} of class {1} in file {2}\033[0m against file {3} if the name of this " \
692                  "file had not changed!\n".format(
693                sys._getframe().f_code.co_name, self.__class__.__name__, CURRENT_FILENAME,
694                self.PREBUILTS_DOWNLOAD_CONFIG_FILE_PATH))
695            raise error
696        if self.gn_binary_path == "" or self.ninja_binary_path == "":
697            print("\nLogic of prebuilts_download may be wrong." \
698                  "\nCheck \033[92mdata in file {0}\033[0m against func {1} of class {2} in file {3}!\n".format(
699                self.PREBUILTS_DOWNLOAD_CONFIG_FILE_PATH, sys._getframe().f_code.co_name, self.__class__.__name__,
700                CURRENT_FILENAME))
701            sys.exit(0)
702        if not os.path.isfile(self.gn_binary_path) or not os.path.isfile(self.ninja_binary_path):
703            print("\nStep for prebuilts_download may be ommited. (\033[92m./prebuilts_download.sh\033[0m)" \
704                  "\nCheck \033[92mwhether gn binary and ninja binary are under directory prebuilts\033[0m!\n".format())
705            sys.exit(0)
706        return
707
708    def which_dict_flags_match_arg(self, dict_including_dicts_to_match: dict, arg_to_match: str) -> str:
709        for key in dict_including_dicts_to_match.keys():
710            if self.is_dict_flags_match_arg(dict_including_dicts_to_match[key], arg_to_match):
711                return key
712        return ""
713
714    def dict_in_os_cpu_mode_match_arg(self, arg: str) -> [bool, str, str]:
715        os_cpu_part = ""
716        mode_part = ""
717        match_success = True
718        key_to_dict_in_os_cpu_matched_arg = ""
719        key_to_dict_in_mode_matched_arg = ""
720        arg_to_list = arg.split(self.DELIMITER_BETWEEN_OS_CPU_MODE_FOR_COMMAND)
721        if len(arg_to_list) == 1:
722            os_cpu_part = arg_to_list[0]
723            mode_part = "release"
724            key_to_dict_in_os_cpu_matched_arg = self.which_dict_flags_match_arg(self.ARG_DICT.get("os_cpu"), os_cpu_part)
725            key_to_dict_in_mode_matched_arg = self.which_dict_flags_match_arg(self.ARG_DICT.get("mode"), mode_part)
726        elif len(arg_to_list) == 2:
727            os_cpu_part = arg_to_list[0]
728            mode_part = arg_to_list[1]
729            key_to_dict_in_os_cpu_matched_arg = self.which_dict_flags_match_arg(self.ARG_DICT.get("os_cpu"), os_cpu_part)
730            key_to_dict_in_mode_matched_arg = self.which_dict_flags_match_arg(self.ARG_DICT.get("mode"), mode_part)
731        else:
732            print("\"\033[92m{0}\033[0m\" combined with more than 2 flags is not supported.".format(arg))
733        if (key_to_dict_in_os_cpu_matched_arg == "") | (key_to_dict_in_mode_matched_arg == ""):
734            match_success = False
735        return [match_success, key_to_dict_in_os_cpu_matched_arg, key_to_dict_in_mode_matched_arg]
736
737    def get_help_msg_of_dict(self, dict_in: dict, indentation_str_current: str, indentation_str_per_level: str) -> str:
738        help_msg = "".format()
739        for key in dict_in.keys():
740            if isinstance(dict_in[key], dict):
741                help_msg += "{0}{1}:\n".format(indentation_str_current, key)
742                help_msg += self.get_help_msg_of_dict(
743                    dict_in[key], indentation_str_current + indentation_str_per_level, indentation_str_per_level)
744            elif key == "flags":
745                help_msg += "{0}{1}: \033[92m{2}\033[0m\n".format(indentation_str_current, key, " ".join(dict_in[key]))
746            elif key == "description":
747                help_msg += "{0}{1}: {2}\n".format(indentation_str_current, key, dict_in[key])
748        return help_msg
749
750    def get_help_msg_of_all(self) -> str:
751        help_msg = "".format()
752        # Command template
753        help_msg += "\033[32mCommand template:\033[0m\n{}\n\n".format(
754            "  python3 ark.py \033[92m[os_cpu].[mode] [gn_target] [option]\033[0m\n"
755            "  python3 ark.py \033[92m[os_cpu].[mode] [test262] [none or --aot] " \
756            "[none or --pgo] [none or --litecg] [none, file or dir] [none or --threads=X] [option]\033[0m\n"
757            "  python3 ark.py \033[92m[os_cpu].[mode] [test262] [none or --jit] [none or --threads=X]\033[0m\n"
758            "  python3 ark.py \033[92m[os_cpu].[mode] [test262] [none or --baseline-jit] [none or --enable-rm] " \
759            "[none or --threads=X and/or --test-list TEST_LIST_NAME]\033[0m\n"
760            "  python3 ark.py \033[92m[os_cpu].[mode] [unittest] [option]\033[0m\n"
761            "  python3 ark.py \033[92m[os_cpu].[mode] [runtime_core_unittest] [option]\033[0m\n"
762            "  python3 ark.py \033[92m[os_cpu].[mode] [regresstest] [none, file or dir] " \
763              "[none or --processes X and/or --test-list TEST_LIST_NAME]\033[0m\n")
764        # Command examples
765        help_msg += "\033[32mCommand examples:\033[0m\n{}\n\n".format(
766            "  python3 ark.py \033[92mx64.release\033[0m\n"
767            "  python3 ark.py \033[92mx64.release ets_runtime\033[0m\n"
768            "  python3 ark.py \033[92mx64.release ark_js_vm es2panda\033[0m\n"
769            "  python3 ark.py \033[92mx64.release ark_js_vm es2panda --clean\033[0m\n"
770            "  python3 ark.py \033[92mx64.release test262\033[0m\n"
771            "  python3 ark.py \033[92mx64.release test262 --threads=16\033[0m\n"
772            "  python3 ark.py \033[92mx64.release test262 --aot --pgo --litecg\033[0m\n"
773            "  python3 ark.py \033[92mx64.release test262 --aot --pgo --litecg --threads=8\033[0m\n"
774            "  python3 ark.py \033[92mx64.release test262 --jit --enable-rm\033[0m\n"
775            "  python3 ark.py \033[92mx64.release test262 --baseline-jit\033[0m\n"
776            "  python3 ark.py \033[92mx64.release test262 built-ins/Array\033[0m\n"
777            "  python3 ark.py \033[92mx64.release test262 built-ins/Array/name.js\033[0m\n"
778            "  python3 ark.py \033[92mx64.release unittest\033[0m\n"
779            "  python3 ark.py \033[92mx64.release runtime_core_unittest\033[0m\n"
780            "  python3 ark.py \033[92mx64.release regresstest\033[0m\n"
781            "  python3 ark.py \033[92mx64.release regresstest --processes=4\033[0m\n"
782            "  python3 ark.py \033[92mx64.release workload\033[0m\n"
783            "  python3 ark.py \033[92mx64.release workload report\033[0m\n"
784            "  python3 ark.py \033[92mx64.release workload report dev\033[0m\n"
785            "  python3 ark.py \033[92mx64.release workload report dev -20\033[0m\n"
786            "  python3 ark.py \033[92mx64.release workload report dev -20 10\033[0m\n"
787            "  python3 ark.py \033[92mx64.release workload report dev -20 10 weekly_workload\033[0m\n")
788        # Arguments
789        help_msg += "\033[32mArguments:\033[0m\n{}".format(
790            self.get_help_msg_of_dict(
791                self.ARG_DICT, self.INDENTATION_STRING_PER_LEVEL, self.INDENTATION_STRING_PER_LEVEL))
792        return help_msg
793
794    def clean(self, out_path: str):
795        if not os.path.exists(out_path):
796            print("Path \"{}\" does not exist! No need to clean it.".format(out_path))
797        else:
798            print("=== clean start ===")
799            code = _call("{0} clean {1}".format(self.gn_binary_path, out_path))
800            if code != 0:
801                print("=== clean failed! ===\n")
802                sys.exit(code)
803            print("=== clean success! ===\n")
804        return
805
806    def build_for_gn_target(self, out_path: str, gn_args: list, arg_list: list, log_file_name: str):
807        # prepare log file
808        build_log_path = os.path.join(out_path, log_file_name)
809        backup(build_log_path, "w")
810        if arg_list is not None:
811            build_target = " ".join([str(arg).strip() for arg in arg_list
812                                     if arg is not None or len(str(arg).strip()) > 0])
813        else:
814            build_target = ""
815        str_to_build_log = "================================\nbuild_time: {0}\nbuild_target: {1}\n\n".format(
816            str_of_time_now(), build_target)
817        _write(build_log_path, str_to_build_log, "a")
818        # gn command
819        print("=== gn gen start ===")
820        code = call_with_output(
821            "{0} gen {1} --args=\"{2}\" --export-compile-commands".format(
822                self.gn_binary_path, out_path, " ".join(gn_args).replace("\"", "\\\"")),
823            build_log_path)
824        if code != 0:
825            print("=== gn gen failed! ===\n")
826            sys.exit(code)
827        else:
828            print("=== gn gen success! ===\n")
829        # ninja command
830        # Always add " -d keeprsp" to ninja command to keep response file("*.rsp"), thus we could get shared libraries
831        # of an excutable from its response file.
832        ninja_cmd = \
833            self.ninja_binary_path + \
834            (" -v" if self.enable_verbose else "") + \
835            (" -d keepdepfile" if self.enable_keepdepfile else "") + \
836            " -d keeprsp" + \
837            " -C {}".format(out_path) + \
838            " {}".format(" ".join(arg_list if arg_list else [])) + \
839            " -k {}".format(self.ignore_errors)
840        print(ninja_cmd)
841        code = call_with_output(ninja_cmd, build_log_path)
842        if code != 0:
843            print("=== ninja failed! ===\n")
844            sys.exit(code)
845        else:
846            print("=== ninja success! ===\n")
847        return
848
849    def call_build_gn_target(self, gn_args, out_path, x64_out_path, test_suite, log_file_name):
850        if any('target_cpu="arm64"' in arg for arg in gn_args):
851            gn_args.append("so_dir_for_qemu=\"../../{0}/common/common/libc/\"".format(out_path))
852            gn_args.append("run_with_qemu=true".format(out_path))
853            if not os.path.exists(x64_out_path):
854                os.makedirs(x64_out_path)
855            self.build_for_gn_target(
856                x64_out_path,
857                ['target_os="linux"', 'target_cpu="x64"', 'is_debug=false'],
858                self.ARG_DICT.get("target").get(test_suite).get("gn_targets_depend_on"),
859                log_file_name)
860            self.build_for_gn_target(
861                out_path,
862                gn_args,
863                self.ARG_DICT.get("target").get(test_suite).get("arm64_gn_targets_depend_on"),
864                log_file_name)
865        else:
866            self.build_for_gn_target(
867                out_path,
868                gn_args,
869                self.ARG_DICT.get("target").get(test_suite).get("gn_targets_depend_on"),
870                log_file_name)
871
872    def get_build_cmd(self, *, test_suite, test_script_name, test_script_path,
873                      out_path, x64_out_path, gn_args: list, args_to_cmd: str, timeout,
874                      run_jit: bool = False, run_baseline_jit: bool = False, aot_mode: bool = False,
875                      run_pgo: bool = False, enable_litecg: bool = False, ignore_list: Optional[str] = None) -> str:
876        if run_jit:
877            cmd = self.get_jit_cmd(test_suite, test_script_name, test_script_path,
878                                   gn_args, out_path, x64_out_path, args_to_cmd, timeout)
879        elif run_baseline_jit:
880            cmd = self.get_baseline_jit_cmd(test_suite, test_script_name, test_script_path,
881                                            gn_args, out_path, x64_out_path, args_to_cmd, timeout)
882        elif aot_mode and test_suite == "test262":
883            cmd = self.get_test262_aot_cmd(gn_args, out_path, x64_out_path, run_pgo,
884                                           enable_litecg, args_to_cmd, timeout)
885        else:
886            cmd = self.get_cmd(test_suite, test_script_name, test_script_path,
887                               gn_args, out_path, x64_out_path, aot_mode, run_pgo,
888                               enable_litecg, args_to_cmd, timeout, ignore_list)
889        return cmd
890
891    def build_for_suite(self, *, test_suite, test_script_name, test_script_path,
892                        out_path, gn_args: list, log_file_name, args_to_cmd: str, timeout,
893                        run_jit: bool = False, run_baseline_jit: bool = False, aot_mode: bool = False,
894                        run_pgo: bool = False, enable_litecg: bool = False, ignore_list: Optional[str] = None,
895                        skip_compiler: bool = False):
896        x64_out_path = self.__get_x64_out_path(out_path)
897        if not skip_compiler:
898            self.call_build_gn_target(gn_args, out_path, x64_out_path, test_suite, log_file_name)
899        cmd = self.get_build_cmd(
900            test_suite=test_suite,
901            test_script_name=test_script_name,
902            test_script_path=test_script_path,
903            out_path=out_path,
904            x64_out_path=x64_out_path,
905            gn_args=gn_args,
906            args_to_cmd=args_to_cmd,
907            timeout=timeout,
908            run_jit=run_jit,
909            run_baseline_jit=run_baseline_jit,
910            aot_mode=aot_mode, run_pgo=run_pgo, enable_litecg=enable_litecg, ignore_list=ignore_list)
911        log_path = str(os.path.join(out_path, log_file_name))
912        str_to_log = "================================\n{2}_time: {0}\n{2}_target: {1}\n\n".format(
913            str_of_time_now(), args_to_cmd, test_suite)
914        _write(log_path, str_to_log, "a")
915        print(f"=== {test_suite} start ===")
916        code = call_with_output(cmd, log_path)
917        if code != 0:
918            print(f"=== {test_suite} fail! ===\n")
919            sys.exit(code)
920        print(f"=== {test_suite} success! ===\n")
921
922    def build_for_test262(self, out_path, gn_args: list, arg_list: list):
923        timeout, arg_list = self.parse_timeout(arg_list)
924        arg_list = arg_list[1:]
925
926        is_aot_mode, arg_list = self.__purge_arg_list("--aot", arg_list)
927        is_pgo, arg_list = self.__purge_arg_list("--pgo", arg_list)
928        is_litecg, arg_list = self.__purge_arg_list("--litecg", arg_list)
929        is_jit, arg_list = self.__purge_arg_list("--jit", arg_list)
930        is_baseline_jit, arg_list = self.__purge_arg_list("--baseline-jit", arg_list)
931        is_skip_compiler, arg_list = self.__purge_arg_list("--skip-compiler", arg_list)
932        print(f"Test262: arg_list = {arg_list}")
933
934        args_to_test262_cmd = self.build_args_to_test262_cmd(arg_list)
935        self.build_for_suite(
936            test_suite="test262",
937            test_script_name="test262/run_test262.py",
938            test_script_path="arkcompiler/ets_frontend",
939            out_path=out_path,
940            gn_args=gn_args,
941            log_file_name=self.TEST262_LOG_FILE_NAME,
942            args_to_cmd=args_to_test262_cmd,
943            timeout=timeout,
944            run_jit=is_jit,
945            run_pgo=is_pgo,
946            run_baseline_jit=is_baseline_jit,
947            aot_mode=is_aot_mode,
948            enable_litecg=is_litecg,
949            skip_compiler=is_skip_compiler
950        )
951
952    def build_for_unittest(self, out_path: str, gn_args: list, log_file_name: str):
953        self.build_for_gn_target(
954            out_path, gn_args, self.ARG_DICT.get("target").get("unittest").get("gn_targets_depend_on"),
955            log_file_name)
956        return
957
958    def build_for_runtime_core_unittest(self, out_path: str, gn_args: list, log_file_name: str):
959        runtime_core_ut_depend = self.ARG_DICT.get("target").get("runtime_core_unittest").get("gn_targets_depend_on")
960        self.build_for_gn_target(out_path, gn_args, runtime_core_ut_depend, log_file_name)
961        return
962
963    def build_for_regress_test(self, out_path, gn_args: list, arg_list: list):
964        timeout, arg_list = self.parse_option(arg_list, option_name="--timeout", default_value=200)
965        ignore_list, arg_list = self.parse_option(arg_list, option_name="--ignore-list", default_value=None)
966
967        arg_list = arg_list[1:]
968
969        is_aot, arg_list = self.__purge_arg_list("--aot", arg_list)
970        is_pgo, arg_list = self.__purge_arg_list("--pgo", arg_list)
971        is_litecg, arg_list = self.__purge_arg_list("--litecg", arg_list)
972        is_jit, arg_list = self.__purge_arg_list("--jit", arg_list)
973        is_baseline_jit, arg_list = self.__purge_arg_list("--baseline-jit", arg_list)
974        is_skip_compiler, arg_list = self.__purge_arg_list("--skip-compiler", arg_list)
975        print(f"Regress: arg_list = {arg_list}")
976
977        args_to_regress_test_cmd = self.build_args_to_regress_cmd(arg_list)
978        self.build_for_suite(
979            test_suite="regresstest",
980            test_script_name="test/regresstest/run_regress_test.py",
981            test_script_path="arkcompiler/ets_runtime",
982            out_path=out_path,
983            gn_args=gn_args,
984            log_file_name=self.REGRESS_TEST_LOG_FILE_NAME,
985            args_to_cmd=args_to_regress_test_cmd,
986            timeout=timeout,
987            run_jit=is_jit,
988            run_pgo=is_pgo,
989            run_baseline_jit=is_baseline_jit,
990            aot_mode=is_aot,
991            enable_litecg=is_litecg,
992            ignore_list=ignore_list,
993            skip_compiler=is_skip_compiler
994        )
995
996    def build(self, out_path: str, gn_args: list, arg_list: list):
997        if not os.path.exists(out_path):
998            print("# mkdir -p {}".format(out_path))
999            os.makedirs(out_path)
1000        if len(arg_list) == 0:
1001            self.build_for_gn_target(out_path, gn_args, ["default"], self.GN_TARGET_LOG_FILE_NAME)
1002        elif self.is_dict_flags_match_arg(self.ARG_DICT.get("target").get("workload"), arg_list[0]):
1003            self.build_for_workload(arg_list, out_path, gn_args, 'workload.log')
1004        elif self.is_dict_flags_match_arg(self.ARG_DICT.get("target").get("test262"), arg_list[0]):
1005            self.build_for_test262(out_path, gn_args, arg_list)
1006        elif self.is_dict_flags_match_arg(self.ARG_DICT.get("target").get("unittest"), arg_list[0]):
1007            if len(arg_list) > 1:
1008                print("\033[92m\"unittest\" not support additional arguments.\033[0m\n".format())
1009                sys.exit(0)
1010            self.build_for_unittest(out_path, gn_args, self.UNITTEST_LOG_FILE_NAME)
1011        elif self.is_dict_flags_match_arg(self.ARG_DICT.get("target").get("runtime_core_unittest"), arg_list[0]):
1012            if len(arg_list) > 1:
1013                print("\033[92m\"runtime_core_unittest\" not support additional arguments.\033[0m\n".format())
1014                sys.exit(0)
1015            self.build_for_runtime_core_unittest(out_path, gn_args, self.RUNTIME_CORE_UNITTEST_LOG_FILE_NAME)
1016        elif self.is_dict_flags_match_arg(self.ARG_DICT.get("target").get("regresstest"), arg_list[0]):
1017            self.build_for_regress_test(out_path, gn_args, arg_list)
1018        else:
1019            self.build_for_gn_target(out_path, gn_args, arg_list, self.GN_TARGET_LOG_FILE_NAME)
1020        return
1021
1022    def parse_timeout(self, arg_list) -> Tuple[Optional[Union[str, int]], List[str]]:
1023        return self.parse_option(arg_list, option_name="--timeout", default_value=400000)
1024
1025    def match_options(self, arg_list: list, out_path: str) -> [list, list]:
1026        arg_list_ret = []
1027        gn_args_ret = []
1028        for arg in arg_list:
1029            # match [option][clean] flag
1030            if self.is_dict_flags_match_arg(self.ARG_DICT.get("option").get("clean"), arg):
1031                self.clean(out_path)
1032                sys.exit(0)
1033            # match [option][clean-continue] flag
1034            elif self.is_dict_flags_match_arg(self.ARG_DICT.get("option").get("clean-continue"), arg):
1035                if not self.has_cleaned:
1036                    self.clean(out_path)
1037                    self.has_cleaned = True
1038            # match [option][gn-args] flag
1039            elif self.is_dict_flags_match_arg(self.ARG_DICT.get("option").get("gn-args"), arg):
1040                gn_args_ret.append(arg[(arg.find("=") + 1):])
1041            # match [option][keepdepfile] flag
1042            elif self.is_dict_flags_match_arg(self.ARG_DICT.get("option").get("keepdepfile"), arg):
1043                if not self.enable_keepdepfile:
1044                    self.enable_keepdepfile = True
1045            # match [option][verbose] flag
1046            elif self.is_dict_flags_match_arg(self.ARG_DICT.get("option").get("verbose"), arg):
1047                if not self.enable_verbose:
1048                    self.enable_verbose = True
1049            # match [option][keep-going] flag
1050            elif self.is_dict_flags_match_arg(self.ARG_DICT.get("option").get("keep-going"), arg):
1051                if self.ignore_errors == 1:
1052                    input_value = arg[(arg.find("=") + 1):]
1053                    try:
1054                        self.ignore_errors = int(input_value)
1055                    except Exception as _:
1056                        print("\033[92mIllegal value \"{}\" for \"--keep-going\" argument.\033[0m\n".format(
1057                            input_value
1058                        ))
1059                        sys.exit(0)
1060            # make a new list with flag that do not match any flag in [option]
1061            else:
1062                arg_list_ret.append(arg)
1063        return [arg_list_ret, gn_args_ret]
1064
1065    def build_for_workload(self, arg_list, out_path, gn_args, log_file_name):
1066        root_dir = os.path.dirname(os.path.abspath(__file__))
1067        report = False
1068        tools = 'dev'
1069        boundary_value = '-10'
1070        run_count = '10'
1071        code_v = ''
1072        run_interpreter = False
1073        if len(arg_list) >= 2 and arg_list[1] == 'report':
1074            report = True
1075        if len(arg_list) >= 3 and arg_list[2]:
1076            tools = arg_list[2]
1077        if len(arg_list) >= 4 and arg_list[3]:
1078            boundary_value = arg_list[3]
1079        if len(arg_list) >= 5 and arg_list[4]:
1080            run_count = arg_list[4]
1081        if len(arg_list) >= 6 and arg_list[5]:
1082            code_v = arg_list[5]
1083        if len(arg_list) >= 7 and arg_list[6] == '--run-interpreter':
1084            run_interpreter = True
1085        self.build_for_gn_target(out_path, gn_args, ["default"], self.GN_TARGET_LOG_FILE_NAME)
1086        workload_cmd = "cd arkcompiler/ets_runtime/test/workloadtest/ && python3 work_load.py" \
1087                       " --code-path {0}" \
1088                       " --report {1}" \
1089                       " --tools-type {2}" \
1090                       " --boundary-value {3}" \
1091                       " --run-count {4}" \
1092                       " --code-v {5}" \
1093            .format(root_dir, report, tools, boundary_value, run_count, code_v)
1094        if run_interpreter:
1095            workload_cmd += " --run-interpreter true"
1096        workload_log_path = os.path.join(out_path, log_file_name)
1097        str_to_workload_log = "================================\nwokload_time: {0}\nwokload_target: {1}\n\n".format(
1098            str_of_time_now(), 'file')
1099        _write(workload_log_path, str_to_workload_log, "a")
1100        print("=== workload start ===")
1101        code = call_with_output(workload_cmd, workload_log_path)
1102        if code != 0:
1103            print("=== workload fail! ===\n")
1104            sys.exit(code)
1105        print("=== workload success! ===\n")
1106        return
1107
1108    def start_for_matched_os_cpu_mode(self, os_cpu_key: str, mode_key: str, arg_list: list):
1109        # get binary gn and ninja
1110        self.get_binaries()
1111        # get out_path
1112        name_of_out_dir_of_second_level = \
1113            self.ARG_DICT.get("os_cpu").get(os_cpu_key).get("prefix_of_name_of_out_dir_of_second_level") + \
1114            self.DELIMITER_FOR_SECOND_OUT_DIR_NAME + \
1115            self.ARG_DICT.get("mode").get(mode_key).get("suffix_of_name_of_out_dir_of_second_level")
1116        out_path = os.path.join(self.NAME_OF_OUT_DIR_OF_FIRST_LEVEL, name_of_out_dir_of_second_level)
1117        # match [option] flag
1118        [arg_list, gn_args] = self.match_options(arg_list, out_path)
1119        # get expression which would be written to args.gn file
1120        gn_args.extend(self.ARG_DICT.get("os_cpu").get(os_cpu_key).get("gn_args"))
1121        gn_args.extend(self.ARG_DICT.get("mode").get(mode_key).get("gn_args"))
1122        # start to build
1123        self.build(out_path, gn_args, arg_list)
1124        return
1125
1126    def __purge_arg_list(self, option_name: str, arg_list: List[Any]) -> Tuple[bool, List[Any]]:
1127        if option_name in arg_list:
1128            arg_list.remove(option_name)
1129            return True, arg_list
1130        return False, arg_list
1131
1132
1133if __name__ == "__main__":
1134    ark_py = ArkPy()
1135    ark_py.__main__(sys.argv[1:])
1136