Add WebGl2 benchmarking example

This makes it so that we can specify a custom HTML shell file for the
emcc_binary rule.

Change-Id: I919e917d6fd92fed6ab77775c5373d2886edacca
diff --git a/tools/cpp/emscripten/defs.bzl b/tools/cpp/emscripten/defs.bzl
index 721e895..cd37472 100644
--- a/tools/cpp/emscripten/defs.bzl
+++ b/tools/cpp/emscripten/defs.bzl
@@ -1,51 +1,79 @@
 # Sourced from https://github.com/ribrdb/rules_emscripten/blob/master/toolchain/defs.bzl
 # TODO(james): Specialize this more for our purposes--e.g.,
 # we probably will only actually use one set of the possible options.
-def emcc_binary(name,
-                memory_init_file=0,
-                wasm=True,
-                worker=False,
-                linkopts=[],
-                **kwargs):
-    includejs = False
+def emcc_binary(name, srcs=[], linkopts=[], html_shell=None, **kwargs):
+    """Produces a deployable set of WebAssembly files.
+
+    Depending on the settings, the exact format of the output varies.
+    The output will be a a .js, .wasm, and optional .html file, all sharing the
+    same basename. The .js file is the script that should be included in any
+    webpage, and will handle calling the code compiled to the .wasm file.
+
+    The optional .html file uses some existing template html file and adds the
+    necessary <script> statement to import the .js script. This html file will
+    be generated if the name of the rule ends with ".html"; if the html_shell
+    argument is specified, then the provided html file is used to generate the
+    output html. The only change made to the template html is to replace any
+    instances of "{{{ SCRIPT }}}" with the appropriate <script> tags. This is
+    consistent with how the "--shell-file" flag works in emscripten. However, we
+    can't use the builtin flag with the script in its current form, because
+    that would require making an html file an input to a cc_library rule,
+    which bazel gets obnoxious about.
+    TODO(james): Rewrite this as a rule so that we can do some of this more
+    cleanly.
+
+    This macro also defines a rule with a name equal to the basename of
+    the name argument (e.g., if name = "foo.html", basename = "foo"). This rule
+    is a filegroup containing all the output files of this rule.
+
+    Internally, this rule works by:
+    1) Generating a tarball that contains the .js and .wasm files, using
+       a cc_binary that calls the emscripten compiler.
+    2) Extracting said tarball.
+    3) Generating the output html from the html shell template.
+    """
     includehtml = False
     linkopts = list(linkopts)
+    srcs = list(srcs)
     if name.endswith(".html"):
         basename = name[:-5]
         includehtml = True
-        includejs = True
     elif name.endswith(".js"):
         basename = name[:-3]
-        includejs = True
     outputs = []
-    if includejs:
-        outputs.append(basename + ".js")
-        if wasm:
-            outputs.append(basename + ".wasm")
-        if memory_init_file:
-            outputs.append(basename + ".mem")
-        if worker:
-            outputs.append(basename + ".worker.js")
-            linkopts.append('--proxy-to-worker')
+    outputs.append(basename + ".js")
+    outputs.append(basename + ".wasm")
 
-    if includehtml:
+    if includehtml and not html_shell:
         outputs.append(basename + ".html")
-    if not wasm:
-        linkopts.append('-s WASM=0')
-        linkopts.append('--memory-init-file %d' % memory_init_file)
-    if includejs:
-        tarfile = name + ".tar"
-        # we'll generate a tarfile and extract multiple outputs
-        native.cc_binary(name=tarfile, linkopts=linkopts, restricted_to = ["//tools:web"], **kwargs)
-        native.genrule(
-            name="emcc_extract_" + tarfile,
-            srcs=[tarfile],
-            outs=outputs,
-            output_to_bindir=1,
-            testonly=kwargs.get('testonly'),
-            restricted_to = ["//tools:web"],
-            cmd="""
-          tar xf $< -C "$(@D)"/$$(dirname "%s")
-        """ % [outputs[0]])
-    else:
-        native.cc_binary(name=name, linkopts=linkopts, restricted_to = ["//tools:web"], **kwargs)
+    tarfile = name + ".tar"
+    if html_shell:
+        tarfile = basename + ".js.tar"
+    native.cc_binary(
+        name=tarfile,
+        srcs=srcs,
+        linkopts=linkopts,
+        restricted_to = ["//tools:web"],
+        **kwargs)
+    native.genrule(
+        name="emcc_extract_" + tarfile,
+        srcs=[tarfile],
+        outs=outputs,
+        output_to_bindir=1,
+        testonly=kwargs.get('testonly'),
+        restricted_to = ["//tools:web"],
+        cmd="""tar xf $< -C "$(@D)"/$$(dirname "%s")""" % [outputs[0]])
+    if html_shell:
+         native.genrule(
+             name = "generate_shell_" + name,
+             srcs = [html_shell],
+             outs = [basename + ".html"],
+             restricted_to = ["//tools:web"],
+             cmd = "sed 's/{{{ SCRIPT }}}/<script async type=\"text\/javascript\" src=\"" + basename + ".js\"><\/script>/' $< > $@",
+         )
+         outputs.append(basename + ".html")
+    native.filegroup(
+        name = basename,
+        srcs = outputs,
+        restricted_to = ["//tools:web"]
+    )