|  | #!/usr/bin/env python | 
|  | # | 
|  | # Copyright 2019 the V8 project authors. All rights reserved. | 
|  | # Use of this source code is governed by a BSD-style license that can be | 
|  | # found in the LICENSE file. | 
|  | """\ | 
|  | Helper script for compiling and running the Wasm C/C++ API examples. | 
|  |  | 
|  | Usage: tools/run-wasm-api-tests.py outdir tempdir [filters...] | 
|  |  | 
|  | "outdir" is the build output directory containing libwee8, e.g. out/x64.release | 
|  | "tempdir" is a temporary dir where this script may put its artifacts. It is | 
|  | the caller's responsibility to clean it up afterwards. | 
|  |  | 
|  | By default, this script builds and runs all examples, both the respective | 
|  | C and C++ versions, both with GCC ("gcc" and "g++" binaries found in $PATH) | 
|  | and V8's bundled Clang in third_party/llvm-build/. You can use any number | 
|  | of "filters" arguments to run only a subset: | 
|  | - "c": run C versions of examples | 
|  | - "cc": run C++ versions of examples | 
|  | - "gcc": compile with GCC | 
|  | - "clang": compile with Clang | 
|  | - "hello" etc.: run "hello" example | 
|  | """ | 
|  |  | 
|  | from __future__ import print_function | 
|  |  | 
|  | import os | 
|  | import shutil | 
|  | import subprocess | 
|  | import sys | 
|  |  | 
|  | CFLAGS = "-DDEBUG -Wall -Werror -O0 -ggdb -fsanitize=address" | 
|  |  | 
|  | CHECKOUT_PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) | 
|  | WASM_PATH = os.path.join(CHECKOUT_PATH, "third_party", "wasm-api") | 
|  | CLANG_PATH = os.path.join(CHECKOUT_PATH, "third_party", "llvm-build", | 
|  | "Release+Asserts", "bin") | 
|  |  | 
|  | EXAMPLES = ["hello", "callback", "trap", "reflect", "global", "table", | 
|  | "memory", "finalize", "serialize", "threads"] | 
|  |  | 
|  | CLANG = { | 
|  | "name": "Clang", | 
|  | "c": os.path.join(CLANG_PATH, "clang"), | 
|  | "cc": os.path.join(CLANG_PATH, "clang++"), | 
|  | "ldflags": "-fsanitize-memory-track-origins -fsanitize-memory-use-after-dtor", | 
|  | } | 
|  | GCC = { | 
|  | "name": "GCC", | 
|  | "c": "gcc", | 
|  | "cc": "g++", | 
|  | "ldflags": "", | 
|  | } | 
|  |  | 
|  | C = { | 
|  | "name": "C", | 
|  | "suffix": "c", | 
|  | "cflags": "", | 
|  | } | 
|  | CXX = { | 
|  | "name": "C++", | 
|  | "suffix": "cc", | 
|  | "cflags": "-std=c++11", | 
|  | } | 
|  |  | 
|  | MIN_ARGS = 3  # Script, outdir, tempdir | 
|  |  | 
|  | def _Call(cmd_list, silent=False): | 
|  | cmd = " ".join(cmd_list) | 
|  | if not silent: print("# %s" % cmd) | 
|  | return subprocess.call(cmd, shell=True) | 
|  |  | 
|  | class Runner(object): | 
|  | def __init__(self, name, outdir, tempdir): | 
|  | self.name = name | 
|  | self.outdir = outdir | 
|  | self.tempdir = tempdir | 
|  | self.src_file_basename = os.path.join(WASM_PATH, "example", name) | 
|  | self.dst_file_basename = os.path.join(tempdir, name) | 
|  | self.lib_file = os.path.join(outdir, "obj", "libwee8.a") | 
|  | if not os.path.exists(self.lib_file): | 
|  | print("libwee8 library not found, make sure to pass the outdir as " | 
|  | "first argument; see --help") | 
|  | sys.exit(1) | 
|  | src_wasm_file = self.src_file_basename + ".wasm" | 
|  | dst_wasm_file = self.dst_file_basename + ".wasm" | 
|  | shutil.copyfile(src_wasm_file, dst_wasm_file) | 
|  |  | 
|  | def _Error(self, step, lang, compiler, code): | 
|  | print("Error: %s failed. To repro: tools/run-wasm-api-tests.py " | 
|  | "%s %s %s %s %s" % | 
|  | (step, self.outdir, self.tempdir, self.name, lang, | 
|  | compiler["name"].lower())) | 
|  | return code | 
|  |  | 
|  | def CompileAndRun(self, compiler, language): | 
|  | print("==== %s %s/%s ====" % | 
|  | (self.name, language["name"], compiler["name"])) | 
|  | lang = language["suffix"] | 
|  | src_file = self.src_file_basename + "." + lang | 
|  | exe_file = self.dst_file_basename + "-" + lang | 
|  | obj_file = exe_file  + ".o" | 
|  | # Compile. | 
|  | c = _Call([compiler[lang], "-c", language["cflags"], CFLAGS, | 
|  | "-I", WASM_PATH, "-o", obj_file, src_file]) | 
|  | if c: return self._Error("compilation", lang, compiler, c) | 
|  | # Link. | 
|  | c = _Call([compiler["cc"], CFLAGS, compiler["ldflags"], obj_file, | 
|  | "-o", exe_file, self.lib_file, "-ldl -pthread"]) | 
|  | if c: return self._Error("linking", lang, compiler, c) | 
|  | # Execute. | 
|  | exe_file = "./%s-%s" % (self.name, lang) | 
|  | c = _Call(["cd", self.tempdir, ";", exe_file]) | 
|  | if c: return self._Error("execution", lang, compiler, c) | 
|  | return 0 | 
|  |  | 
|  | def Main(args): | 
|  | if (len(args) < MIN_ARGS or args[1] in ("-h", "--help", "help")): | 
|  | print(__doc__) | 
|  | return 1 | 
|  |  | 
|  | outdir = sys.argv[1] | 
|  | tempdir = sys.argv[2] | 
|  | result = 0 | 
|  | examples = EXAMPLES | 
|  | compilers = (GCC, CLANG) | 
|  | languages = (C, CXX) | 
|  | if len(args) > MIN_ARGS: | 
|  | custom_compilers = [] | 
|  | custom_languages = [] | 
|  | custom_examples = [] | 
|  | for i in range(MIN_ARGS, len(args)): | 
|  | arg = args[i] | 
|  | if arg == "c" and C not in custom_languages: | 
|  | custom_languages.append(C) | 
|  | elif arg in ("cc", "cpp", "cxx", "c++") and CXX not in custom_languages: | 
|  | custom_languages.append(CXX) | 
|  | elif arg in ("gcc", "g++") and GCC not in custom_compilers: | 
|  | custom_compilers.append(GCC) | 
|  | elif arg in ("clang", "clang++") and CLANG not in custom_compilers: | 
|  | custom_compilers.append(CLANG) | 
|  | elif arg in EXAMPLES and arg not in custom_examples: | 
|  | custom_examples.append(arg) | 
|  | else: | 
|  | print("Didn't understand '%s'" % arg) | 
|  | return 1 | 
|  | if custom_compilers: | 
|  | compilers = custom_compilers | 
|  | if custom_languages: | 
|  | languages = custom_languages | 
|  | if custom_examples: | 
|  | examples = custom_examples | 
|  | for example in examples: | 
|  | runner = Runner(example, outdir, tempdir) | 
|  | for compiler in compilers: | 
|  | for language in languages: | 
|  | c = runner.CompileAndRun(compiler, language) | 
|  | if c: result = c | 
|  | if result: | 
|  | print("\nFinished with errors.") | 
|  | else: | 
|  | print("\nFinished successfully.") | 
|  | return result | 
|  |  | 
|  | if __name__ == "__main__": | 
|  | sys.exit(Main(sys.argv)) |