• 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, 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["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 get_test262_cmd(gn_args, out_path, x64_out_path, run_pgo, enable_litecg, args_to_test262_cmd,
313                        timeout):
314
315        print("running test262 in AsmMode\n")
316        if any('target_cpu="arm64"' in arg for arg in gn_args):
317            test262_cmd = "cd arkcompiler/ets_frontend && python3 test262/run_test262.py {0} --timeout {3}" \
318                            " --libs-dir ../../{1}/arkcompiler/ets_runtime:../../{1}/thirdparty/icu:" \
319                            "../../{1}/thirdparty/zlib:../../prebuilts/clang/ohos/linux-x86_64/llvm/lib" \
320                            " --ark-arch aarch64" \
321                            " --ark-arch-root=../../{1}/common/common/libc/" \
322                            " --ark-tool=../../{1}/arkcompiler/ets_runtime/ark_js_vm" \
323                            " --ark-frontend-binary=../../{2}/arkcompiler/ets_frontend/es2abc" \
324                            " --merge-abc-binary=../../{2}/arkcompiler/ets_frontend/merge_abc" \
325                            " --ark-frontend=es2panda".format(args_to_test262_cmd, out_path, x64_out_path)
326        else:
327            test262_cmd = "cd arkcompiler/ets_frontend && python3 test262/run_test262.py {0} --timeout {2}" \
328                    " --libs-dir ../../prebuilts/clang/ohos/linux-x86_64/llvm/lib" \
329                    " --ark-tool=../../{1}/arkcompiler/ets_runtime/ark_js_vm" \
330                    " --ark-frontend-binary=../../{1}/arkcompiler/ets_frontend/es2abc" \
331                    " --merge-abc-binary=../../{1}/arkcompiler/ets_frontend/merge_abc" \
332                    " --ark-frontend=es2panda".format(args_to_test262_cmd, out_path, timeout)
333        return test262_cmd
334
335    @staticmethod
336    def get_test262_aot_cmd(gn_args, out_path, x64_out_path, run_pgo, enable_litecg, args_to_test262_cmd,
337                        timeout):
338        print("running test262 in AotMode\n")
339        if any('target_cpu="arm64"' in arg for arg in gn_args):
340            if run_pgo:
341                test262_cmd = "cd arkcompiler/ets_frontend && python3 test262/run_test262.py {0} --timeout {4}" \
342                        " --libs-dir ../../{1}/arkcompiler/ets_runtime:../../{1}/thirdparty/icu:" \
343                        "../../{1}/thirdparty/zlib:../../prebuilts/clang/ohos/linux-x86_64/llvm/lib" \
344                        " --ark-arch aarch64" \
345                        " --ark-arch-root=../../{1}/common/common/libc/" \
346                        " --ark-tool=../../{1}/arkcompiler/ets_runtime/ark_js_vm" \
347                        " --ark-aot-tool=../../{1}/arkcompiler/ets_runtime/ark_aot_compiler" \
348                        " --ark-frontend-binary=../../{2}/arkcompiler/ets_frontend/es2abc" \
349                        " --merge-abc-binary=../../{2}/arkcompiler/ets_frontend/merge_abc" \
350                        " --ark-aot" \
351                        " --ark-frontend=es2panda"\
352                        "{3}".format(args_to_test262_cmd, out_path, x64_out_path, " --run-pgo", timeout)
353            else:
354                test262_cmd = "cd arkcompiler/ets_frontend && python3 test262/run_test262.py {0} --timeout {3}" \
355                        " --libs-dir ../../prebuilts/clang/ohos/linux-x86_64/llvm/lib:../../{2}/thirdparty/icu/" \
356                        " --ark-arch aarch64" \
357                        " --ark-arch-root=../../{1}/common/common/libc/" \
358                        " --ark-aot" \
359                        " --ark-aot-tool=../../{2}/arkcompiler/ets_runtime/ark_aot_compiler" \
360                        " --ark-tool=../../{1}/arkcompiler/ets_runtime/ark_js_vm" \
361                        " --ark-frontend-binary=../../{2}/arkcompiler/ets_frontend/es2abc" \
362                        " --merge-abc-binary=../../{2}/arkcompiler/ets_frontend/merge_abc" \
363                        " --ark-frontend=es2panda".format(args_to_test262_cmd, out_path, x64_out_path, timeout)
364        else:
365            test262_cmd = "cd arkcompiler/ets_frontend && python3 test262/run_test262.py {0} --timeout {3}" \
366                        " --libs-dir ../../{1}/arkcompiler/ets_runtime:../../{1}/thirdparty/icu" \
367                        ":../../{1}/thirdparty/zlib:../../prebuilts/clang/ohos/linux-x86_64/llvm/lib" \
368                        " --ark-tool=../../{1}/arkcompiler/ets_runtime/ark_js_vm" \
369                        " --ark-aot-tool=../../{1}/arkcompiler/ets_runtime/ark_aot_compiler" \
370                        " --ark-frontend-binary=../../{1}/arkcompiler/ets_frontend/es2abc" \
371                        " --merge-abc-binary=../../{1}/arkcompiler/ets_frontend/merge_abc" \
372                        " --ark-aot" \
373                        " --ark-frontend=es2panda"\
374                        "{2}".format(args_to_test262_cmd, out_path, " --run-pgo" if run_pgo else "", timeout)
375        if enable_litecg:
376            test262_cmd = test262_cmd + " --enable-litecg"
377        return test262_cmd
378
379    @staticmethod
380    def get_test262_jit_cmd(gn_args, out_path, x64_out_path, args_to_test262_cmd, timeout):
381        print("running test262 in JIT mode\n")
382        if any('target_cpu="arm64"' in arg for arg in gn_args):
383            test262_cmd = "cd arkcompiler/ets_frontend && python3 test262/run_test262.py {0} --timeout {3}" \
384                " --libs-dir ../../prebuilts/clang/ohos/linux-x86_64/llvm/lib:../../{1}/thirdparty/icu/" \
385                ":../../{1}/thirdparty/bounds_checking_function" \
386                ":../../{1}/arkcompiler/ets_runtime:" \
387                " --ark-arch aarch64" \
388                " --run-jit" \
389                " --ark-arch-root=../../{1}/common/common/libc/" \
390                " --ark-aot-tool=../../{2}/arkcompiler/ets_runtime/ark_aot_compiler" \
391                " --ark-tool=../../{1}/arkcompiler/ets_runtime/ark_js_vm" \
392                " --ark-frontend-binary=../../{2}/arkcompiler/ets_frontend/es2abc" \
393                " --merge-abc-binary=../../{2}/arkcompiler/ets_frontend/merge_abc" \
394                " --ark-frontend=es2panda".format(args_to_test262_cmd, out_path, x64_out_path, timeout)
395        else:
396            test262_cmd = "cd arkcompiler/ets_frontend && python3 test262/run_test262.py {0} --timeout {3}" \
397                " --libs-dir ../../{1}/arkcompiler/ets_runtime:../../{1}/thirdparty/icu" \
398                ":../../{1}/thirdparty/zlib:../../prebuilts/clang/ohos/linux-x86_64/llvm/lib" \
399                " --run-jit" \
400                " --ark-tool=../../{1}/arkcompiler/ets_runtime/ark_js_vm" \
401                " --ark-frontend-binary=../../{1}/arkcompiler/ets_frontend/es2abc" \
402                " --merge-abc-binary=../../{1}/arkcompiler/ets_frontend/merge_abc" \
403                " --ark-frontend=es2panda"\
404                "{2}".format(args_to_test262_cmd, out_path, x64_out_path, timeout)
405        return test262_cmd
406
407    @staticmethod
408    def get_test262_baseline_jit_cmd(gn_args, out_path, x64_out_path, args_to_test262_cmd, timeout):
409        print("running test262 in baseline JIT mode\n")
410        if any('target_cpu="arm64"' in arg for arg in gn_args):
411            test262_cmd = "cd arkcompiler/ets_frontend && python3 test262/run_test262.py {0} --timeout {3}" \
412                " --libs-dir ../../prebuilts/clang/ohos/linux-x86_64/llvm/lib" \
413                ":../../{1}/thirdparty/icu" \
414                ":../../prebuilts/clang/ohos/linux-x86_64/llvm/lib/aarch64-linux-ohos" \
415                ":../../{1}/thirdparty/bounds_checking_function" \
416                ":../../{1}/arkcompiler/ets_runtime" \
417                ":../../{1}/common/common/libc/lib" \
418                " --ark-arch aarch64" \
419                " --run-baseline-jit" \
420                " --ark-arch-root=../../{1}/common/common/libc/" \
421                " --ark-aot-tool=../../{2}/arkcompiler/ets_runtime/ark_aot_compiler" \
422                " --ark-tool=../../{1}/arkcompiler/ets_runtime/ark_js_vm" \
423                " --ark-frontend-binary=../../{2}/arkcompiler/ets_frontend/es2abc" \
424                " --merge-abc-binary=../../{2}/arkcompiler/ets_frontend/merge_abc" \
425                " --ark-frontend=es2panda".format(args_to_test262_cmd, out_path, x64_out_path, timeout)
426        else:
427            test262_cmd = "cd arkcompiler/ets_frontend && python3 test262/run_test262.py {0} --timeout {3}" \
428                " --libs-dir ../../{1}/lib.unstripped/arkcompiler/ets_runtime" \
429                ":../../{1}/lib.unstripped/thirdparty/icu" \
430                ":../../prebuilts/clang/ohos/linux-x86_64/llvm/lib" \
431                ":../../{1}/lib.unstripped/thirdparty/bounds_checking_function/" \
432                " --run-baseline-jit" \
433                " --ark-tool=../../{1}/arkcompiler/ets_runtime/ark_js_vm" \
434                " --ark-frontend-binary=../../{1}/arkcompiler/ets_frontend/es2abc" \
435                " --merge-abc-binary=../../{1}/arkcompiler/ets_frontend/merge_abc" \
436                " --ark-frontend=es2panda"\
437                "{2}".format(args_to_test262_cmd, out_path, x64_out_path, timeout)
438        return test262_cmd
439
440    @staticmethod
441    def build_args_to_test262_cmd(arg_list):
442        args_to_test262_cmd = []
443
444        disable_force_gc = [arg for arg in arg_list if "disable-force-gc" in arg]
445        if disable_force_gc:
446            args_to_test262_cmd.append("--disable-force-gc")
447            arg_list.remove(disable_force_gc[0])
448
449        threads_name = "--threads"
450        threads_value, arg_list = ArkPy.parse_option(arg_list, option_name=threads_name, default_value=None)
451        if threads_value:
452            args_to_test262_cmd.extend([threads_name, threads_value])
453
454        if len(arg_list) == 0:
455            args_to_test262_cmd.append("--es2021 all")
456        elif len(arg_list) == 1:
457            arg = arg_list[0]
458            if ".js" in arg:
459                args_to_test262_cmd.append("--file test262/data/test_es2021/{}".format(arg))
460            else:
461                args_to_test262_cmd.append("--dir test262/data/test_es2021/{}".format(arg))
462        else:
463            print("\033[92m\"test262\" not support multiple additional arguments.\033[0m\n".format())
464            sys.exit(0)
465
466        return " ".join(args_to_test262_cmd)
467
468    @staticmethod
469    def build_args_to_regress_cmd(arg_list):
470        args_to_regress_cmd = []
471
472        processes_name = "--processes"
473        processes_value, arg_list = ArkPy.parse_option(arg_list, option_name=processes_name, default_value=1)
474        args_to_regress_cmd.extend([processes_name, processes_value])
475
476        test_list_name = "--test-list"
477        test_list_value, arg_list = ArkPy.parse_option(arg_list, option_name=test_list_name, default_value=None)
478        if test_list_value is not None:
479            args_to_regress_cmd.extend([test_list_name, test_list_value])
480
481        if len(arg_list) == 1:
482            arg = arg_list[0]
483            if ".js" in arg:
484                args_to_regress_cmd.append(f"--test-file {arg}")
485            else:
486                args_to_regress_cmd.append(f"--test-dir {arg}")
487        elif len(arg_list) > 1:
488            print("\033[92m\"regresstest\" not support multiple additional arguments.\033[0m\n".format())
489            sys.exit(0)
490
491        return " ".join([str(arg) for arg in args_to_regress_cmd])
492
493    @staticmethod
494    def parse_option(arg_list: List[str], option_name: str, default_value: Optional[Union[str, int]]) \
495            -> Tuple[Optional[Union[str, int]], List[str]]:
496        option_value, arg_list = ArkPy.__parse_option_with_space(arg_list, option_name)
497        if option_value is None:
498            option_value, arg_list = ArkPy.__parse_option_with_equal(arg_list, option_name)
499        if option_value is None and default_value is not None:
500            option_value = default_value
501        return option_value, arg_list
502
503    @staticmethod
504    def __is_option_value_int(value: Optional[Union[str, int]]) -> Tuple[bool, Optional[int]]:
505        if isinstance(value, int):
506            return True, int(value)
507        else:
508            return False, None
509
510    @staticmethod
511    def __is_option_value_str(value: Optional[Union[str, int]]) -> Tuple[bool, Optional[str]]:
512        if isinstance(value, str):
513            return True, str(value)
514        else:
515            return False, None
516
517    @staticmethod
518    def __get_option_value(option_name: str, value: Optional[Union[str, int]]) -> Union[str, int]:
519        result, res_value = ArkPy.__is_option_value_int(value)
520        if result:
521            return res_value
522        result, res_value = ArkPy.__is_option_value_str(value)
523        if result:
524            return res_value
525        print(f"Invalid '{option_name}' value.")
526        sys.exit(1)
527
528    @staticmethod
529    def __parse_option_with_space(arg_list: List[str], option_name: str) \
530            -> Tuple[Optional[Union[str, int]], List[str]]:
531        if option_name in arg_list:
532            option_index = arg_list.index(option_name)
533            if len(arg_list) > option_index + 1:
534                option_value = ArkPy.__get_option_value(option_name, arg_list[option_index + 1])
535                arg_list = arg_list[:option_index] + arg_list[option_index + 2:]
536            else:
537                print(f"Missing {option_name} value.")
538                sys.exit(1)
539
540            return option_value, arg_list
541        return None, arg_list
542
543    @staticmethod
544    def __parse_option_with_equal(arg_list: List[str], option_name: str) \
545            -> Tuple[Optional[Union[str, int]], List[str]]:
546        for index, arg in enumerate(arg_list):
547            local_option_name = f"{option_name}="
548            if arg.startswith(local_option_name):
549                option_value = arg[len(local_option_name):]
550                if option_value:
551                    option_value = ArkPy.__get_option_value(option_name, option_value)
552                    arg_list = arg_list[:index] + arg_list[index + 1:]
553                    return option_value, arg_list
554                else:
555                    print(f"Missing {option_name} value.")
556                    sys.exit(1)
557        return None, arg_list
558
559    def get_binaries(self):
560        host_os = sys.platform
561        host_cpu = platform.machine()
562        try:
563            with open(self.PREBUILTS_DOWNLOAD_CONFIG_FILE_PATH) as file_prebuilts_download_config:
564                prebuilts_download_config_dict = json.load(file_prebuilts_download_config)
565                file_prebuilts_download_config.close()
566            for element in prebuilts_download_config_dict[host_os][host_cpu]["copy_config"]:
567                if element["unzip_filename"] == "gn":
568                    self.gn_binary_path = os.path.join(element["unzip_dir"], element["unzip_filename"])
569                elif element["unzip_filename"] == "ninja":
570                    self.ninja_binary_path = os.path.join(element["unzip_dir"], element["unzip_filename"])
571        except Exception as error:
572            print("\nLogic of getting gn binary or ninja binary does not match logic of prebuilts_download." \
573                  "\nCheck func \033[92m{0} of class {1} in file {2}\033[0m against file {3} if the name of this " \
574                  "file had not changed!\n".format(
575                    sys._getframe().f_code.co_name, self.__class__.__name__, CURRENT_FILENAME,
576                    self.PREBUILTS_DOWNLOAD_CONFIG_FILE_PATH))
577            raise error
578        if self.gn_binary_path == "" or self.ninja_binary_path == "":
579            print("\nLogic of prebuilts_download may be wrong." \
580                  "\nCheck \033[92mdata in file {0}\033[0m against func {1} of class {2} in file {3}!\n".format(
581                    self.PREBUILTS_DOWNLOAD_CONFIG_FILE_PATH, sys._getframe().f_code.co_name, self.__class__.__name__,
582                    CURRENT_FILENAME))
583            sys.exit(0)
584        if not os.path.isfile(self.gn_binary_path) or not os.path.isfile(self.ninja_binary_path):
585            print("\nStep for prebuilts_download may be ommited. (\033[92m./prebuilts_download.sh\033[0m)" \
586            "\nCheck \033[92mwhether gn binary and ninja binary are under directory prebuilts\033[0m!\n".format())
587            sys.exit(0)
588        return
589
590    def which_dict_flags_match_arg(self, dict_including_dicts_to_match: dict, arg_to_match: str) -> str:
591        for key in dict_including_dicts_to_match.keys():
592            if self.is_dict_flags_match_arg(dict_including_dicts_to_match[key], arg_to_match):
593                return key
594        return ""
595
596    def dict_in_os_cpu_mode_match_arg(self, arg: str) -> [bool, str, str]:
597        os_cpu_part = ""
598        mode_part = ""
599        match_success = True
600        key_to_dict_in_os_cpu_matched_arg = ""
601        key_to_dict_in_mode_matched_arg = ""
602        arg_to_list = arg.split(self.DELIMITER_BETWEEN_OS_CPU_MODE_FOR_COMMAND)
603        if len(arg_to_list) == 1:
604            os_cpu_part = arg_to_list[0]
605            mode_part = "release"
606            key_to_dict_in_os_cpu_matched_arg = self.which_dict_flags_match_arg(self.ARG_DICT["os_cpu"], os_cpu_part)
607            key_to_dict_in_mode_matched_arg = self.which_dict_flags_match_arg(self.ARG_DICT["mode"], mode_part)
608        elif len(arg_to_list) == 2:
609            os_cpu_part = arg_to_list[0]
610            mode_part = arg_to_list[1]
611            key_to_dict_in_os_cpu_matched_arg = self.which_dict_flags_match_arg(self.ARG_DICT["os_cpu"], os_cpu_part)
612            key_to_dict_in_mode_matched_arg = self.which_dict_flags_match_arg(self.ARG_DICT["mode"], mode_part)
613        else:
614            print("\"\033[92m{0}\033[0m\" combined with more than 2 flags is not supported.".format(arg))
615        if (key_to_dict_in_os_cpu_matched_arg == "") | (key_to_dict_in_mode_matched_arg == ""):
616            match_success = False
617        return [match_success, key_to_dict_in_os_cpu_matched_arg, key_to_dict_in_mode_matched_arg]
618
619    def get_help_msg_of_dict(self, dict_in: dict, indentation_str_current: str, indentation_str_per_level: str) -> str:
620        help_msg = "".format()
621        for key in dict_in.keys():
622            if isinstance(dict_in[key], dict):
623                help_msg += "{0}{1}:\n".format(indentation_str_current, key)
624                help_msg += self.get_help_msg_of_dict(
625                    dict_in[key], indentation_str_current + indentation_str_per_level, indentation_str_per_level)
626            elif key == "flags":
627                help_msg += "{0}{1}: \033[92m{2}\033[0m\n".format(indentation_str_current, key, " ".join(dict_in[key]))
628            elif key == "description":
629                help_msg += "{0}{1}: {2}\n".format(indentation_str_current, key, dict_in[key])
630        return help_msg
631
632    def get_help_msg_of_all(self) -> str:
633        help_msg = "".format()
634        # Command template
635        help_msg += "\033[32mCommand template:\033[0m\n{}\n\n".format(
636            "  python3 ark.py \033[92m[os_cpu].[mode] [gn_target] [option]\033[0m\n"
637            "  python3 ark.py \033[92m[os_cpu].[mode] [test262] [none or --aot] " \
638              "[none or --pgo] [none or --litecg] [none, file or dir] [none or --threads=X] [option]\033[0m\n"
639            "  python3 ark.py \033[92m[os_cpu].[mode] [test262] [none or --jit] [none or --threads=X]\033[0m\n"
640            "  python3 ark.py \033[92m[os_cpu].[mode] [test262] [none or --baseline-jit] [none or --threads=X]\033[0m\n"
641            "  python3 ark.py \033[92m[os_cpu].[mode] [unittest] [option]\033[0m\n"
642            "  python3 ark.py \033[92m[os_cpu].[mode] [regresstest] [none, file or dir] " \
643              "[none or --processes X and/or --test-list TEST_LIST_NAME]\033[0m\n")
644        # Command examples
645        help_msg += "\033[32mCommand examples:\033[0m\n{}\n\n".format(
646            "  python3 ark.py \033[92mx64.release\033[0m\n"
647            "  python3 ark.py \033[92mx64.release ets_runtime\033[0m\n"
648            "  python3 ark.py \033[92mx64.release ark_js_vm es2panda\033[0m\n"
649            "  python3 ark.py \033[92mx64.release ark_js_vm es2panda --clean\033[0m\n"
650            "  python3 ark.py \033[92mx64.release test262\033[0m\n"
651            "  python3 ark.py \033[92mx64.release test262 --threads=16\033[0m\n"
652            "  python3 ark.py \033[92mx64.release test262 --aot --pgo --litecg\033[0m\n"
653            "  python3 ark.py \033[92mx64.release test262 --aot --pgo --litecg --threads=8\033[0m\n"
654            "  python3 ark.py \033[92mx64.release test262 --jit\033[0m\n"
655            "  python3 ark.py \033[92mx64.release test262 --baseline-jit\033[0m\n"
656            "  python3 ark.py \033[92mx64.release test262 built-ins/Array\033[0m\n"
657            "  python3 ark.py \033[92mx64.release test262 built-ins/Array/name.js\033[0m\n"
658            "  python3 ark.py \033[92mx64.release unittest\033[0m\n"
659            "  python3 ark.py \033[92mx64.release regresstest\033[0m\n"
660            "  python3 ark.py \033[92mx64.release regresstest --processes=4\033[0m\n"
661            "  python3 ark.py \033[92mx64.release workload\033[0m\n"
662            "  python3 ark.py \033[92mx64.release workload report\033[0m\n"
663            "  python3 ark.py \033[92mx64.release workload report dev\033[0m\n"
664            "  python3 ark.py \033[92mx64.release workload report dev -20\033[0m\n"
665            "  python3 ark.py \033[92mx64.release workload report dev -20 10\033[0m\n"
666            "  python3 ark.py \033[92mx64.release workload report dev -20 10 weekly_workload\033[0m\n")
667        # Arguments
668        help_msg += "\033[32mArguments:\033[0m\n{}".format(
669            self.get_help_msg_of_dict(
670                self.ARG_DICT, self.INDENTATION_STRING_PER_LEVEL, self.INDENTATION_STRING_PER_LEVEL))
671        return help_msg
672
673    def clean(self, out_path: str):
674        if not os.path.exists(out_path):
675            print("Path \"{}\" does not exist! No need to clean it.".format(out_path))
676        else:
677            print("=== clean start ===")
678            code = _call("{0} clean {1}".format(self.gn_binary_path, out_path))
679            if code != 0:
680                print("=== clean failed! ===\n")
681                sys.exit(code)
682            print("=== clean success! ===\n")
683        return
684
685    def build_for_gn_target(self, out_path: str, gn_args: list, arg_list: list, log_file_name: str):
686        # prepare log file
687        build_log_path = os.path.join(out_path, log_file_name)
688        backup(build_log_path, "w")
689        str_to_build_log = "================================\nbuild_time: {0}\nbuild_target: {1}\n\n".format(
690            str_of_time_now(), " ".join(arg_list))
691        _write(build_log_path, str_to_build_log, "a")
692        # gn command
693        print("=== gn gen start ===")
694        code = call_with_output(
695            "{0} gen {1} --args=\"{2}\"".format(
696                self.gn_binary_path, out_path, " ".join(gn_args).replace("\"", "\\\"")),
697            build_log_path)
698        if code != 0:
699            print("=== gn gen failed! ===\n")
700            sys.exit(code)
701        else:
702            print("=== gn gen success! ===\n")
703        # ninja command
704        # Always add " -d keeprsp" to ninja command to keep response file("*.rsp"), thus we could get shared libraries
705        # of an excutable from its response file.
706        ninja_cmd = \
707        self.ninja_binary_path + \
708        (" -v" if self.enable_verbose else "") + \
709        (" -d keepdepfile" if self.enable_keepdepfile else "") + \
710        " -d keeprsp" + \
711        " -C {}".format(out_path) + \
712        " {}".format(" ".join(arg_list)) + \
713        " -k {}".format(self.ignore_errors)
714        print(ninja_cmd)
715        code = call_with_output(ninja_cmd, build_log_path)
716        if code != 0:
717            print("=== ninja failed! ===\n")
718            sys.exit(code)
719        else:
720            print("=== ninja success! ===\n")
721        return
722
723    def build_for_test262(self, out_path, timeout, gn_args: list, arg_list: list, log_file_name: str,
724                          aot_mode: bool, run_pgo=False, enable_litecg=False, run_jit=False,
725                          run_baseline_jit=False):
726        args_to_test262_cmd = self.build_args_to_test262_cmd(arg_list)
727        x64_out_path = ""
728        if any('target_cpu="arm64"' in arg for arg in gn_args):
729            if 'release' in out_path:
730                x64_out_path = 'out/x64.release'
731            if 'debug' in out_path:
732                x64_out_path = 'out/x64.debug'
733            gn_args.append("so_dir_for_qemu=\"../../{0}/common/common/libc/\"".format(out_path))
734            gn_args.append("run_with_qemu=true".format(out_path))
735            if not os.path.exists(x64_out_path):
736                os.makedirs(x64_out_path)
737            self.build_for_gn_target(
738                x64_out_path, ['target_os="linux"', 'target_cpu="x64"', 'is_debug=false'],
739                self.ARG_DICT["target"]["test262"]["gn_targets_depend_on"], log_file_name)
740            self.build_for_gn_target(
741                out_path, gn_args, self.ARG_DICT["target"]["test262"]["arm64_gn_targets_depend_on"], log_file_name)
742        else:
743            self.build_for_gn_target(
744                out_path, gn_args, self.ARG_DICT["target"]["test262"]["gn_targets_depend_on"], log_file_name)
745        if run_jit:
746            test262_cmd = self.get_test262_jit_cmd(gn_args, out_path, x64_out_path, args_to_test262_cmd, timeout)
747        elif run_baseline_jit:
748            test262_cmd = self.get_test262_baseline_jit_cmd(gn_args, out_path, x64_out_path,
749                                                            args_to_test262_cmd, timeout)
750        elif aot_mode:
751            test262_cmd = self.get_test262_aot_cmd(gn_args, out_path, x64_out_path, run_pgo, enable_litecg, args_to_test262_cmd,
752                        timeout)
753        else:
754            test262_cmd = self.get_test262_cmd(gn_args, out_path, x64_out_path, run_pgo,
755                                            enable_litecg, args_to_test262_cmd, timeout)
756        test262_log_path = os.path.join(out_path, log_file_name)
757        str_to_test262_log = "================================\ntest262_time: {0}\ntest262_target: {1}\n\n".format(
758            str_of_time_now(), args_to_test262_cmd)
759        _write(test262_log_path, str_to_test262_log, "a")
760        print("=== test262 start ===")
761        code = call_with_output(test262_cmd, test262_log_path)
762        if code != 0:
763            print("=== test262 fail! ===\n")
764            sys.exit(code)
765        print("=== test262 success! ===\n")
766
767    def build_for_unittest(self, out_path: str, gn_args: list, log_file_name:str):
768        self.build_for_gn_target(
769            out_path, gn_args, self.ARG_DICT["target"]["unittest"]["gn_targets_depend_on"],
770            log_file_name)
771        return
772
773    def build_for_regress_test(self, out_path, gn_args: list, arg_list: list, log_file_name: str, timeout):
774        args_to_regress_test_cmd = self.build_args_to_regress_cmd(arg_list)
775        self.build_for_gn_target(
776            out_path, gn_args, self.ARG_DICT["target"]["regresstest"]["gn_targets_depend_on"], log_file_name)
777        regress_test_cmd = "python3 arkcompiler/ets_runtime/test/regresstest/run_regress_test.py --timeout {2}" \
778                      " --ark-tool ./{0}/arkcompiler/ets_runtime/ark_js_vm" \
779                      " --ark-frontend-binary ./{0}/arkcompiler/ets_frontend/es2abc" \
780                      " --LD_LIBRARY_PATH ./{0}/arkcompiler/ets_runtime:./{0}/thirdparty/icu:" \
781                      "./prebuilts/clang/ohos/linux-x86_64/llvm/lib" \
782                      " --out-dir ./{0}/ {1}".format(out_path, args_to_regress_test_cmd, timeout)
783        regress_test_log_path = os.path.join(out_path, log_file_name)
784        str_to_test_log = "============\n regresstest_time: {0}\nregresstest_target: {1}\n\n".format(
785            str_of_time_now(), regress_test_cmd)
786        _write(regress_test_log_path, str_to_test_log, "a")
787        print("=== regresstest start ===")
788        code = call_with_output(regress_test_cmd, regress_test_log_path)
789        if code != 0:
790            print("=== regresstest fail! ===\n")
791            sys.exit(code)
792        print("=== regresstest success! ===\n")
793        return
794
795    def build(self, out_path: str, gn_args: list, arg_list: list):
796        if not os.path.exists(out_path):
797            print("# mkdir -p {}".format(out_path))
798            os.makedirs(out_path)
799        if len(arg_list) == 0:
800            self.build_for_gn_target(out_path, gn_args, ["default"], self.GN_TARGET_LOG_FILE_NAME)
801        elif self.is_dict_flags_match_arg(self.ARG_DICT["target"]["workload"], arg_list[0]):
802            self.build_for_workload(arg_list, out_path, gn_args, 'workload.log')
803        elif self.is_dict_flags_match_arg(self.ARG_DICT["target"]["test262"], arg_list[0]):
804            timeout, arg_list = self.parse_timeout(arg_list)
805            run_aot_mode = len(arg_list) >= 2 and arg_list[1] == "--aot"
806            run_aot_pgo_litecg = len(arg_list) >= 4 and ((arg_list[2] == "--pgo" and arg_list[3] == "--litecg") or
807                                                         (arg_list[3] == "--pgo" and arg_list[2] == "--litecg"))
808            run_aot_pgo = len(arg_list) >= 3 and arg_list[2] == "--pgo"
809            run_aot_litecg = len(arg_list) >= 3 and arg_list[2] == "--litecg"
810            run_jit = len(arg_list) >= 2 and arg_list[1] == "--jit"
811            run_baseline_jit = len(arg_list) >= 2 and arg_list[1] == "--baseline-jit"
812            if run_aot_mode:
813                if run_aot_pgo_litecg:
814                    self.build_for_test262(out_path, timeout, gn_args, arg_list[4:], self.TEST262_LOG_FILE_NAME, True,
815                                           True, True)
816                elif run_aot_litecg:
817                    self.build_for_test262(out_path, timeout, gn_args, arg_list[3:], self.TEST262_LOG_FILE_NAME, True,
818                                           False, True)
819                elif run_aot_pgo:
820                    self.build_for_test262(out_path, timeout, gn_args, arg_list[3:],
821                                           self.TEST262_LOG_FILE_NAME, True, True)
822                else:
823                    self.build_for_test262(out_path, timeout, gn_args, arg_list[2:], self.TEST262_LOG_FILE_NAME, True)
824            elif run_jit:
825                self.build_for_test262(out_path, timeout, gn_args, arg_list[2:],
826                                       self.TEST262_LOG_FILE_NAME, False, False,
827                                       False, True)
828            elif run_baseline_jit:
829                self.build_for_test262(out_path, timeout, gn_args, arg_list[2:],
830                                       self.TEST262_LOG_FILE_NAME, False, False,
831                                       False, False, True)
832            else:
833                self.build_for_test262(out_path, timeout, gn_args, arg_list[1:], self.TEST262_LOG_FILE_NAME, False)
834        elif self.is_dict_flags_match_arg(self.ARG_DICT["target"]["unittest"], arg_list[0]):
835            if len(arg_list) > 1:
836                print("\033[92m\"unittest\" not support additional arguments.\033[0m\n".format())
837                sys.exit(0)
838            self.build_for_unittest(out_path, gn_args, self.UNITTEST_LOG_FILE_NAME)
839        elif self.is_dict_flags_match_arg(self.ARG_DICT["target"]["regresstest"], arg_list[0]):
840            timeout, arg_list = self.parse_option(arg_list, option_name="--timeout", default_value=200)
841            self.build_for_regress_test(out_path, gn_args, arg_list[1:], self.REGRESS_TEST_LOG_FILE_NAME, timeout)
842        else:
843            self.build_for_gn_target(out_path, gn_args, arg_list, self.GN_TARGET_LOG_FILE_NAME)
844        return
845
846    def parse_timeout(self, arg_list) -> Tuple[Optional[Union[str, int]], List[str]]:
847        return self.parse_option(arg_list, option_name="--timeout", default_value=400000)
848
849    def match_options(self, arg_list: list, out_path: str) -> [list, list]:
850        arg_list_ret = []
851        gn_args_ret = []
852        for arg in arg_list:
853            # match [option][clean] flag
854            if self.is_dict_flags_match_arg(self.ARG_DICT["option"]["clean"], arg):
855                self.clean(out_path)
856                sys.exit(0)
857            # match [option][clean-continue] flag
858            elif self.is_dict_flags_match_arg(self.ARG_DICT["option"]["clean-continue"], arg):
859                if not self.has_cleaned:
860                    self.clean(out_path)
861                    self.has_cleaned = True
862            # match [option][gn-args] flag
863            elif self.is_dict_flags_match_arg(self.ARG_DICT["option"]["gn-args"], arg):
864                gn_args_ret.append(arg[(arg.find("=") + 1):])
865            # match [option][keepdepfile] flag
866            elif self.is_dict_flags_match_arg(self.ARG_DICT["option"]["keepdepfile"], arg):
867                if not self.enable_keepdepfile:
868                    self.enable_keepdepfile = True
869            # match [option][verbose] flag
870            elif self.is_dict_flags_match_arg(self.ARG_DICT["option"]["verbose"], arg):
871                if not self.enable_verbose:
872                    self.enable_verbose = True
873            # match [option][keep-going] flag
874            elif self.is_dict_flags_match_arg(self.ARG_DICT["option"]["keep-going"], arg):
875                if self.ignore_errors == 1:
876                    input_value = arg[(arg.find("=") + 1):]
877                    try:
878                        self.ignore_errors = int(input_value)
879                    except Exception as _:
880                        print("\033[92mIllegal value \"{}\" for \"--keep-going\" argument.\033[0m\n".format(
881                            input_value
882                        ))
883                        sys.exit(0)
884            # make a new list with flag that do not match any flag in [option]
885            else:
886                arg_list_ret.append(arg)
887        return [arg_list_ret, gn_args_ret]
888
889    def build_for_workload(self, arg_list, out_path, gn_args, log_file_name):
890        root_dir = os.path.dirname(os.path.abspath(__file__))
891        report = False
892        tools = 'dev'
893        boundary_value = '-10'
894        run_count = '10'
895        code_v = ''
896        run_interpreter = False
897        if len(arg_list) >= 2 and arg_list[1] == 'report':
898            report = True
899        if len(arg_list) >= 3 and arg_list[2]:
900            tools = arg_list[2]
901        if len(arg_list) >= 4 and arg_list[3]:
902            boundary_value = arg_list[3]
903        if len(arg_list) >= 5 and arg_list[4]:
904            run_count = arg_list[4]
905        if len(arg_list) >= 6 and arg_list[5]:
906            code_v = arg_list[5]
907        if len(arg_list) >= 7 and arg_list[6] == '--run-interpreter':
908            run_interpreter = True
909        self.build_for_gn_target(out_path, gn_args, ["default"], self.GN_TARGET_LOG_FILE_NAME)
910        workload_cmd = "cd arkcompiler/ets_runtime/test/workloadtest/ && python3 work_load.py" \
911          " --code-path {0}" \
912          " --report {1}" \
913          " --tools-type {2}" \
914          " --boundary-value {3}" \
915          " --run-count {4}" \
916          " --code-v {5}" \
917          .format(root_dir, report, tools, boundary_value, run_count, code_v)
918        if run_interpreter:
919            workload_cmd += " --run-interpreter true"
920        workload_log_path = os.path.join(out_path, log_file_name)
921        str_to_workload_log = "================================\nwokload_time: {0}\nwokload_target: {1}\n\n".format(
922            str_of_time_now(), 'file')
923        _write(workload_log_path, str_to_workload_log, "a")
924        print("=== workload start ===")
925        code = call_with_output(workload_cmd, workload_log_path)
926        if code != 0:
927            print("=== workload fail! ===\n")
928            sys.exit(code)
929        print("=== workload success! ===\n")
930        return
931
932    def start_for_matched_os_cpu_mode(self, os_cpu_key: str, mode_key: str, arg_list: list):
933        # get binary gn and ninja
934        self.get_binaries()
935        # get out_path
936        name_of_out_dir_of_second_level = \
937            self.ARG_DICT["os_cpu"][os_cpu_key]["prefix_of_name_of_out_dir_of_second_level"] + \
938            self.DELIMITER_FOR_SECOND_OUT_DIR_NAME + \
939            self.ARG_DICT["mode"][mode_key]["suffix_of_name_of_out_dir_of_second_level"]
940        out_path = os.path.join(self.NAME_OF_OUT_DIR_OF_FIRST_LEVEL, name_of_out_dir_of_second_level)
941        # match [option] flag
942        [arg_list, gn_args] = self.match_options(arg_list, out_path)
943        # get expression which would be written to args.gn file
944        gn_args.extend(self.ARG_DICT["os_cpu"][os_cpu_key]["gn_args"])
945        gn_args.extend(self.ARG_DICT["mode"][mode_key]["gn_args"])
946        # start to build
947        self.build(out_path, gn_args, arg_list)
948        return
949
950
951
952if __name__ == "__main__":
953    ark_py = ArkPy()
954    ark_py.__main__(sys.argv[1:])
955