1# Copyright 2014 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5import("//build/config/jumbo.gni")
6
7# TODO(rockot): Maybe we can factor these dependencies out of //mojo. They're
8# used to conditionally enable message ID scrambling in a way which is
9# consistent across toolchains and which is affected by branded vs non-branded
10# Chrome builds. Ideally we could create some generic knobs here that could be
11# flipped elsewhere though.
12import("//build/config/chrome_build.gni")
13import("//build/config/nacl/config.gni")
14import("//components/nacl/features.gni")
15import("//third_party/jinja2/jinja2.gni")
16import("//tools/ipc_fuzzer/ipc_fuzzer.gni")
17
18declare_args() {
19  # Indicates whether typemapping should be supported in this build
20  # configuration. This may be disabled when building external projects which
21  # depend on //mojo but which do not need/want all of the Chromium tree
22  # dependencies that come with typemapping.
23  #
24  # Note that (perhaps obviously) a huge amount of Chromium code will not build
25  # with typemapping disabled, so it is never valid to set this to |false| in
26  # any Chromium build configuration.
27  enable_mojom_typemapping = true
28
29  # Controls message ID scrambling behavior. If |true|, message IDs are
30  # scrambled (i.e. randomized based on the contents of //chrome/VERSION) on
31  # non-Chrome OS desktop platforms. Set to |false| to disable message ID
32  # scrambling on all platforms.
33  enable_mojom_message_id_scrambling = true
34}
35
36# NOTE: We would like to avoid scrambling message IDs where it doesn't add
37# value, so we limit the behavior to desktop builds for now. There is some
38# redundancy in the conditions here, but it is tolerated for clarity:
39# We're explicit about Mac, Windows, and Linux desktop support, but it's
40# also necessary to ensure that bindings in alternate toolchains (e.g.
41# NaCl IRT) are always consistent with the default toolchain; for that
42# reason we always enable scrambling within NaCl toolchains when possible,
43# as well as within the default toolchain when NaCl is enabled.
44#
45# Finally, because we *cannot* enable scrambling on Chrome OS (it would break
46# ARC) we have to explicitly opt out there even when NaCl is enabled (and
47# consequently also when building for NaCl toolchains.) For this reason we
48# check |target_os| explicitly, as it's consistent across all toolchains.
49enable_scrambled_message_ids =
50    enable_mojom_message_id_scrambling &&
51    (is_mac || is_win || (is_linux && !is_chromeos) ||
52     ((enable_nacl || is_nacl || is_nacl_nonsfi) && target_os != "chromeos"))
53
54mojom_generator_root = "//mojo/public/tools/bindings"
55mojom_generator_script = "$mojom_generator_root/mojom_bindings_generator.py"
56mojom_generator_sources = [
57  "$mojom_generator_root/generators/mojom_cpp_generator.py",
58  "$mojom_generator_root/generators/mojom_js_generator.py",
59  "$mojom_generator_root/generators/mojom_java_generator.py",
60  "$mojom_generator_root/pylib/mojom/__init__.py",
61  "$mojom_generator_root/pylib/mojom/error.py",
62  "$mojom_generator_root/pylib/mojom/generate/__init__.py",
63  "$mojom_generator_root/pylib/mojom/generate/constant_resolver.py",
64  "$mojom_generator_root/pylib/mojom/generate/generator.py",
65  "$mojom_generator_root/pylib/mojom/generate/module.py",
66  "$mojom_generator_root/pylib/mojom/generate/pack.py",
67  "$mojom_generator_root/pylib/mojom/generate/template_expander.py",
68  "$mojom_generator_root/pylib/mojom/generate/translate.py",
69  "$mojom_generator_root/pylib/mojom/parse/__init__.py",
70  "$mojom_generator_root/pylib/mojom/parse/ast.py",
71  "$mojom_generator_root/pylib/mojom/parse/lexer.py",
72  "$mojom_generator_root/pylib/mojom/parse/parser.py",
73  "$mojom_generator_script",
74]
75
76if (enable_scrambled_message_ids) {
77  declare_args() {
78    # The path to a file whose contents can be used as the basis for a message
79    # ID scrambling salt.
80    mojom_message_id_salt_path = "//chrome/VERSION"
81
82    # The path to a file whose contents will be concatenated to the contents of
83    # the file at |mojom_message_id_salt_path| to form a complete salt for
84    # message ID scrambling. May be the empty string, in which case the contents
85    # of the above file alone are used as the complete salt.
86    if (is_chrome_branded) {
87      mojom_message_id_salt_suffix_path =
88          "//mojo/internal/chrome-message-id-salt-suffix"
89    } else {
90      mojom_message_id_salt_suffix_path = ""
91    }
92  }
93
94  assert(mojom_message_id_salt_path != "")
95  message_scrambling_args = [
96    "--scrambled_message_id_salt_path",
97    rebase_path(mojom_message_id_salt_path, root_build_dir),
98  ]
99  message_scrambling_inputs = [ mojom_message_id_salt_path ]
100
101  if (mojom_message_id_salt_suffix_path != "") {
102    message_scrambling_args += [
103      "--scrambled_message_id_salt_path",
104      rebase_path(mojom_message_id_salt_suffix_path, root_build_dir),
105    ]
106    message_scrambling_inputs += [ mojom_message_id_salt_suffix_path ]
107  }
108} else {
109  message_scrambling_args = []
110  message_scrambling_inputs = []
111}
112
113if (enable_mojom_typemapping) {
114  if (!is_ios) {
115    _bindings_configuration_files = [
116      "//mojo/public/tools/bindings/chromium_bindings_configuration.gni",
117      "//mojo/public/tools/bindings/blink_bindings_configuration.gni",
118    ]
119  } else {
120    _bindings_configuration_files =
121        [ "//mojo/public/tools/bindings/chromium_bindings_configuration.gni" ]
122  }
123  _bindings_configurations = []
124  foreach(config_file, _bindings_configuration_files) {
125    _bindings_configurations += [ read_file(config_file, "scope") ]
126  }
127  foreach(configuration, _bindings_configurations) {
128    # Check that the mojom field of each typemap refers to a mojom that exists.
129    foreach(typemap, configuration.typemaps) {
130      _typemap_config = {
131      }
132      _typemap_config = typemap.config
133      read_file(_typemap_config.mojom, "")
134    }
135  }
136} else {
137  _bindings_configuration_files = []
138  _bindings_configurations = [
139    {
140      typemaps = []
141      component_macro_suffix = ""
142    },
143    {
144      variant = "blink"
145      component_macro_suffix = "_BLINK"
146      for_blink = true
147      typemaps = []
148    },
149  ]
150}
151
152# Generates targets for building C++, JavaScript and Java bindings from mojom
153# files. The output files will go under the generated file directory tree with
154# the same path as each input file.
155#
156# Other targets should depend on one of these generated targets (where "foo"
157# is the target name):
158#
159#   foo
160#       C++ bindings.
161#
162#   foo_blink
163#       C++ bindings using Blink standard types.
164#
165#   foo_java
166#       Java bindings.
167#
168#   foo_js
169#       JavaScript bindings; used as compile-time dependency.
170#
171#   foo_js_data_deps
172#       JavaScript bindings; used as run-time dependency.
173#
174# Parameters:
175#
176#   sources (optional if one of the deps sets listed below is present)
177#       List of source .mojom files to compile.
178#
179#   deps (optional)
180#       Note: this can contain only other mojom targets.
181#
182#       DEPRECATED: This is synonymous with public_deps because all mojom
183#       dependencies must be public by design. Please use public_deps.
184#
185#   public_deps (optional)
186#       Note: this can contain only other mojom targets.
187#
188#   import_dirs (optional)
189#       List of import directories that will get added when processing sources.
190#
191#   testonly (optional)
192#
193#   visibility (optional)
194#
195#   visibility_blink (optional)
196#       The value to use for visibility for the blink variant. If unset,
197#       |visibility| is used.
198#
199#   use_once_callback (optional)
200#       If set to true, generated classes will use base::OnceCallback instead of
201#       base::RepeatingCallback.
202#       Default value is true.
203#       TODO(dcheng):
204#           - Convert everything to use OnceCallback.
205#           - Remove support for the old mode.
206#
207#   cpp_only (optional)
208#       If set to true, only the C++ bindings targets will be generated.
209#
210#   support_lazy_serialization (optional)
211#       If set to |true|, generated C++ bindings will effectively prefer to
212#       transmit messages in an unserialized form when going between endpoints
213#       in the same process. This avoids the runtime cost of serialization,
214#       deserialization, and validation logic at the expensive of increased
215#       code size. Defaults to |false|.
216#
217#   disable_variants (optional)
218#       If |true|, no variant sources will be generated for the target. Defaults
219#       to |false|.
220#
221#   disallow_native_types (optional)
222#       If set to |true|, mojoms in this target may not apply the [Native]
223#       attribute to struct or enum declarations. This avoids emitting code
224#       which depends on legacy IPC serialization. Default is |false|, meaning
225#       [Native] types are allowed.
226#
227#   disallow_interfaces (optional)
228#       If set to |true|, mojoms in this target may not define interfaces.
229#       Generates bindings with a smaller set of dependencies. Defaults to
230#       |false|.
231#
232#   scramble_message_ids (optional)
233#       If set to |true| (the default), generated mojom interfaces will use
234#       scrambled ordinal identifiers in encoded messages.
235#
236#   component_output_prefix (optional)
237#       The prefix to use for the output_name of any component library emitted
238#       for generated C++ bindings. If this is omitted, C++ bindings targets are
239#       emitted as source_sets instead. Because this controls the name of the
240#       output shared library binary in the root output directory, it must be
241#       unique across the entire build configuration.
242#
243#       This is required if |component_macro_prefix| is specified.
244#
245#   component_macro_prefix (optional)
246#       This specifies a macro prefix to use for component export macros and
247#       should therefore be globally unique in the project. For example if this
248#       is "FOO_BAR", then the generated C++ sources will be built with
249#       IS_FOO_BAR_{suffix}_IMPL defined, and the generated public headers will
250#       annotate public symbol definitions with
251#       COMPONENT_EXPORT(FOO_BAR_{suffix}). "suffix" in this case depends on
252#       which internal subtarget is generating the code (e.g. "SHARED", or a
253#       variant name like "BLINK").
254#
255#   enabled_features (optional)
256#       Definitions in a mojom file can be guarded by an EnableIf attribute. If
257#       the value specified by the attribute does not match any items in the
258#       list of enabled_features, the definition will be disabled, with no code
259#       emitted for it.
260#
261# The following parameters are used to support the component build. They are
262# needed so that bindings which are linked with a component can use the same
263# export settings for classes. The first three are for the chromium variant, and
264# the last three are for the blink variant. These parameters are mutually
265# exclusive to |component_macro_prefix|, but |component_output_prefix| may still
266# be used to uniqueify the generated invariant (i.e. shared) output component.
267#   export_class_attribute (optional)
268#       The attribute to add to the class declaration. e.g. "CONTENT_EXPORT"
269#   export_define (optional)
270#       A define to be added to the source_set which is needed by the export
271#       header. e.g. "CONTENT_IMPLEMENTATION=1"
272#   export_header (optional)
273#       A header to be added to the generated bindings to support the component
274#       build. e.g. "content/common/content_export.h"
275#   export_class_attribute_blink (optional)
276#   export_define_blink (optional)
277#   export_header_blink (optional)
278#       These three parameters are the blink variants of the previous 3.
279#
280# The following parameters are used to correct component build dependencies.
281# They are needed so mojom-mojom dependencies follow the rule that dependencies
282# on a source set in another component are replaced by a dependency on the
283# containing component. The first two are for the chromium variant; the other
284# two are for the blink variant.
285#   overridden_deps (optional)
286#       The list of mojom deps to be overridden.
287#   component_deps (optional)
288#       The list of component deps to add to replace overridden_deps.
289#   overridden_deps_blink (optional)
290#   component_deps_blink (optional)
291#       These two parameters are the blink variants of the previous two.
292#
293# check_includes_blink (optional)
294#     Overrides the check_includes variable for the blink variant.
295#     If check_includes_blink is not defined, the check_includes variable
296#     retains its original value.
297template("mojom") {
298  assert(
299      defined(invoker.sources) || defined(invoker.deps) ||
300          defined(invoker.public_deps),
301      "\"sources\" or \"deps\" must be defined for the $target_name template.")
302
303  if (defined(invoker.export_class_attribute) ||
304      defined(invoker.export_define) || defined(invoker.export_header)) {
305    assert(defined(invoker.export_class_attribute))
306    assert(defined(invoker.export_define))
307    assert(defined(invoker.export_header))
308    assert(!defined(invoker.component_macro_prefix))
309  }
310  if (defined(invoker.export_class_attribute_blink) ||
311      defined(invoker.export_define_blink) ||
312      defined(invoker.export_header_blink)) {
313    assert(defined(invoker.export_class_attribute_blink))
314    assert(defined(invoker.export_define_blink))
315    assert(defined(invoker.export_header_blink))
316    assert(!defined(invoker.component_macro_prefix))
317  }
318  if (defined(invoker.overridden_deps) || defined(invoker.component_deps)) {
319    assert(defined(invoker.overridden_deps))
320    assert(defined(invoker.component_deps))
321  }
322
323  if (defined(invoker.overridden_deps_blink) ||
324      defined(invoker.component_deps_blink)) {
325    assert(defined(invoker.overridden_deps_blink))
326    assert(defined(invoker.component_deps_blink))
327  }
328
329  require_full_cpp_deps =
330      !defined(invoker.disallow_native_types) ||
331      !invoker.disallow_native_types || !defined(invoker.disallow_interfaces) ||
332      !invoker.disallow_interfaces
333
334  all_deps = []
335  if (defined(invoker.deps)) {
336    all_deps += invoker.deps
337  }
338  if (defined(invoker.public_deps)) {
339    all_deps += invoker.public_deps
340  }
341
342  if (defined(invoker.component_macro_prefix)) {
343    assert(defined(invoker.component_output_prefix))
344  }
345
346  group("${target_name}__is_mojom") {
347  }
348
349  # Explicitly ensure that all dependencies (invoker.deps and
350  # invoker.public_deps) are mojom targets.
351  group("${target_name}__check_deps_are_all_mojom") {
352    deps = []
353    foreach(d, all_deps) {
354      name = get_label_info(d, "label_no_toolchain")
355      toolchain = get_label_info(d, "toolchain")
356      deps += [ "${name}__is_mojom(${toolchain})" ]
357    }
358  }
359
360  target_sources_list = "$target_gen_dir/$target_name.sources_list"
361  sources_list = []
362  if (defined(invoker.sources)) {
363    sources_list = invoker.sources
364  }
365  write_file(target_sources_list, sources_list)
366
367  # a target implicitly depends on its own sources
368  deps_sources = [ rebase_path(target_sources_list, root_build_dir) ]
369  foreach(d, all_deps) {
370    dep_dir = get_label_info("$d", "target_gen_dir")
371    dep_short_name = get_label_info("$d", "name")
372    deps_sources +=
373        [ rebase_path("$dep_dir/$dep_short_name.sources_list", root_build_dir) ]
374  }
375
376  write_file("$target_gen_dir/$target_name.deps_sources_list", deps_sources)
377
378  if (defined(invoker.sources)) {
379    parser_target_name = "${target_name}__parser"
380    enabled_features = []
381    if (defined(invoker.enabled_features)) {
382      enabled_features += invoker.enabled_features
383    }
384    if (is_posix) {
385      enabled_features += [ "is_posix" ]
386    }
387    if (is_android) {
388      enabled_features += [ "is_android" ]
389    } else if (is_chromeos) {
390      enabled_features += [ "is_chromeos" ]
391    } else if (is_fuchsia) {
392      enabled_features += [ "is_fuchsia" ]
393    } else if (is_ios) {
394      enabled_features += [ "is_ios" ]
395    } else if (is_linux) {
396      enabled_features += [ "is_linux" ]
397    } else if (is_mac) {
398      enabled_features += [ "is_mac" ]
399    } else if (is_win) {
400      enabled_features += [ "is_win" ]
401    }
402
403    action(parser_target_name) {
404      script = mojom_generator_script
405      inputs = mojom_generator_sources + jinja2_sources
406      sources = invoker.sources
407      outputs = []
408      filelist = []
409      foreach(source, invoker.sources) {
410        filename = get_path_info("$source", "name")
411        dirname = get_path_info("$source", "gen_dir")
412        outputs += [ "$dirname/$filename.p" ]
413        filelist += [ rebase_path("$source", root_build_dir) ]
414      }
415
416      response_file_contents = filelist
417
418      args = [
419        "parse",
420        "--filelist={{response_file_name}}",
421        "-o",
422        rebase_path(root_gen_dir, root_build_dir),
423        "-d",
424        rebase_path("//", root_build_dir),
425      ]
426      foreach(enabled_feature, enabled_features) {
427        args += [
428          "--enable_feature",
429          enabled_feature,
430        ]
431      }
432    }
433  }
434
435  parsed_target_name = "${target_name}__parsed"
436  group(parsed_target_name) {
437    public_deps = []
438    if (defined(invoker.sources)) {
439      public_deps += [ ":$parser_target_name" ]
440    }
441    foreach(d, all_deps) {
442      # Resolve the name, so that a target //mojo/something becomes
443      # //mojo/something:something and we can append the parsed
444      # suffix to get the mojom dependency name.
445      full_name = get_label_info("$d", "label_no_toolchain")
446      public_deps += [ "${full_name}__parsed" ]
447    }
448  }
449
450  if (defined(invoker.sources)) {
451    verify_deps_target_names = []
452    if (!defined(invoker.skip_deps_check) || !invoker.skip_deps_check) {
453      verify_deps_target_name = "${target_name}__verify_deps"
454      verify_deps_target_names += [ ":$verify_deps_target_name" ]
455      source_file_name = target_name
456
457      action(verify_deps_target_name) {
458        script = mojom_generator_script
459        inputs = mojom_generator_sources + jinja2_sources
460        sources = invoker.sources
461        deps = [
462          ":$parsed_target_name",
463        ]
464        outputs = []
465        filelist = []
466        foreach(source, invoker.sources) {
467          filename = get_path_info("$source", "name")
468          dirname = get_path_info("$source", "gen_dir")
469          outputs += [ "$dirname/$filename.v" ]
470          filelist += [ rebase_path("$source", root_build_dir) ]
471        }
472
473        response_file_contents = filelist
474
475        args = [
476          "verify",
477          "--filelist={{response_file_name}}",
478          "-f",
479          rebase_path("$target_gen_dir/$source_file_name.deps_sources_list",
480                      root_build_dir),
481          "--gen_dir",
482          rebase_path(root_gen_dir, root_build_dir),
483          "--depth",
484          rebase_path("//", root_build_dir),
485        ]
486      }
487    }
488  }
489
490  generator_cpp_message_ids_target_name = "${target_name}__generate_message_ids"
491
492  # Generate code that is shared by different variants.
493  if (defined(invoker.sources)) {
494    common_generator_args = [
495      "--use_bundled_pylibs",
496      "generate",
497      "-d",
498      rebase_path("//", root_build_dir),
499      "-I",
500      rebase_path("//", root_build_dir),
501      "-o",
502      rebase_path(root_gen_dir, root_build_dir),
503      "--bytecode_path",
504      rebase_path("$root_gen_dir/mojo/public/tools/bindings", root_build_dir),
505    ]
506
507    if (defined(invoker.disallow_native_types) &&
508        invoker.disallow_native_types) {
509      common_generator_args += [ "--disallow_native_types" ]
510    }
511
512    if (defined(invoker.disallow_interfaces) && invoker.disallow_interfaces) {
513      common_generator_args += [ "--disallow_interfaces" ]
514    }
515
516    if (defined(invoker.import_dirs)) {
517      foreach(import_dir, invoker.import_dirs) {
518        common_generator_args += [
519          "-I",
520          rebase_path(import_dir, root_build_dir),
521        ]
522      }
523    }
524
525    if (defined(invoker.component_macro_prefix)) {
526      shared_component_export_macro =
527          "COMPONENT_EXPORT(${invoker.component_macro_prefix}_SHARED)"
528      shared_component_impl_macro =
529          "IS_${invoker.component_macro_prefix}_SHARED_IMPL"
530      shared_component_output_name = "${invoker.component_output_prefix}_shared"
531    } else if (defined(invoker.export_class_attribute_shared) ||
532               defined(invoker.export_class_attribute)) {
533      if (defined(invoker.export_class_attribute_shared)) {
534        assert(defined(invoker.export_header_shared))
535        shared_component_export_macro = invoker.export_class_attribute_shared
536        shared_component_impl_macro = invoker.export_define_shared
537      } else {
538        assert(!defined(invoker.export_header_shared))
539
540        # If no explicit shared attribute/define was provided by the invoker,
541        # we derive some reasonable settings frorm the default variant.
542        shared_component_export_macro = "COMPONENT_EXPORT(MOJOM_SHARED_" +
543                                        invoker.export_class_attribute + ")"
544        shared_component_impl_macro =
545            "IS_MOJOM_SHARED_" + invoker.export_class_attribute + "_IMPL"
546      }
547
548      if (defined(invoker.component_output_prefix)) {
549        shared_component_output_name =
550            "${invoker.component_output_prefix}_shared"
551      } else {
552        shared_component_output_name = "${target_name}_shared"
553      }
554    }
555
556    action(generator_cpp_message_ids_target_name) {
557      script = mojom_generator_script
558      inputs = mojom_generator_sources + jinja2_sources
559      sources = invoker.sources
560      deps = [
561        ":$parsed_target_name",
562        "//mojo/public/tools/bindings:precompile_templates",
563      ]
564      outputs = []
565      args = common_generator_args
566      filelist = []
567      foreach(source, invoker.sources) {
568        outputs += [ "$target_gen_dir/$source-shared-message-ids.h" ]
569        filelist += [ rebase_path("$source", root_build_dir) ]
570      }
571
572      response_file_contents = filelist
573
574      args += [
575        "--filelist={{response_file_name}}",
576        "--generate_non_variant_code",
577        "--generate_message_ids",
578        "-g",
579        "c++",
580      ]
581
582      if (!defined(invoker.scramble_message_ids) ||
583          invoker.scramble_message_ids) {
584        inputs += message_scrambling_inputs
585        args += message_scrambling_args
586      }
587    }
588
589    generator_shared_cpp_outputs = [
590      "{{source_gen_dir}}/{{source_name_part}}.mojom-shared-internal.h",
591      "{{source_gen_dir}}/{{source_name_part}}.mojom-shared.cc",
592      "{{source_gen_dir}}/{{source_name_part}}.mojom-shared.h",
593    ]
594    generator_shared_target_name = "${target_name}_shared__generator"
595    action(generator_shared_target_name) {
596      script = mojom_generator_script
597      inputs = mojom_generator_sources + jinja2_sources
598      sources = invoker.sources
599      deps = [
600               ":$parsed_target_name",
601               "//mojo/public/tools/bindings:precompile_templates",
602             ] + verify_deps_target_names
603
604      outputs = []
605      args = common_generator_args
606      filelist = []
607      foreach(source, invoker.sources) {
608        filelist += [ rebase_path("$source", root_build_dir) ]
609        outputs += [
610          "$target_gen_dir/$source-shared-internal.h",
611          "$target_gen_dir/$source-shared.cc",
612          "$target_gen_dir/$source-shared.h",
613        ]
614      }
615
616      response_file_contents = filelist
617
618      args += [
619        "--filelist={{response_file_name}}",
620        "--generate_non_variant_code",
621        "-g",
622        "c++",
623      ]
624
625      if (defined(shared_component_export_macro)) {
626        args += [
627          "--export_attribute",
628          shared_component_export_macro,
629          "--export_header",
630          "base/component_export.h",
631        ]
632      }
633    }
634  } else {
635    group(generator_cpp_message_ids_target_name) {
636    }
637  }
638
639  shared_cpp_sources_target_name = "${target_name}_shared_cpp_sources"
640  jumbo_source_set(shared_cpp_sources_target_name) {
641    if (defined(invoker.testonly)) {
642      testonly = invoker.testonly
643    }
644    deps = []
645    if (defined(invoker.sources)) {
646      sources =
647          process_file_template(invoker.sources, generator_shared_cpp_outputs)
648      deps += [ ":$generator_shared_target_name" ]
649    }
650    if (require_full_cpp_deps) {
651      public_deps = [
652        "//mojo/public/cpp/bindings",
653      ]
654    } else {
655      public_deps = [
656        "//mojo/public/cpp/bindings:bindings_base",
657      ]
658    }
659    foreach(d, all_deps) {
660      # Resolve the name, so that a target //mojo/something becomes
661      # //mojo/something:something and we can append shared_cpp_sources_suffix
662      # to get the cpp dependency name.
663      full_name = get_label_info("$d", "label_no_toolchain")
664      public_deps += [ "${full_name}_shared" ]
665    }
666    if (defined(shared_component_impl_macro)) {
667      defines = [ shared_component_impl_macro ]
668    }
669  }
670
671  shared_cpp_library_target_name = "${target_name}_shared"
672  if (defined(shared_component_output_name)) {
673    component(shared_cpp_library_target_name) {
674      if (defined(invoker.testonly)) {
675        testonly = invoker.testonly
676      }
677      output_name = "$shared_component_output_name"
678      public_deps = [
679        ":$shared_cpp_sources_target_name",
680      ]
681    }
682  } else {
683    group(shared_cpp_library_target_name) {
684      if (defined(invoker.testonly)) {
685        testonly = invoker.testonly
686      }
687      public_deps = [
688        ":$shared_cpp_sources_target_name",
689      ]
690    }
691  }
692
693  # Generate code for variants.
694  if (!defined(invoker.disable_variants) || !invoker.disable_variants) {
695    enabled_configurations = _bindings_configurations
696  } else {
697    first_config = _bindings_configurations[0]
698    assert(!defined(first_config.variant))
699    enabled_configurations = [ first_config ]
700  }
701  foreach(bindings_configuration, enabled_configurations) {
702    cpp_only = false
703    if (defined(invoker.cpp_only)) {
704      cpp_only = invoker.cpp_only
705    }
706    variant_suffix = ""
707    if (defined(bindings_configuration.variant)) {
708      variant = bindings_configuration.variant
709      variant_suffix = "_${variant}"
710      cpp_only = true
711    }
712    type_mappings_target_name = "${target_name}${variant_suffix}__type_mappings"
713    type_mappings_path =
714        "$target_gen_dir/${target_name}${variant_suffix}__type_mappings"
715    active_typemaps = []
716    enabled_sources = []
717    if (defined(invoker.sources)) {
718      generator_cpp_outputs = []
719      variant_dash_suffix = ""
720      if (defined(variant)) {
721        variant_dash_suffix = "-${variant}"
722      }
723      generator_cpp_outputs += [
724        "{{source_gen_dir}}/{{source_name_part}}.mojom${variant_dash_suffix}.cc",
725        "{{source_gen_dir}}/{{source_name_part}}.mojom${variant_dash_suffix}.h",
726      ]
727      enabled_sources = []
728      if (defined(bindings_configuration.blacklist)) {
729        foreach(source, invoker.sources) {
730          blacklisted = false
731          foreach(blacklisted_source, bindings_configuration.blacklist) {
732            if (get_path_info(source, "abspath") == blacklisted_source) {
733              blacklisted = true
734            }
735          }
736          if (!blacklisted) {
737            enabled_sources += [ source ]
738          }
739        }
740      } else {
741        enabled_sources = invoker.sources
742      }
743      foreach(source, enabled_sources) {
744        # TODO(sammc): Use a map instead of a linear scan when GN supports maps.
745        foreach(typemap, bindings_configuration.typemaps) {
746          _typemap_config = {
747          }
748          _typemap_config = typemap.config
749          if (get_path_info(source, "abspath") == _typemap_config.mojom) {
750            enabled = false
751            if (!defined(_typemap_config.os_whitelist)) {
752              enabled = true
753            } else {
754              foreach(os, _typemap_config.os_whitelist) {
755                if (os == "android" && is_android) {
756                  enabled = true
757                } else if (os == "chromeos" && is_chromeos) {
758                  enabled = true
759                } else if (os == "fuchsia" && is_fuchsia) {
760                  enabled = true
761                } else if (os == "ios" && is_ios) {
762                  enabled = true
763                } else if (os == "linux" && is_linux) {
764                  enabled = true
765                } else if (os == "mac" && is_mac) {
766                  enabled = true
767                } else if (os == "posix" && is_posix) {
768                  enabled = true
769                } else if (os == "win" && is_win) {
770                  enabled = true
771                }
772              }
773            }
774            if (enabled) {
775              active_typemaps += [ typemap ]
776            }
777          }
778        }
779      }
780
781      generator_target_name = "${target_name}${variant_suffix}__generator"
782      action(generator_target_name) {
783        script = mojom_generator_script
784        inputs = mojom_generator_sources + jinja2_sources
785        sources = invoker.sources
786        deps = [
787                 ":$parsed_target_name",
788                 ":$type_mappings_target_name",
789                 "//mojo/public/tools/bindings:precompile_templates",
790               ] + verify_deps_target_names
791        outputs = []
792        args = common_generator_args
793        filelist = []
794        foreach(source, invoker.sources) {
795          filelist += [ rebase_path("$source", root_build_dir) ]
796          outputs += [
797            "$target_gen_dir/${source}${variant_dash_suffix}.cc",
798            "$target_gen_dir/${source}${variant_dash_suffix}.h",
799          ]
800        }
801
802        response_file_contents = filelist
803
804        args += [
805          "--filelist={{response_file_name}}",
806          "-g",
807          "c++",
808        ]
809
810        if (defined(bindings_configuration.variant)) {
811          args += [
812            "--variant",
813            bindings_configuration.variant,
814          ]
815        }
816
817        args += [
818          "--typemap",
819          rebase_path(type_mappings_path, root_build_dir),
820        ]
821
822        if (defined(invoker.component_macro_prefix)) {
823          args += [
824            "--export_attribute",
825            "COMPONENT_EXPORT(${invoker.component_macro_prefix}" +
826                "${bindings_configuration.component_macro_suffix})",
827            "--export_header",
828            "base/component_export.h",
829          ]
830        }
831
832        if (defined(bindings_configuration.for_blink) &&
833            bindings_configuration.for_blink) {
834          args += [ "--for_blink" ]
835          if (defined(invoker.export_class_attribute_blink)) {
836            args += [
837              "--export_attribute",
838              invoker.export_class_attribute_blink,
839              "--export_header",
840              invoker.export_header_blink,
841            ]
842          }
843        } else {
844          if (defined(invoker.export_class_attribute)) {
845            args += [
846              "--export_attribute",
847              invoker.export_class_attribute,
848              "--export_header",
849              invoker.export_header,
850            ]
851          }
852        }
853
854        if (!defined(invoker.use_once_callback) || invoker.use_once_callback) {
855          args += [ "--use_once_callback" ]
856        }
857
858        if (defined(invoker.support_lazy_serialization) &&
859            invoker.support_lazy_serialization) {
860          args += [ "--support_lazy_serialization" ]
861        }
862      }
863    }
864
865    action(type_mappings_target_name) {
866      inputs = _bindings_configuration_files + mojom_generator_sources +
867               jinja2_sources
868      outputs = [
869        type_mappings_path,
870      ]
871      script = "$mojom_generator_root/generate_type_mappings.py"
872      deps = []
873      args = [
874        "--output",
875        rebase_path(type_mappings_path, root_build_dir),
876      ]
877
878      foreach(d, all_deps) {
879        name = get_label_info(d, "label_no_toolchain")
880        toolchain = get_label_info(d, "toolchain")
881        dependency_output = "${name}${variant_suffix}__type_mappings"
882        dependency_target = "${dependency_output}(${toolchain})"
883        deps += [ dependency_target ]
884        dependency_output_dir =
885            get_label_info(dependency_output, "target_gen_dir")
886        dependency_name = get_label_info(dependency_output, "name")
887        dependency_path =
888            rebase_path("$dependency_output_dir/${dependency_name}",
889                        root_build_dir)
890        args += [
891          "--dependency",
892          dependency_path,
893        ]
894      }
895
896      if (enabled_sources != []) {
897        # TODO(sammc): Pass the typemap description in a file to avoid command
898        # line length limitations.
899        typemap_description = []
900        foreach(typemap, active_typemaps) {
901          _typemap_config = {
902          }
903          _typemap_config = typemap.config
904          typemap_description += [ "--start-typemap" ]
905          if (defined(_typemap_config.public_headers)) {
906            foreach(value, _typemap_config.public_headers) {
907              typemap_description += [ "public_headers=$value" ]
908            }
909          }
910          if (defined(_typemap_config.traits_headers)) {
911            foreach(value, _typemap_config.traits_headers) {
912              typemap_description += [ "traits_headers=$value" ]
913            }
914          }
915          foreach(value, _typemap_config.type_mappings) {
916            typemap_description += [ "type_mappings=$value" ]
917          }
918
919          # The typemap configuration files are not actually used as inputs here
920          # but this establishes a necessary build dependency to ensure that
921          # typemap changes force a rebuild of affected targets.
922          inputs += [ typemap.filename ]
923        }
924        args += typemap_description
925      }
926    }
927
928    if (defined(invoker.component_macro_prefix)) {
929      output_target_type = "component"
930    } else {
931      output_target_type = "source_set"
932    }
933
934    js_data_deps_target_name = target_name + "_js_data_deps"
935    not_needed([ "js_data_deps_target_name" ])
936
937    target("jumbo_" + output_target_type, "${target_name}${variant_suffix}") {
938      if (defined(bindings_configuration.for_blink) &&
939          bindings_configuration.for_blink &&
940          defined(invoker.visibility_blink)) {
941        visibility = invoker.visibility_blink
942      } else if (defined(invoker.visibility)) {
943        visibility = invoker.visibility
944      }
945      if (defined(invoker.testonly)) {
946        testonly = invoker.testonly
947      }
948      defines = []
949      if (defined(invoker.export_define)) {
950        defines += [ invoker.export_define ]
951      }
952      if (defined(invoker.export_define_blink)) {
953        defines += [ invoker.export_define_blink ]
954      }
955      if (enabled_sources != []) {
956        sources = process_file_template(enabled_sources, generator_cpp_outputs)
957      }
958      deps = [
959        ":$generator_cpp_message_ids_target_name",
960        "//mojo/public/cpp/bindings:struct_traits",
961        "//mojo/public/interfaces/bindings:bindings__generator",
962        "//mojo/public/interfaces/bindings:bindings_shared__generator",
963      ]
964      public_deps = [
965        ":$shared_cpp_library_target_name",
966        "//base",
967      ]
968      if (require_full_cpp_deps) {
969        public_deps += [ "//mojo/public/cpp/bindings" ]
970      } else {
971        public_deps += [ "//mojo/public/cpp/bindings:bindings_base" ]
972      }
973
974      if (enabled_sources != []) {
975        public_deps += [ ":$generator_target_name" ]
976      }
977      if (defined(invoker.component_macro_prefix)) {
978        output_name = "${invoker.component_output_prefix}${variant_suffix}"
979        defines += [ "IS_${invoker.component_macro_prefix}" +
980                     "${bindings_configuration.component_macro_suffix}_IMPL" ]
981      }
982      foreach(d, all_deps) {
983        # Resolve the name, so that a target //mojo/something becomes
984        # //mojo/something:something and we can append variant_suffix to
985        # get the cpp dependency name.
986        full_name = get_label_info("$d", "label_no_toolchain")
987        public_deps += [ "${full_name}${variant_suffix}" ]
988      }
989      if (defined(bindings_configuration.for_blink) &&
990          bindings_configuration.for_blink) {
991        if (defined(invoker.overridden_deps_blink)) {
992          foreach(d, invoker.overridden_deps_blink) {
993            # Resolve the name, so that a target //mojo/something becomes
994            # //mojo/something:something and we can append variant_suffix
995            # to get the cpp dependency name.
996            full_name = get_label_info("$d", "label_no_toolchain")
997            public_deps -= [ "${full_name}${variant_suffix}" ]
998          }
999          public_deps += invoker.component_deps_blink
1000        }
1001        if (defined(invoker.check_includes_blink)) {
1002          check_includes = invoker.check_includes_blink
1003        }
1004      } else {
1005        if (defined(invoker.check_includes_blink)) {
1006          not_needed(invoker, [ "check_includes_blink" ])
1007        }
1008        if (defined(invoker.overridden_deps)) {
1009          foreach(d, invoker.overridden_deps) {
1010            # Resolve the name, so that a target //mojo/something becomes
1011            # //mojo/something:something and we can append variant_suffix
1012            # to get the cpp dependency name.
1013            full_name = get_label_info("$d", "label_no_toolchain")
1014            public_deps -= [ "${full_name}${variant_suffix}" ]
1015          }
1016          public_deps += invoker.component_deps
1017        }
1018      }
1019      foreach(typemap, active_typemaps) {
1020        _typemap_config = {
1021        }
1022        _typemap_config = typemap.config
1023        if (defined(_typemap_config.sources)) {
1024          sources += _typemap_config.sources
1025        }
1026        if (defined(_typemap_config.public_deps)) {
1027          public_deps += _typemap_config.public_deps
1028        }
1029        if (defined(_typemap_config.deps)) {
1030          deps += _typemap_config.deps
1031        }
1032      }
1033      if (defined(invoker.export_header)) {
1034        sources += [ "//" + invoker.export_header ]
1035      }
1036      if (defined(bindings_configuration.for_blink) &&
1037          bindings_configuration.for_blink) {
1038        public_deps += [ "//mojo/public/cpp/bindings:wtf_support" ]
1039      }
1040
1041      if (enable_ipc_fuzzer) {
1042        # Generate JS bindings by default if IPC fuzzer is enabled.
1043        public_deps += [ ":$js_data_deps_target_name" ]
1044      }
1045    }
1046
1047    if (!cpp_only && is_android) {
1048      import("//build/config/android/rules.gni")
1049
1050      java_generator_target_name = target_name + "_java__generator"
1051      if (enabled_sources != []) {
1052        generator_java_outputs =
1053            [ "{{source_gen_dir}}/{{source_name_part}}.mojom.srcjar" ]
1054        action(java_generator_target_name) {
1055          script = mojom_generator_script
1056          inputs = mojom_generator_sources + jinja2_sources
1057          sources = enabled_sources
1058          deps = [
1059                   ":$parsed_target_name",
1060                   ":$type_mappings_target_name",
1061                   "//mojo/public/tools/bindings:precompile_templates",
1062                 ] + verify_deps_target_names
1063          outputs = []
1064          args = common_generator_args
1065          filelist = []
1066          foreach(source, invoker.sources) {
1067            filelist += [ rebase_path("$source", root_build_dir) ]
1068            outputs += [ "$target_gen_dir/$source.srcjar" ]
1069          }
1070
1071          response_file_contents = filelist
1072
1073          args += [
1074            "--filelist={{response_file_name}}",
1075            "-g",
1076            "java",
1077          ]
1078
1079          if (!defined(invoker.scramble_message_ids) ||
1080              invoker.scramble_message_ids) {
1081            inputs += message_scrambling_inputs
1082            args += message_scrambling_args
1083          }
1084        }
1085      } else {
1086        group(java_generator_target_name) {
1087        }
1088      }
1089
1090      java_srcjar_target_name = target_name + "_java_sources"
1091      action(java_srcjar_target_name) {
1092        script = "//mojo/public/tools/gn/zip.py"
1093        inputs = []
1094        if (enabled_sources != []) {
1095          inputs =
1096              process_file_template(enabled_sources, generator_java_outputs)
1097        }
1098        output = "$target_gen_dir/$target_name.srcjar"
1099        outputs = [
1100          output,
1101        ]
1102        rebase_inputs = rebase_path(inputs, root_build_dir)
1103        rebase_output = rebase_path(output, root_build_dir)
1104        args = [
1105          "--zip-inputs=$rebase_inputs",
1106          "--output=$rebase_output",
1107        ]
1108        deps = []
1109        if (enabled_sources != []) {
1110          deps = [
1111            ":$java_generator_target_name",
1112          ]
1113        }
1114      }
1115
1116      java_target_name = target_name + "_java"
1117      android_library(java_target_name) {
1118        deps = [
1119          "//base:base_java",
1120          "//mojo/public/java:bindings_java",
1121          "//mojo/public/java:system_java",
1122        ]
1123
1124        # Disable warnings/checks on these generated files.
1125        chromium_code = false
1126
1127        foreach(d, all_deps) {
1128          # Resolve the name, so that a target //mojo/something becomes
1129          # //mojo/something:something and we can append "_java" to get the java
1130          # dependency name.
1131          full_name = get_label_info(d, "label_no_toolchain")
1132          deps += [ "${full_name}_java" ]
1133        }
1134
1135        srcjar_deps = [ ":$java_srcjar_target_name" ]
1136      }
1137    }
1138  }
1139
1140  if (enable_ipc_fuzzer || !defined(invoker.cpp_only) || !invoker.cpp_only) {
1141    if (defined(invoker.sources)) {
1142      generator_js_target_name = "${target_name}_js__generator"
1143      generator_js_outputs = [
1144        "{{source_gen_dir}}/{{source_name_part}}.mojom.js",
1145        "{{source_gen_dir}}/{{source_name_part}}.mojom.externs.js",
1146      ]
1147      action(generator_js_target_name) {
1148        script = mojom_generator_script
1149        inputs = mojom_generator_sources + jinja2_sources
1150        sources = []
1151        if (defined(invoker.sources)) {
1152          sources += invoker.sources
1153        }
1154        deps = [
1155                 ":$parsed_target_name",
1156                 "//mojo/public/tools/bindings:precompile_templates",
1157               ] + verify_deps_target_names
1158        outputs = []
1159        args = common_generator_args
1160        filelist = []
1161        foreach(source, invoker.sources) {
1162          filelist += [ rebase_path("$source", root_build_dir) ]
1163          outputs += [
1164            "$target_gen_dir/$source.js",
1165            "$target_gen_dir/$source.externs.js",
1166          ]
1167        }
1168
1169        response_file_contents = filelist
1170
1171        args += [
1172          "--filelist={{response_file_name}}",
1173          "-g",
1174          "javascript",
1175        ]
1176
1177        if (!defined(invoker.scramble_message_ids) ||
1178            invoker.scramble_message_ids) {
1179          inputs += message_scrambling_inputs
1180          args += message_scrambling_args
1181        }
1182
1183        if (enable_ipc_fuzzer) {
1184          args += [ "--generate_fuzzing" ]
1185        }
1186      }
1187    }
1188
1189    js_target_name = target_name + "_js"
1190    group(js_target_name) {
1191      public_deps = []
1192      if (defined(invoker.sources)) {
1193        public_deps += [ ":$generator_js_target_name" ]
1194      }
1195
1196      foreach(d, all_deps) {
1197        full_name = get_label_info(d, "label_no_toolchain")
1198        public_deps += [ "${full_name}_js" ]
1199      }
1200    }
1201
1202    group(js_data_deps_target_name) {
1203      deps = []
1204      if (defined(invoker.sources)) {
1205        data = process_file_template(invoker.sources, generator_js_outputs)
1206        deps += [ ":$generator_js_target_name" ]
1207      }
1208
1209      data_deps = []
1210      foreach(d, all_deps) {
1211        full_name = get_label_info(d, "label_no_toolchain")
1212        data_deps += [ "${full_name}_js_data_deps" ]
1213      }
1214    }
1215  }
1216}
1217
1218# A helper for the mojom() template above when component libraries are desired
1219# for generated C++ bindings units. Supports all the same arguments as mojom()
1220# except for the optional |component_output_prefix| and |component_macro_prefix|
1221# arguments. These are instead shortened to |output_prefix| and |macro_prefix|
1222# and are *required*.
1223template("mojom_component") {
1224  assert(defined(invoker.output_prefix) && defined(invoker.macro_prefix))
1225
1226  mojom(target_name) {
1227    forward_variables_from(invoker,
1228                           "*",
1229                           [
1230                             "output_prefix",
1231                             "macro_prefix",
1232                           ])
1233    component_output_prefix = invoker.output_prefix
1234    component_macro_prefix = invoker.macro_prefix
1235  }
1236}
1237