# Copyright 2015 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import("//build/config/nacl/config.gni")
import("//build/config/nacl/rules.gni")
import("//components/nacl/features.gni")

assert(enable_nacl)

if (current_cpu == "pnacl") {
  if (is_nacl_nonsfi) {
    nacl_toolchain_variant = "nonsfi"
  } else {
    nacl_toolchain_variant = "pnacl"
  }
} else if (is_nacl_glibc) {
  nacl_toolchain_variant = "glibc"
} else {
  nacl_toolchain_variant = "newlib"
}

# Assemble data for Native Client based test
#
# Build a Native Client based test, including any additional support files
# and copy them over to a toolchain-specific target directory.
#
# Variables:
#   output_name: name of the ouput file other than the default
#   sources: source files for a target
#   generate_nmf: whether to generate a manifest (default true)
#   pretranslate_pexe: whether to pre-translate pexe to nexe during build
#     (default true for Non-SFI, otherwise false)
#   nonstable_pexe: use non-finalized pexe (default false)
#   debug_pexe: copy both non-finalized and finalized pexe (default false)
#   destination_dir: the output directory relative to the $root_build_dir,
#     if ommitted the output directory is $root_build_dir and the manifest
#     will be suffixed with the name of the toolchain (optional)
#   test_files: additional test files to copy to $destination_dir (optional)
#   nmfflags: additional flags for the nmf generator (optional)
template("nacl_test_data") {
  assert(defined(invoker.sources))
  forward_variables_from(invoker, [ "destination_dir" ])

  if (defined(invoker.output_name)) {
    output_name = invoker.output_name
  } else {
    output_name = target_name
  }

  if (current_cpu == "x64") {
    nmf_cpu = "x86_64"
  } else if (current_cpu == "x86") {
    nmf_cpu = "x86_32"
  } else {
    nmf_cpu = current_cpu
  }

  if (current_cpu == "pnacl") {
    if (defined(invoker.pretranslate_pexe)) {
      pretranslate_pexe = invoker.pretranslate_pexe
    } else {
      pretranslate_pexe = is_nacl_nonsfi
    }
  } else {
    pretranslate_pexe = false
  }

  # Note this can't test "is_win" because it's evaluated in the NaCl
  # toolchain context where is_win==false because current_os=="nacl".
  # It tests target_cpu rather than current_cpu because it's also
  # needed in the current_cpu=="pnacl" && pretranslate_pexe case.
  if (target_os == "win" && target_cpu == "x86" && !is_nacl_nonsfi &&
      (current_cpu == "x86" || pretranslate_pexe)) {
    # x86 Windows builds of Chrome run on both x86 Windows and x64
    # Windows.  On x64 Windows, only x64 NaCl is supported, so those
    # tests are needed too.
    extra_tc_cpu = "x64"
    if (current_cpu == "x86") {
      extra_nmf_cpu = "x86_64"
    }
  }

  if (is_nacl_glibc) {
    suffix = "glibc_${nmf_cpu}"
    if (defined(extra_nmf_cpu)) {
      extra_suffix = "glibc_${extra_nmf_cpu}"
      glibc_tc = "//build/toolchain/nacl:glibc"
      assert(current_toolchain == "${glibc_tc}_${current_cpu}")
      extra_toolchain = "${glibc_tc}_${extra_tc_cpu}"
    }
  } else {
    suffix = "newlib_${nmf_cpu}"
    if (defined(extra_nmf_cpu)) {
      extra_suffix = "newlib_${extra_nmf_cpu}"
      newlib_tc = "//build/toolchain/nacl:clang_newlib"
      assert(current_toolchain == "${newlib_tc}_${current_cpu}")
      extra_toolchain = "${newlib_tc}_${extra_tc_cpu}"
    }
  }
  suffixed_output_name = "${output_name}_${suffix}"
  if (defined(extra_nmf_cpu)) {
    extra_suffixed_output_name = "${output_name}_${extra_suffix}"
  }
  if (pretranslate_pexe) {
    pexe_translate_target_name = target_name + "_translate_pexe_"
    if (defined(extra_tc_cpu)) {
      # There will be an extra pretranslation done below for the
      # extra CPU (i.e. for x64 on x86 Windows).
      extra_pexe_translate_target_name =
          pexe_translate_target_name + extra_tc_cpu
    }
    pexe_translate_target_name += target_cpu
  }
  if (defined(invoker.generate_nmf)) {
    generate_nmf = invoker.generate_nmf
  } else {
    generate_nmf = true
  }
  nexe_target_name = target_name + "_nexe"
  nexe_copy_target_name = target_name + "_copy_nexe"
  if (current_cpu == "pnacl" && !is_nacl_nonsfi) {
    if (defined(invoker.debug_pexe) && invoker.debug_pexe) {
      pexe_copy_debug_target_name = target_name + "_copy_pexe_debug"
    }
  }
  if (generate_nmf) {
    nmf_target_name = target_name + "_nmf"
  }
  if (defined(invoker.test_files)) {
    test_files_target_name = target_name + "_test_files"
  }
  final_target_name = target_name

  # When the destination_dir is specified, the build artifacts end up
  # in the that directory and the manifest is the same as the target name.
  # When the destination_dir is not specified, the artifacts end up
  # in the root build directory and the manifests are suffixed to ensure
  # they do not overlap in case when we build the same test using multiple
  # different toolchains.
  if (defined(invoker.destination_dir)) {
    target_dir =
        "${root_build_dir}/${destination_dir}/${nacl_toolchain_variant}"
    if (generate_nmf) {
      nmf_name = output_name
    }
  } else {
    target_dir = root_build_dir
    if (generate_nmf) {
      if (is_nacl_nonsfi) {
        nacl_toolchain_name = "pnacl_${nacl_toolchain_variant}"
      } else {
        nacl_toolchain_name = nacl_toolchain_variant
      }
      nmf_name = "${output_name}_${nacl_toolchain_name}"
    }
  }

  executable(nexe_target_name) {
    visibility = [ ":*" ]
    output_name = suffixed_output_name
    sources = invoker.sources
    forward_variables_from(invoker,
                           [
                             "cflags",
                             "defines",
                             "include_dirs",
                             "ldflags",
                             "libs",
                           ])
    deps = [
      "//build/config/nacl:nacl_base",
      "//ppapi/native_client:ppapi_lib",
    ]
    ldflags = [ "-pthread" ]
    if (defined(invoker.deps)) {
      deps += invoker.deps
    }
  }

  if (current_cpu == "pnacl" && pretranslate_pexe) {
    # This is a template so it can be invoked twice in the
    # defined(extra_tc_cpu) case below.
    template("nacl_test_data_pretranslate_pexe") {
      action(target_name) {
        translate_cpu = invoker.translate_cpu

        visibility = [ ":$nexe_copy_target_name" ]

        # We specify the toolchain explicitly because in the Non-SFI case, we
        # still want to use the pexe built using the newlib_pnacl toolchain.
        tests = ":ppapi_nacl_tests_nexe(//build/toolchain/nacl:newlib_pnacl)"

        pexe = get_label_info(tests, "root_out_dir") +
               "/${suffixed_output_name}.pexe"
        if (translate_cpu == "x86" ||
            (is_nacl_nonsfi &&
             (translate_cpu == "x86" || translate_cpu == "x64"))) {
          nmf_cpu = "x32"
        } else {
          nmf_cpu = translate_cpu
        }
        if (is_nacl_nonsfi) {
          suffix = "pnacl_newlib_${nmf_cpu}_nonsfi"
        } else {
          suffix = "pnacl_newlib_${nmf_cpu}"
        }
        nexe = "${root_out_dir}/${output_name}_${suffix}.nexe"

        script = "${nacl_toolchain_bindir}/pydir/loader.py"
        sources = [
          pexe,
        ]
        outputs = [
          nexe,
        ]

        if (is_nacl_nonsfi) {
          if (translate_cpu == "x86" || translate_cpu == "x64") {
            arch = "x86-32-nonsfi"
          } else if (translate_cpu == "arm") {
            arch = "arm-nonsfi"
          }
        } else {
          # TODO(phosek): remove the following once change 1360243003 is rolled
          # into Chrome and use translate_cpu directly.
          if (translate_cpu == "x86") {
            arch = "i686"
          } else if (translate_cpu == "x64") {
            arch = "x86-64"
          } else if (translate_cpu == "arm") {
            arch = "armv7"
          } else if (translate_cpu == "mipsel") {
            arch = "mipsel"
          }
        }

        # The pre-translated object file has to be linked with an IRT shim to
        # get a runnable nexe. This is handled by pnacl-translate, which passes
        # -l:libpnacl_irt_shim.a to native linker, and we need to ensure the
        # linker can find the correct library.
        if (is_nacl_nonsfi) {
          pnacl_irt_shim = "//ppapi/native_client/src/untrusted/pnacl_irt_shim:aot(//build/toolchain/nacl:newlib_pnacl_nonsfi)"
        } else {
          pnacl_irt_shim = "//ppapi/native_client/src/untrusted/pnacl_irt_shim:aot(//build/toolchain/nacl:clang_newlib_${translate_cpu})"
        }

        args = [
          "pnacl-translate",
          rebase_path(pexe, root_build_dir),
          "-o",
          rebase_path(nexe, root_build_dir),
          "-arch",
          arch,
          "-Wl,-L" +
              rebase_path(get_label_info(pnacl_irt_shim, "target_out_dir"),
                          root_build_dir),
        ]
        deps = [
          ":$nexe_target_name(//build/toolchain/nacl:newlib_pnacl)",
        ]
        data_deps = [
          pnacl_irt_shim,
        ]
      }
    }

    nacl_test_data_pretranslate_pexe(pexe_translate_target_name) {
      translate_cpu = target_cpu
    }
    if (defined(extra_tc_cpu)) {
      nacl_test_data_pretranslate_pexe(extra_pexe_translate_target_name) {
        translate_cpu = extra_tc_cpu
      }
    }
  }

  copy(nexe_copy_target_name) {
    visibility = [ ":$final_target_name" ]
    if (generate_nmf) {
      visibility += [ ":$nmf_target_name" ]
    }
    if (current_cpu == "pnacl") {
      if (pretranslate_pexe) {
        sources = get_target_outputs(":${pexe_translate_target_name}")
        if (defined(extra_tc_cpu)) {
          sources += get_target_outputs(":${extra_pexe_translate_target_name}")
        }
      } else if (defined(invoker.nonstable_pexe) && invoker.nonstable_pexe) {
        sources = [
          "${root_out_dir}/exe.unstripped/${suffixed_output_name}.pexe",
        ]
      } else {
        sources = [
          "${root_out_dir}/${suffixed_output_name}.pexe",
        ]
      }
    } else {
      sources = [
        "${root_out_dir}/${suffixed_output_name}.nexe",
      ]
      if (defined(extra_nmf_cpu)) {
        extra_root_out_dir =
            get_label_info(":${nexe_target_name}(${extra_toolchain})",
                           "root_out_dir")
        sources +=
            [ "${extra_root_out_dir}/${extra_suffixed_output_name}.nexe" ]
      }
    }
    outputs = [
      "${target_dir}/{{source_file_part}}",
    ]
    if (current_cpu == "pnacl" && pretranslate_pexe) {
      deps = [
        ":$pexe_translate_target_name",
      ]
      if (defined(extra_tc_cpu)) {
        deps += [ ":$extra_pexe_translate_target_name" ]
      }
    } else {
      deps = [
        ":$nexe_target_name",
      ]
      if (defined(extra_nmf_cpu)) {
        deps += [ ":${nexe_target_name}(${extra_toolchain})" ]
      }
    }
  }

  if (current_cpu == "pnacl" && !is_nacl_nonsfi) {
    if (defined(invoker.debug_pexe) && invoker.debug_pexe) {
      copy(pexe_copy_debug_target_name) {
        visibility = [ ":$final_target_name" ]
        sources = [
          "${root_out_dir}/exe.unstripped/${suffixed_output_name}.pexe",
        ]
        outputs = [
          "${target_dir}/{{source_name_part}}.pexe.debug",
        ]
        deps = [
          ":$nexe_target_name",
        ]
      }
    }
  }

  if (generate_nmf) {
    if (is_nacl_nonsfi) {
      generate_nonsfi_test_nmf(nmf_target_name) {
        visibility = [ ":$final_target_name" ]
        forward_variables_from(invoker, [ "nmfflags" ])
        nmf = "${target_dir}/${nmf_name}.nmf"
        files = get_target_outputs(":$nexe_copy_target_name")
        executable = files[0]
        deps = [
          ":$nexe_copy_target_name",
        ]
      }
    } else {
      generate_nmf(nmf_target_name) {
        visibility = [ ":$final_target_name" ]
        forward_variables_from(invoker, [ "nmfflags" ])
        nmf = "${target_dir}/${nmf_name}.nmf"
        executables = get_target_outputs(":$nexe_copy_target_name")
        if (is_nacl_glibc) {
          lib_prefix = "${output_name}_libs"
          stage_dependencies = target_dir
        }
        deps = [
          ":$nexe_copy_target_name",
        ]
      }
    }
  }

  if (defined(invoker.test_files)) {
    copy(test_files_target_name) {
      visibility = [ ":$final_target_name" ]
      sources = invoker.test_files
      outputs = [
        "${target_dir}/{{source_file_part}}",
      ]
    }
  }

  group(final_target_name) {
    data_deps = [
      ":$nexe_copy_target_name",
    ]
    if (current_cpu == "pnacl" && !is_nacl_nonsfi) {
      if (defined(invoker.debug_pexe) && invoker.debug_pexe) {
        data_deps += [ ":$pexe_copy_debug_target_name" ]
      }
    }
    if (generate_nmf) {
      data_deps += [ ":$nmf_target_name" ]
    }
    if (defined(invoker.test_files)) {
      data_deps += [ ":$test_files_target_name" ]
    }
  }
}