# Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.

import("runtime_args.gni")

_dart_runtime = get_path_info("../runtime", "abspath")

_base_config = [
  "$_dart_runtime:dart_arch_config",
  "$_dart_runtime:dart_config",
  "$_dart_runtime:dart_os_config",
]

_base_host_targeting_host_config = [ "$_dart_runtime:dart_config" ]

_maybe_product = [ "$_dart_runtime:dart_maybe_product_config" ]

_product = [ "$_dart_runtime:dart_product_config" ]

_jit_config = _base_config + _maybe_product

_jit_product_config = _base_config + _product

_base_libfuzzer_config = [ "$_dart_runtime:dart_libfuzzer_config" ]

_libfuzzer_config = _base_config + _base_libfuzzer_config

_aotruntime_config = _base_config + [
                       "$_dart_runtime:dart_maybe_product_config",
                       "$_dart_runtime:dart_aotruntime_config",
                     ]

_aotruntime_product_config = _base_config + [
                               "$_dart_runtime:dart_aotruntime_config",
                               "$_dart_runtime:dart_product_config",
                             ]

_precompiler_base = [ "$_dart_runtime:dart_precompiler_config" ]

_precompiler_config = _base_config + _precompiler_base + _maybe_product

_precompiler_testing_config =
    _precompiler_config + [ "$_dart_runtime:dart_testing_config" ]

_precompiler_product_config = _base_config + _precompiler_base + _product

_precompiler_host_targeting_host_config =
    _base_host_targeting_host_config + _precompiler_base + _maybe_product

_precompiler_product_host_targeting_host_config =
    _base_host_targeting_host_config + _precompiler_base + _product

_precompiler_product_linux_x64_config =
    [
      "$_dart_runtime:dart_config",
      "$_dart_runtime:dart_linux_x64_config",
    ] + _product + _precompiler_base

_precompiler_product_linux_arm64_config =
    [
      "$_dart_runtime:dart_config",
      "$_dart_runtime:dart_linux_arm64_config",
    ] + _product + _precompiler_base

_precompiler_product_linux_arm_config =
    [
      "$_dart_runtime:dart_config",
      "$_dart_runtime:dart_linux_arm_config",
    ] + _product + _precompiler_base

_precompiler_product_linux_riscv64_config =
    [
      "$_dart_runtime:dart_config",
      "$_dart_runtime:dart_linux_riscv64_config",
    ] + _product + _precompiler_base

_all_configs = [
  {
    suffix = "_jit"
    configs = _jit_config
    snapshot = true
    compiler = true
    is_product = false
  },
  {
    suffix = "_jit_product"
    configs = _jit_product_config
    snapshot = true
    compiler = true
    is_product = true
  },
  {
    suffix = "_aotruntime"
    configs = _aotruntime_config
    snapshot = true
    compiler = false
    is_product = false
  },
  {
    suffix = "_aotruntime_product"
    configs = _aotruntime_product_config
    snapshot = true
    compiler = false
    is_product = true
  },
  {
    suffix = "_precompiler"
    configs = _precompiler_config
    snapshot = false
    compiler = true
    is_product = false
  },
  {
    suffix = "_precompiler_testing"
    configs = _precompiler_testing_config
    snapshot = false
    compiler = true
    is_product = false
  },
  {
    suffix = "_precompiler_product"
    configs = _precompiler_product_config
    snapshot = false
    compiler = true
    is_product = true
  },
  {
    suffix = "_precompiler_host_targeting_host"
    configs = _precompiler_host_targeting_host_config
    snapshot = false
    compiler = true
    is_product = false
  },
  {
    suffix = "_precompiler_product_host_targeting_host"
    configs = _precompiler_product_host_targeting_host_config
    snapshot = false
    compiler = true
    is_product = true
  },
  {
    suffix = "_libfuzzer"
    configs = _libfuzzer_config
    snapshot = true
    compiler = true
    is_product = false
  },
  {
    suffix = "_precompiler_product_linux_x64"
    configs = _precompiler_product_linux_x64_config
    snapshot = false
    compiler = true
    is_product = true
  },
  {
    suffix = "_precompiler_product_linux_arm64"
    configs = _precompiler_product_linux_arm64_config
    snapshot = false
    compiler = true
    is_product = true
  },
  {
    suffix = "_precompiler_product_linux_arm"
    configs = _precompiler_product_linux_arm_config
    snapshot = false
    compiler = true
    is_product = true
  },
  {
    suffix = "_precompiler_product_linux_riscv64"
    configs = _precompiler_product_linux_riscv64_config
    snapshot = false
    compiler = true
    is_product = true
  },
]

# This template creates a target for each of the configurations listed above.
# For example:
#
#  library_for_all_configs("libfoo") {
#    target_type = "source_set"
#    sources = [ "foo.c" ]
#    configurable_deps [ ":libbar" ]
#  }
#
# will make a source_set target for libfoo_jit, libfoo_jit_product, etc. that
# depends on libbar_jit, libbar_jit_product etc. respectively.
#
# Parameters
#
#  target_type (required):
#    The target declaration or template to repeat for each configuration.
#
#  configurable_deps (optional):
#    Dependencies of this target, which are themselves generated by
#    library_for_all_configs(). The listed dependencies will be suffixed with
#    a string that matches the configuration.
#
#  extra_deps (optional):
#    Regular additional deps that don't receive special treatment.
#
#  extra_configs (optional):
#    Any configs needed in addition to the ones above.
#
#  snapshot_sources (optional):
#    Additional sources to include when the configuration has a snapshot.
#
template("library_for_all_configs") {
  assert(defined(invoker.target_type))
  extra_configs = []
  if (defined(invoker.extra_configs)) {
    extra_configs += invoker.extra_configs
  }
  configurable_deps = []
  if (defined(invoker.configurable_deps)) {
    configurable_deps += invoker.configurable_deps
  }
  extra_deps = []
  if (defined(invoker.extra_deps)) {
    extra_deps += invoker.extra_deps
  }
  extra_product_deps = []
  if (defined(invoker.extra_product_deps)) {
    extra_product_deps += invoker.extra_product_deps
  }
  extra_nonproduct_deps = []
  if (defined(invoker.extra_nonproduct_deps)) {
    extra_nonproduct_deps += invoker.extra_nonproduct_deps
  }
  extra_precompiler_deps = []
  if (defined(invoker.extra_precompiler_deps)) {
    extra_precompiler_deps += invoker.extra_precompiler_deps
  }
  foreach(conf, _all_configs) {
    target(invoker.target_type, "${target_name}${conf.suffix}") {
      forward_variables_from(invoker,
                             "*",
                             [
                               "extra_configs",
                               "extra_deps",
                               "configurable_deps",
                             ])
      configs += conf.configs + extra_configs
      configured_deps = []
      foreach(dep, configurable_deps) {
        configured_deps += [ "${dep}${conf.suffix}" ]
      }
      if (defined(compiler_lib)) {
        if (conf.compiler) {
          configured_deps += [ "${compiler_lib}${conf.suffix}" ]
        } else {
          not_needed([ "compiler_lib" ])
        }
      }
      deps = configured_deps + extra_deps

      # The "dart_maybe_product_config" and "dart_product_config" configs in
      # runtime/BUILD.gn have logic to avoid building PRODUCT artifacts in debug
      # builds.
      if (conf.is_product && !dart_debug) {
        not_needed([ "extra_nonproduct_deps" ])
        deps += extra_product_deps
      } else {
        not_needed([ "extra_product_deps" ])
        deps += extra_nonproduct_deps
      }
      if (conf.snapshot) {
        if (defined(snapshot_sources)) {
          sources += snapshot_sources
        }
      } else {
        if (conf.compiler) {
          deps += extra_precompiler_deps
        }
        if (defined(snapshot_sources)) {
          not_needed([ "snapshot_sources" ])
        }
      }
    }
  }
}

template("library_for_all_configs_with_compiler") {
  assert(defined(invoker.target_type))
  extra_configs = []
  if (defined(invoker.extra_configs)) {
    extra_configs += invoker.extra_configs
  }
  configurable_deps = []
  if (defined(invoker.configurable_deps)) {
    configurable_deps += invoker.configurable_deps
  }
  extra_deps = []
  if (defined(invoker.extra_deps)) {
    extra_deps += invoker.extra_deps
  }
  extra_product_deps = []
  if (defined(invoker.extra_product_deps)) {
    extra_product_deps += invoker.extra_product_deps
  }
  extra_nonproduct_deps = []
  if (defined(invoker.extra_nonproduct_deps)) {
    extra_nonproduct_deps += invoker.extra_nonproduct_deps
  }
  extra_precompiler_deps = []
  if (defined(invoker.extra_precompiler_deps)) {
    extra_precompiler_deps += invoker.extra_precompiler_deps
  }
  foreach(conf, _all_configs) {
    if (conf.compiler) {
      target(invoker.target_type, "${target_name}${conf.suffix}") {
        forward_variables_from(invoker,
                               "*",
                               [
                                 "extra_configs",
                                 "extra_deps",
                                 "configurable_deps",
                               ])
        configs += conf.configs + extra_configs
        configured_deps = []
        foreach(dep, configurable_deps) {
          configured_deps += [ "${dep}${conf.suffix}" ]
        }
        deps = configured_deps + extra_deps

        # The "dart_maybe_product_config" and "dart_product_config" configs in
        # runtime/BUILD.gn have logic to avoid building PRODUCT artifacts in
        # debug builds.
        if (conf.is_product && !dart_debug) {
          not_needed([ "extra_nonproduct_deps" ])
          deps += extra_product_deps
        } else {
          not_needed([ "extra_product_deps" ])
          deps += extra_nonproduct_deps
        }
        if (conf.snapshot) {
          if (defined(snapshot_sources)) {
            sources += snapshot_sources
          }
        } else {
          deps += extra_precompiler_deps
          if (defined(snapshot_sources)) {
            not_needed([ "snapshot_sources" ])
          }
        }
      }
    }
  }
}
