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