1#!/usr/bin/env python 2# 3# Copyright 2019 the V8 project authors. All rights reserved. 4# Use of this source code is governed by a BSD-style license that can be 5# found in the LICENSE file. 6"""\ 7Helper script for compiling and running the Wasm C/C++ API examples. 8 9Usage: tools/run-wasm-api-tests.py outdir tempdir [filters...] 10 11"outdir" is the build output directory containing libwee8, e.g. out/x64.release 12"tempdir" is a temporary dir where this script may put its artifacts. It is 13the caller's responsibility to clean it up afterwards. 14 15By default, this script builds and runs all examples, both the respective 16C and C++ versions, both with GCC ("gcc" and "g++" binaries found in $PATH) 17and V8's bundled Clang in third_party/llvm-build/. You can use any number 18of "filters" arguments to run only a subset: 19 - "c": run C versions of examples 20 - "cc": run C++ versions of examples 21 - "gcc": compile with GCC 22 - "clang": compile with Clang 23 - "hello" etc.: run "hello" example 24""" 25 26from __future__ import print_function 27 28import os 29import shutil 30import subprocess 31import sys 32 33CFLAGS = "-DDEBUG -Wall -Werror -O0 -ggdb -fsanitize=address" 34 35CHECKOUT_PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 36WASM_PATH = os.path.join(CHECKOUT_PATH, "third_party", "wasm-api") 37CLANG_PATH = os.path.join(CHECKOUT_PATH, "third_party", "llvm-build", 38 "Release+Asserts", "bin") 39 40EXAMPLES = ["hello", "callback", "trap", "reflect", "global", "table", 41 "memory", "finalize", "serialize", "threads", "hostref", "multi", 42 "start"] 43 44CLANG = { 45 "name": "Clang", 46 "c": os.path.join(CLANG_PATH, "clang"), 47 "cc": os.path.join(CLANG_PATH, "clang++"), 48 "ldflags": "-fsanitize-memory-track-origins -fsanitize-memory-use-after-dtor", 49} 50GCC = { 51 "name": "GCC", 52 "c": "gcc", 53 "cc": "g++", 54 "ldflags": "", 55} 56 57C = { 58 "name": "C", 59 "suffix": "c", 60 "cflags": "", 61} 62CXX = { 63 "name": "C++", 64 "suffix": "cc", 65 "cflags": "-std=c++11", 66} 67 68MIN_ARGS = 3 # Script, outdir, tempdir 69 70def _Call(cmd_list, silent=False): 71 cmd = " ".join(cmd_list) 72 if not silent: print("# %s" % cmd) 73 return subprocess.call(cmd, shell=True) 74 75class Runner(object): 76 def __init__(self, name, outdir, tempdir): 77 self.name = name 78 self.outdir = outdir 79 self.tempdir = tempdir 80 self.src_file_basename = os.path.join(WASM_PATH, "example", name) 81 self.dst_file_basename = os.path.join(tempdir, name) 82 self.lib_file = os.path.join(outdir, "obj", "libwee8.a") 83 if not os.path.exists(self.lib_file): 84 print("libwee8 library not found, make sure to pass the outdir as " 85 "first argument; see --help") 86 sys.exit(1) 87 src_wasm_file = self.src_file_basename + ".wasm" 88 dst_wasm_file = self.dst_file_basename + ".wasm" 89 shutil.copyfile(src_wasm_file, dst_wasm_file) 90 91 def _Error(self, step, lang, compiler, code): 92 print("Error: %s failed. To repro: tools/run-wasm-api-tests.py " 93 "%s %s %s %s %s" % 94 (step, self.outdir, self.tempdir, self.name, lang, 95 compiler["name"].lower())) 96 return code 97 98 def CompileAndRun(self, compiler, language): 99 print("==== %s %s/%s ====" % 100 (self.name, language["name"], compiler["name"])) 101 lang = language["suffix"] 102 src_file = self.src_file_basename + "." + lang 103 exe_file = self.dst_file_basename + "-" + lang 104 obj_file = exe_file + ".o" 105 # Compile. 106 c = _Call([compiler[lang], "-c", language["cflags"], CFLAGS, 107 "-I", WASM_PATH, "-o", obj_file, src_file]) 108 if c: return self._Error("compilation", lang, compiler, c) 109 # Link. 110 c = _Call([compiler["cc"], CFLAGS, compiler["ldflags"], obj_file, 111 "-o", exe_file, self.lib_file, "-ldl -pthread"]) 112 if c: return self._Error("linking", lang, compiler, c) 113 # Execute. 114 exe_file = "./%s-%s" % (self.name, lang) 115 c = _Call(["cd", self.tempdir, ";", exe_file]) 116 if c: return self._Error("execution", lang, compiler, c) 117 return 0 118 119def Main(args): 120 if (len(args) < MIN_ARGS or args[1] in ("-h", "--help", "help")): 121 print(__doc__) 122 return 1 123 124 outdir = sys.argv[1] 125 tempdir = sys.argv[2] 126 result = 0 127 examples = EXAMPLES 128 compilers = (GCC, CLANG) 129 languages = (C, CXX) 130 if len(args) > MIN_ARGS: 131 custom_compilers = [] 132 custom_languages = [] 133 custom_examples = [] 134 for i in range(MIN_ARGS, len(args)): 135 arg = args[i] 136 if arg == "c" and C not in custom_languages: 137 custom_languages.append(C) 138 elif arg in ("cc", "cpp", "cxx", "c++") and CXX not in custom_languages: 139 custom_languages.append(CXX) 140 elif arg in ("gcc", "g++") and GCC not in custom_compilers: 141 custom_compilers.append(GCC) 142 elif arg in ("clang", "clang++") and CLANG not in custom_compilers: 143 custom_compilers.append(CLANG) 144 elif arg in EXAMPLES and arg not in custom_examples: 145 custom_examples.append(arg) 146 else: 147 print("Didn't understand '%s'" % arg) 148 return 1 149 if custom_compilers: 150 compilers = custom_compilers 151 if custom_languages: 152 languages = custom_languages 153 if custom_examples: 154 examples = custom_examples 155 for example in examples: 156 runner = Runner(example, outdir, tempdir) 157 for compiler in compilers: 158 for language in languages: 159 c = runner.CompileAndRun(compiler, language) 160 if c: result = c 161 if result: 162 print("\nFinished with errors.") 163 else: 164 print("\nFinished successfully.") 165 return result 166 167if __name__ == "__main__": 168 sys.exit(Main(sys.argv)) 169