| # 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. |
| |
| # Compile a protocol buffer. |
| # |
| # Protobuf parameters: |
| # |
| # proto_in_dir (optional) |
| # Specifies the path relative to the current BUILD.gn file where |
| # proto files are located and the directory structure of |
| # this proto library starts. |
| # |
| # This option can be calculated automatically but it will raise an |
| # assertion error if any nested directories are found. |
| # |
| # proto_out_dir (optional) |
| # Specifies the path suffix that output files are generated under. |
| # This path will be appended to |root_gen_dir|, but for python stubs |
| # it will be appended to |root_build_dir|/pyproto. |
| # |
| # generate_python (optional, default true) |
| # Generate Python protobuf stubs. |
| # |
| # generate_cc (optional, default true) |
| # Generate C++ protobuf stubs. |
| # |
| # cc_generator_options (optional) |
| # List of extra flags passed to the protocol compiler. If you need to |
| # add an EXPORT macro to a protobuf's C++ header, set the |
| # 'cc_generator_options' variable with the value: |
| # 'dllexport_decl=FOO_EXPORT:' (note trailing colon). |
| # |
| # It is likely you also need to #include a file for the above EXPORT |
| # macro to work (see cc_include) and set |
| # component_build_force_source_set = true. |
| # |
| # cc_include (optional) |
| # String listing an extra include that should be passed. |
| # Example: cc_include = "foo/bar.h" |
| # |
| # generator_plugin_label (optional) |
| # GN label for plugin executable which generates custom cc stubs. |
| # Don't specify a toolchain, host toolchain is assumed. |
| # |
| # generator_plugin_script (optional) |
| # Path to plugin script. Mutually exclusive with |generator_plugin_label|. |
| # |
| # generator_plugin_script_deps (optional) |
| # List of additional files required for generator plugin script. |
| # |
| # generator_plugin_suffix[es] (required if using a plugin) |
| # Suffix (before extension) for generated .cc and .h files |
| # or list of suffixes for all files (with extensions). |
| # |
| # generator_plugin_options (optional) |
| # Extra flags passed to the plugin. See cc_generator_options. |
| # |
| # deps (optional) |
| # Additional dependencies. |
| # |
| # use_protobuf_full (optional) |
| # If adding protobuf library would be required, adds protobuf_full to deps |
| # instead of protobuf_lite. |
| # |
| # import_dirs (optional) |
| # A list of extra import directories to be passed to protoc compiler. The |
| # default case is just proto_in_dir. |
| # WARNING: This options should not be used in Chrome code until |
| # http://crbug.com/691451 is resolved. |
| # |
| # Parameters for compiling the generated code: |
| # |
| # component_build_force_source_set (Default=false) |
| # When set true the generated code will be compiled as a source set in |
| # the component build. This does not affect static builds. If you are |
| # exporting symbols from a component, this is required to prevent those |
| # symbols from being stripped. If you're not using dllexports in |
| # cc_generator_options, it's usually best to leave this false. |
| # |
| # defines (optional) |
| # Defines to supply to the source set that compiles the generated source |
| # code. |
| # |
| # extra_configs (optional) |
| # A list of config labels that will be appended to the configs applying |
| # to the source set. |
| # |
| # Example: |
| # proto_library("mylib") { |
| # sources = [ |
| # "foo.proto", |
| # ] |
| # } |
| |
| template("proto_library") { |
| assert(defined(invoker.sources), "Need sources for proto_library") |
| proto_sources = invoker.sources |
| |
| # Don't apply OS-specific sources filtering to the assignments later on. |
| # Platform files should have gotten filtered out in the sources assignment |
| # when this template was invoked. If they weren't, it was on purpose and |
| # this template shouldn't re-apply the filter. |
| if (!is_starboard) { |
| set_sources_assignment_filter([]) |
| } |
| |
| if (host_os == "win") { |
| host_executable_suffix = ".exe" |
| } else { |
| host_executable_suffix = "" |
| } |
| |
| if (defined(invoker.generate_cc)) { |
| generate_cc = invoker.generate_cc |
| } else { |
| generate_cc = true |
| } |
| |
| if (defined(invoker.generate_python)) { |
| generate_python = invoker.generate_python |
| } else { |
| generate_python = true |
| } |
| |
| if (defined(invoker.generator_plugin_label)) { |
| # Straightforward way to get the name of executable doesn't work because |
| # |root_out_dir| and |root_build_dir| may differ in cross-compilation and |
| # also Windows executables have .exe at the end. |
| |
| plugin_host_label = invoker.generator_plugin_label + "($host_toolchain)" |
| plugin_path = |
| get_label_info(plugin_host_label, "root_out_dir") + "/" + |
| get_label_info(plugin_host_label, "name") + host_executable_suffix |
| generate_with_plugin = true |
| } else if (defined(invoker.generator_plugin_script)) { |
| plugin_path = invoker.generator_plugin_script |
| generate_with_plugin = true |
| } else { |
| generate_with_plugin = false |
| } |
| |
| if (generate_with_plugin) { |
| if (defined(invoker.generator_plugin_suffix)) { |
| generator_plugin_suffixes = [ |
| "${invoker.generator_plugin_suffix}.h", |
| "${invoker.generator_plugin_suffix}.cc", |
| ] |
| } else { |
| generator_plugin_suffixes = invoker.generator_plugin_suffixes |
| } |
| } |
| |
| if (defined(invoker.proto_in_dir)) { |
| proto_in_dir = invoker.proto_in_dir |
| has_nested_dirs = false |
| foreach(proto_source, proto_sources) { |
| if (get_path_info(proto_source, "dir") != proto_in_dir) { |
| has_nested_dirs = true |
| } |
| } |
| } else { |
| proto_in_dir = get_path_info(proto_sources[0], "dir") |
| has_nested_dirs = false |
| |
| # Sanity check, |proto_in_dir| should be defined to allow sub-directories. |
| foreach(proto_source, proto_sources) { |
| assert(get_path_info(proto_source, "dir") == proto_in_dir, |
| "Please define |proto_in_dir| to allow nested directories.") |
| } |
| } |
| |
| # Avoid absolute path because of the assumption that |proto_in_dir| is |
| # relative to the directory of current BUILD.gn file. |
| proto_in_dir = rebase_path(proto_in_dir, ".") |
| |
| if (defined(invoker.proto_out_dir)) { |
| proto_out_dir = invoker.proto_out_dir |
| } else { |
| # Absolute path to the directory of current BUILD.gn file excluding "//". |
| proto_out_dir = rebase_path(".", "//") |
| if (proto_in_dir != ".") { |
| proto_out_dir += "/$proto_in_dir" |
| } |
| } |
| |
| # We need both absolute path to use in GN statements and a relative one |
| # to pass to external script. |
| if (generate_cc || generate_with_plugin) { |
| cc_out_dir = "$root_gen_dir/" + proto_out_dir |
| rel_cc_out_dir = rebase_path(cc_out_dir, root_build_dir) |
| } |
| if (generate_python) { |
| py_out_dir = "$root_out_dir/pyproto/" + proto_out_dir |
| rel_py_out_dir = rebase_path(py_out_dir, root_build_dir) |
| } |
| |
| protos = rebase_path(invoker.sources, proto_in_dir) |
| protogens = [] |
| |
| # List output files. |
| foreach(proto, protos) { |
| proto_dir = get_path_info(proto, "dir") |
| proto_name = get_path_info(proto, "name") |
| proto_path = proto_dir + "/" + proto_name |
| |
| if (generate_cc) { |
| protogens += [ |
| "$cc_out_dir/$proto_path.pb.h", |
| "$cc_out_dir/$proto_path.pb.cc", |
| ] |
| } |
| if (generate_python) { |
| protogens += [ "$py_out_dir/${proto_path}_pb2.py" ] |
| } |
| if (generate_with_plugin) { |
| foreach(suffix, generator_plugin_suffixes) { |
| protogens += [ "$cc_out_dir/${proto_path}${suffix}" ] |
| } |
| } |
| } |
| |
| action_name = "${target_name}_gen" |
| source_set_name = target_name |
| |
| # Generate protobuf stubs. |
| action(action_name) { |
| visibility = [ ":$source_set_name" ] |
| if (is_starboard) { |
| script = "//tools/protoc_wrapper/gn_protoc_wrapper.py" |
| } else { |
| script = "//tools/protoc_wrapper/protoc_wrapper.py" |
| } |
| sources = proto_sources |
| outputs = get_path_info(protogens, "abspath") |
| args = protos |
| |
| if (is_starboard) { |
| # TODO(b/207292694): Build protoc from source. |
| if (is_mac) { |
| protoc_path = "//tools/protoc_mac" |
| } else { |
| protoc_path = "//tools/protoc" |
| } |
| args += [ |
| "--protoc", |
| rebase_path(protoc_path, root_build_dir) + host_executable_suffix, |
| ] |
| } else { |
| protoc_label = "//third_party/protobuf:protoc($host_toolchain)" |
| protoc_path = get_label_info(protoc_label, "root_out_dir") + "/protoc" + |
| host_executable_suffix |
| args += [ |
| # Wrapper should never pick a system protoc. |
| # Path should be rebased because |root_build_dir| for current toolchain |
| # may be different from |root_out_dir| of protoc built on host toolchain. |
| "--protoc", |
| "./" + rebase_path(protoc_path, root_build_dir), |
| ] |
| } |
| |
| args += [ |
| "--proto-in-dir", |
| rebase_path(proto_in_dir, root_build_dir), |
| ] |
| |
| if (generate_cc) { |
| args += [ |
| "--cc-out-dir", |
| rel_cc_out_dir, |
| ] |
| if (defined(invoker.cc_generator_options)) { |
| args += [ |
| "--cc-options", |
| invoker.cc_generator_options, |
| ] |
| } |
| if (defined(invoker.cc_include)) { |
| args += [ |
| "--include", |
| invoker.cc_include, |
| ] |
| } |
| } |
| |
| if (generate_python) { |
| args += [ |
| "--py-out-dir", |
| rel_py_out_dir, |
| ] |
| } |
| |
| if (generate_with_plugin) { |
| args += [ |
| "--plugin", |
| rebase_path(plugin_path, root_build_dir), |
| "--plugin-out-dir", |
| rel_cc_out_dir, |
| ] |
| if (defined(invoker.generator_plugin_options)) { |
| args += [ |
| "--plugin-options", |
| invoker.generator_plugin_options, |
| ] |
| } |
| } |
| |
| if (defined(invoker.import_dirs)) { |
| foreach(path, invoker.import_dirs) { |
| args += ["--import-dir=" + rebase_path(path, root_build_dir)] |
| } |
| } |
| |
| if (is_starboard) { |
| inputs = [] |
| deps = [] |
| } else { |
| # System protoc is not used so it's necessary to build a chromium one. |
| inputs = [ |
| protoc_path, |
| ] |
| deps = [ |
| protoc_label, |
| ] |
| } |
| |
| if (generate_with_plugin) { |
| inputs += [ plugin_path ] |
| if (defined(invoker.generator_plugin_script_deps)) { |
| # Additional scripts for plugin. |
| inputs += invoker.generator_plugin_script_deps |
| } |
| if (defined(plugin_host_label)) { |
| # Action depends on native generator plugin but for host toolchain only. |
| deps += [ plugin_host_label ] |
| } |
| } |
| |
| if (defined(invoker.deps)) { |
| # The deps may have steps that have to run before running protoc. |
| deps += invoker.deps |
| } |
| } |
| |
| # Option to disable building a library in component build. |
| if (defined(invoker.component_build_force_source_set) && |
| invoker.component_build_force_source_set && is_component_build) { |
| link_target_type = "source_set" |
| } else { |
| link_target_type = "static_library" |
| } |
| |
| # Generated files may include other generated headers. These includes always |
| # use relative paths starting at |cc_out_dir|. |
| # However there is no necessity to add an additional directory, if all protos |
| # are located in the same directory which is in the search path by default. |
| if (has_nested_dirs) { |
| config_name = "${target_name}_config" |
| config(config_name) { |
| include_dirs = [ cc_out_dir ] |
| } |
| } |
| |
| # Build generated protobuf stubs as libary or source set. |
| target(link_target_type, target_name) { |
| forward_variables_from(invoker, |
| [ |
| "defines", |
| "testonly", |
| "visibility", |
| ]) |
| |
| sources = get_target_outputs(":$action_name") |
| |
| if (generate_python) { |
| sources -= [ get_path_info("$py_out_dir/${proto_path}_pb2.py", "abspath") ] |
| } |
| |
| if (defined(invoker.extra_configs)) { |
| configs += invoker.extra_configs |
| } |
| |
| public_configs = [ "//third_party/protobuf:using_proto" ] |
| |
| if (generate_cc || generate_with_plugin) { |
| # Not necessary if all protos are located in the same directory. |
| if (has_nested_dirs) { |
| # It's not enough to set |include_dirs| for target since public imports |
| # expose corresponding includes to header files as well. |
| public_configs += [ ":$config_name" ] |
| } |
| |
| # If using built-in cc generator, the resulting headers reference headers |
| # within protobuf_lite. Hence, dependencies require those headers too. |
| # If using generator plugin, extra deps should be resolved by the invoker. |
| if (generate_cc) { |
| if (defined(invoker.use_protobuf_full) && |
| invoker.use_protobuf_full == true) { |
| public_deps = [ |
| "//third_party/protobuf:protobuf_full", |
| ] |
| } else { |
| public_deps = [ |
| "//third_party/protobuf:protobuf_lite", |
| ] |
| } |
| } |
| } |
| |
| deps = [ |
| ":$action_name", |
| ] |
| |
| # This will link any libraries in the deps (the use of invoker.deps in the |
| # action won't link it). |
| if (defined(invoker.deps)) { |
| deps += invoker.deps |
| } |
| } |
| } |