# Copyright (C) 2018 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import("../wasm_vars.gni")

# Used by //gn/standalone/toolchain/BUILD.gn .
em_config = rebase_path(".emscripten", "")
if (is_mac_host) {
  emsdk_dir = rebase_path("//buildtools/mac/emsdk", "")
} else {
  emsdk_dir = rebase_path("//buildtools/linux64/emsdk", "")
}

# Defines a WASM library target.
# Args:
#  generate_js: when true generates a .wasm file and a .js file that wraps it
#      and provides the boilerplate to initialize the module.
#  generate_html: when true generates also an example .html file which contains
#      a minimal console to interact with the module (useful for testing).
template("wasm_lib") {
  assert(defined(invoker.name))

  # If the name is foo the target_name must be foo_wasm.
  assert(invoker.name + "_wasm" == target_name)
  _lib_name = invoker.name
  _is_memory64 = defined(invoker.is_memory64) && invoker.is_memory64
  if (is_wasm) {
    _exports = "['ccall', 'callMain', 'addFunction', 'FS', 'HEAPU8']"
    _target_ldflags = [
      "-s",
      "WASM=1",
      "-s",
      "ENVIRONMENT=web,worker",
      "-s",
      "DISABLE_EXCEPTION_CATCHING=1",
      "-s",
      "NO_DYNAMIC_EXECUTION=1",
      "-s",
      "INITIAL_MEMORY=33554432",
      "-s",
      "ALLOW_MEMORY_GROWTH=1",
      "-s",
      "ALLOW_TABLE_GROWTH=1",
      "-s",
      "STACK_SIZE=2MB",
      "-s",
      "WASM_ASYNC_COMPILATION=0",
      "-s",
      "EXPORTED_RUNTIME_METHODS=" + _exports,

      # This forces the MEMFS filesystem library to always use typed arrays
      # instead of building strings/arrays when appending to a file. This allows
      # to deal with pseudo-files larger than 128 MB when calling traceconv.
      "-s",
      "MEMFS_APPEND_TO_TYPED_ARRAYS=1",

      # Reduces global namespace pollution.
      "-s",
      "MODULARIZE=1",

      # This is to prevent that two different wasm modules end up generating
      # JS that overrides the same global variable (var Module = ...)
      "-s",
      "EXPORT_NAME=${target_name}",

      "-lworkerfs.js",  # For FS.filesystems.WORKERFS
    ]
    if (is_debug) {
      _target_ldflags += [
        "-s",
        "ASSERTIONS=2",
        "-s",
        "SAFE_HEAP=1",
        "-s",
        "STACK_OVERFLOW_CHECK=1",
        "-g4",
        "-O0",
      ]
    } else {
      _target_ldflags += [
        "-s",
        "ASSERTIONS=1",
        "-g2",  # Required for getting C++ symbol names.
        "-O3",
      ]
    }

    if (defined(invoker.js_library)) {
      _target_ldflags += [
        "--js-library",
        invoker.js_library,
      ]
    }

    _vars_to_forward = [
      "cflags",
      "defines",
      "deps",
      "includes",
      "sources",
      "include_dirs",
      "public_configs",
      "testonly",
      "visibility",
    ]

    executable("${_lib_name}.js") {
      forward_variables_from(invoker, _vars_to_forward)
      if (_is_memory64) {
        ldflags = _target_ldflags + [
                    "-s",
                    "MEMORY64=1",
                    "-s",
                    "MAXIMUM_MEMORY=16GB",
                    "-mwasm64",
                  ]
      } else {
        ldflags = _target_ldflags + [
                    "-s",
                    "MAXIMUM_MEMORY=4GB",
                  ]
      }
      output_extension = ""
    }

    # This is just a workaround to deal with the fact that GN doesn't allow
    # spcifying extra outputs for an executable() target. In reality the .wasm
    # file here is generated by the executable() target above, together with the
    # .js file. This dummy target is here to tell GN "there is a target that
    # outputs also the .wasm file", so we can depend on that in copy() targets.
    action("${_lib_name}.wasm") {
      inputs = []
      deps = [ ":${_lib_name}.js" ]
      outputs = [ "$root_out_dir/$_lib_name.wasm" ]
      if (is_debug) {
        outputs += [ "$root_out_dir/$_lib_name.wasm.map" ]
      }
      args = [ "--noop" ]
      script = "//gn/standalone/build_tool_wrapper.py"
    }
    copy("${_lib_name}.d.ts") {
      sources = [ "//gn/standalone/wasm_typescript_declaration.d.ts" ]
      outputs = [ "$root_out_dir/$_lib_name.d.ts" ]
    }
  } else {  # is_wasm
    not_needed(invoker, "*")
  }

  group(target_name) {
    if (_is_memory64) {
      _wasm_32_or_64_toolchain = wasm_memory64_toolchain
    } else {
      _wasm_32_or_64_toolchain = wasm_toolchain
    }
    deps = [
      ":${_lib_name}.d.ts($_wasm_32_or_64_toolchain)",
      ":${_lib_name}.js($_wasm_32_or_64_toolchain)",
      ":${_lib_name}.wasm($_wasm_32_or_64_toolchain)",
    ]
  }
}  # template
