# Copyright 2014 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.

# Instantiate grit. This will produce a script target to run grit, and a
# static library that compiles the .cc files.
#
# Parameters
#
#   source (required)
#       Path to .grd file.
#
#   outputs (required)
#       List of outputs from grit, relative to the target_gen_dir. Grit will
#       verify at build time that this list is correct and will fail if there
#       is a mismatch between the outputs specified by the .grd file and the
#       outputs list here.
#
#       To get this list, you can look in the .grd file for
#       <output filename="..." and put those filename here. The base directory
#       of the list in Grit and the output list specified in the GN grit target
#       are the same (the target_gen_dir) so you can generally copy the names
#       exactly.
#
#       To get the list of outputs programatically, run:
#           python tools/grit/grit_info.py --outputs . path/to/your.grd
#       And strip the leading "./" from the output files.
#
#   defines (optional)
#       Extra defines to pass to grit (on top of the global grit_defines list).
#
#   grit_flags (optional)
#       List of strings containing extra command-line flags to pass to Grit.
#
#   resource_ids (optional)
#       Path to a grit "firstidsfile". Default is
#       //tools/gritsettings/resource_ids. Set to "" to use the value specified
#       in the <grit> nodes of the processed files.
#
#   output_dir (optional)
#       Directory for generated files. If you specify this, you will often
#       want to specify output_name if the target name is not particularly
#       unique, since this can cause files from multiple grit targets to
#       overwrite each other.
#
#   output_name (optiona)
#       Provide an alternate base name for the generated files, like the .d
#       files. Normally these are based on the target name and go in the
#       output_dir, but if multiple targets with the same name end up in
#       the same output_dir, they can collide.
#
#   depfile_dir (optional)
#       If set, used to store the depfile and corresponding stamp file.
#       Defaults to output_dir
#
#   use_qualified_include (optional)
#       If set, output_dir is not added to include_dirs.
#
#   configs (optional)
#       List of additional configs to be applied to the generated target.
#   deps  (optional)
#   inputs  (optional)
#       List of additional files, required for grit to process source file.
#   visibility  (optional)
#       Normal meaning.
#
# Example
#
#   grit("my_resources") {
#     # Source and outputs are required.
#     source = "myfile.grd"
#     outputs = [
#       "foo_strings.h",
#       "foo_strings.pak",
#     ]
#
#     grit_flags = [ "-E", "foo=bar" ]  # Optional extra flags.
#     # You can also put deps here if the grit source depends on generated
#     # files.
#   }
import("//build/config/chrome_build.gni")
import("//build/config/crypto.gni")
import("//build/config/features.gni")
import("//build/config/ui.gni")

grit_defines = []

# Mac and iOS want Title Case strings.
use_titlecase_in_grd_files = is_mac || is_ios
if (use_titlecase_in_grd_files) {
  grit_defines += [
    "-D",
    "use_titlecase",
  ]
}

if (is_chrome_branded) {
  grit_defines += [
    "-D",
    "_google_chrome",
    "-E",
    "CHROMIUM_BUILD=google_chrome",
  ]
} else {
  grit_defines += [
    "-D",
    "_chromium",
    "-E",
    "CHROMIUM_BUILD=chromium",
  ]
}

if (is_chromeos) {
  grit_defines += [
    "-D",
    "chromeos",
    "-D",
    "scale_factors=2x",
  ]
}

if (is_desktop_linux) {
  grit_defines += [
    "-D",
    "desktop_linux",
  ]
}

if (toolkit_views) {
  grit_defines += [
    "-D",
    "toolkit_views",
  ]
}

if (use_aura) {
  grit_defines += [
    "-D",
    "use_aura",
  ]
}

if (use_ash) {
  grit_defines += [
    "-D",
    "use_ash",
  ]
}

if (use_nss_certs) {
  grit_defines += [
    "-D",
    "use_nss_certs",
  ]
}

if (use_ozone) {
  grit_defines += [
    "-D",
    "use_ozone",
  ]
}

if (enable_image_loader_extension) {
  grit_defines += [
    "-D",
    "image_loader_extension",
  ]
}

if (enable_remoting) {
  grit_defines += [
    "-D",
    "remoting",
  ]
}

if (is_android) {
  grit_defines += [
    "-t",
    "android",
    "-E",
    "ANDROID_JAVA_TAGGED_ONLY=true",
  ]
}

if (is_mac || is_ios) {
  grit_defines += [
    "-D",
    "scale_factors=2x",
  ]
}

if (is_ios) {
  grit_defines += [
    "-t",
    "ios",

    # iOS uses a whitelist to filter resources.
    "-w",
    rebase_path("//build/ios/grit_whitelist.txt", root_build_dir),
  ]
}

if (enable_extensions) {
  grit_defines += [
    "-D",
    "enable_extensions",
  ]
}
if (enable_media_router) {
  grit_defines += [
    "-D",
    "enable_media_router",
  ]
}
if (enable_plugins) {
  grit_defines += [
    "-D",
    "enable_plugins",
  ]
}
if (enable_basic_printing || enable_print_preview) {
  grit_defines += [
    "-D",
    "enable_printing",
  ]
  if (enable_print_preview) {
    grit_defines += [
      "-D",
      "enable_print_preview",
    ]
  }
}
if (enable_themes) {
  grit_defines += [
    "-D",
    "enable_themes",
  ]
}
if (enable_app_list) {
  grit_defines += [
    "-D",
    "enable_app_list",
  ]
}
if (enable_settings_app) {
  grit_defines += [
    "-D",
    "enable_settings_app",
  ]
}
if (enable_google_now) {
  grit_defines += [
    "-D",
    "enable_google_now",
  ]
}

# Note: use_concatenated_impulse_responses is omitted. It is never used and
# should probably be removed from GYP build.
if (enable_webrtc) {
  grit_defines += [
    "-D",
    "enable_webrtc",
  ]
}
if (enable_hangout_services_extension) {
  grit_defines += [
    "-D",
    "enable_hangout_services_extension",
  ]
}
if (enable_task_manager) {
  grit_defines += [
    "-D",
    "enable_task_manager",
  ]
}
if (enable_notifications) {
  grit_defines += [
    "-D",
    "enable_notifications",
  ]
}
if (enable_wifi_bootstrapping) {
  grit_defines += [
    "-D",
    "enable_wifi_bootstrapping",
  ]
}
if (enable_service_discovery) {
  grit_defines += [
    "-D",
    "enable_service_discovery",
  ]
}
if (mac_views_browser) {
  grit_defines += [
    "-D",
    "mac_views_browser",
  ]
}

grit_resource_id_file = "//tools/gritsettings/resource_ids"
grit_info_script = "//tools/grit/grit_info.py"

template("grit") {
  assert(defined(invoker.source),
         "\"source\" must be defined for the grit template $target_name")

  grit_inputs = [ invoker.source ]

  if (defined(invoker.resource_ids)) {
    resource_ids = invoker.resource_ids
  } else {
    resource_ids = grit_resource_id_file
  }
  if (resource_ids != "") {
    # The script depends on the ID file. Only add this dependency if the ID
    # file is specified.
    grit_inputs += [ resource_ids ]
  }

  if (defined(invoker.output_dir)) {
    output_dir = invoker.output_dir
  } else {
    output_dir = target_gen_dir
  }

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

  if (defined(invoker.depfile_dir)) {
    depfile_dir = invoker.depfile_dir
  } else {
    depfile_dir = output_dir
  }

  # These are all passed as arguments to the script so have to be relative to
  # the build directory.
  if (resource_ids != "") {
    resource_ids = rebase_path(resource_ids, root_build_dir)
  }
  rebased_output_dir = rebase_path(output_dir, root_build_dir)
  source_path = rebase_path(invoker.source, root_build_dir)

  if (defined(invoker.grit_flags)) {
    grit_flags = invoker.grit_flags
  } else {
    grit_flags = []  # These are optional so default to empty list.
  }

  assert_files_flags = []

  # We want to make sure the declared outputs actually match what Grit is
  # writing. We write the list to a file (some of the output lists are long
  # enough to not fit on a Windows command line) and ask Grit to verify those
  # are the actual outputs at runtime.
  asserted_list_file =
      "$target_out_dir/${grit_output_name}_expected_outputs.txt"
  write_file(asserted_list_file,
             rebase_path(invoker.outputs, root_build_dir, output_dir))
  assert_files_flags += [ "--assert-file-list=" +
                          rebase_path(asserted_list_file, root_build_dir) ]
  grit_outputs =
      get_path_info(rebase_path(invoker.outputs, ".", output_dir), "abspath")

  # The config and the action below get this visibility son only the generated
  # source set can depend on them. The variable "target_name" will get
  # overwritten inside the inner classes so we need to compute it here.
  target_visibility = [ ":$target_name" ]

  # The current grit setup makes an file in $output_dir/grit/foo.h that
  # the source code expects to include via "grit/foo.h". It would be nice to
  # change this to including absolute paths relative to the root gen directory
  # (like "mycomponent/foo.h"). This config sets up the include path.
  grit_config = target_name + "_grit_config"
  config(grit_config) {
    if (!defined(invoker.use_qualified_include) ||
        !invoker.use_qualified_include) {
      include_dirs = [ output_dir ]
    }
    visibility = target_visibility
  }

  grit_custom_target = target_name + "_grit"
  action(grit_custom_target) {
    script = "//tools/grit/grit.py"
    inputs = grit_inputs

    depfile = "$depfile_dir/${grit_output_name}_stamp.d"
    outputs = [ "${depfile}.stamp" ] + grit_outputs

    args = [
      "-i",
      source_path,
      "build",
    ]
    if (resource_ids != "") {
      args += [
        "-f",
        resource_ids,
      ]
    }
    args += [
              "-o",
              rebased_output_dir,
              "--depdir",
              ".",
              "--depfile",
              rebase_path(depfile, root_build_dir),
              "--write-only-new=1",
              "--depend-on-stamp",
            ] + grit_defines

    # Add extra defines with -D flags.
    if (defined(invoker.defines)) {
      foreach(i, invoker.defines) {
        args += [
          "-D",
          i,
        ]
      }
    }

    args += grit_flags + assert_files_flags

    if (defined(invoker.visibility)) {
      # This needs to include both what the invoker specified (since they
      # probably include generated headers from this target), as well as the
      # generated source set (since there's no guarantee that the visibility
      # specified by the invoker includes our target).
      #
      # Only define visibility at all if the invoker specified it. Otherwise,
      # we want to keep the public "no visibility specified" default.
      visibility = target_visibility + invoker.visibility
    }

    deps = [
      "//tools/grit:grit_sources",
    ]
    if (defined(invoker.deps)) {
      deps += invoker.deps
    }
    if (defined(invoker.inputs)) {
      inputs += invoker.inputs
    }
  }

  # This is the thing that people actually link with, it must be named the
  # same as the argument the template was invoked with.
  source_set(target_name) {
    # Since we generate a file, we need to be run before the targets that
    # depend on us.
    sources = grit_outputs

    # Deps set on the template invocation will go on the action that runs
    # grit above rather than this library. This target needs to depend on the
    # action publicly so other scripts can take the outputs from the grit
    # script as inputs.
    public_deps = [
      ":$grit_custom_target",
    ]
    public_configs = [ ":$grit_config" ]

    if (defined(invoker.public_configs)) {
      public_configs += invoker.public_configs
    }

    if (defined(invoker.configs)) {
      configs += invoker.configs
    }

    if (defined(invoker.visibility)) {
      visibility = invoker.visibility
    }
    output_name = grit_output_name
  }
}
