| # Copyright 2014 The Chromium Authors |
| # 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. |
| # |
| # generate_javascript (optional, default false) |
| # Generate Javascript protobuf stubs. |
| # |
| # generate_library (optional, default true) |
| # Generate a "static_library" target for linking with the generated code. |
| # |
| # generate_py_runtime (optional, default false) |
| # Generates a "_py_runtime"-suffixed target for test targets that need the |
| # Python stubs available at runtime. |
| # |
| # 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) |
| # DEPRECATED: use proto_deps or link_deps instead (crbug.com/938011). |
| # Additional dependencies. |
| # |
| # link_deps (optional) |
| # Additional dependencies linked to library. |
| # |
| # proto_deps (optional) |
| # Additional dependencies required before running protoc. |
| # e.g. proto file generating action. |
| # |
| # 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. |
| # WARNING: This circumvents proto checkdeps, and should only be used when |
| # needed, typically when proto files cannot cleanly import through |
| # absolute paths, such as for third_party or generated .proto files. |
| # http://crbug.com/691451 tracks fixing this. |
| # |
| # Parameters for compiling the generated code: |
| # |
| # force_source_set (Default=false) |
| # When set true the generated code will be compiled as a source set. |
| # This can be useful if you need to export the generated symbols from a |
| # shared library. You should use this carefully, as you probably only |
| # want this if your dependencies are *always* shared libraries. Most |
| # of the time, you probably want `component_build_force_source_set` |
| # instead (see the next option). |
| # 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. |
| # |
| # remove_configs (optional) |
| # A list of config labels that will be removed from the configs apllying |
| # to the source set. |
| # |
| # propagate_imports_configs (optional) |
| # A boolean value (defaults to true) that specifies whether the config |
| # generated for the library's import directories will be propagated to |
| # dependents as one of the library target's public_configs. See |
| # crbug.com/1043279#c11 and crbug.com/gn/142 for why this option exists. |
| # WARNING: If set to false, the embedder target is responsible for |
| # propagating a suitable config, so that any dependent headers can resolve |
| # includes generated by proto imports. |
| # |
| # Example: |
| # proto_library("mylib") { |
| # sources = [ |
| # "foo.proto", |
| # ] |
| # } |
| |
| import("//build/config/sanitizers/sanitizers.gni") |
| import("//build/toolchain/kythe.gni") |
| |
| declare_args() { |
| # Allows subprojects to omit javascript dependencies (e.g.) closure_compiler |
| # and google-closure-library. |
| enable_js_protobuf = true |
| } |
| |
| if (enable_js_protobuf) { |
| import("//third_party/closure_compiler/compile_js.gni") |
| } |
| |
| if (host_os == "win") { |
| _host_executable_suffix = ".exe" |
| } else { |
| _host_executable_suffix = "" |
| } |
| |
| _protoc_label = "//third_party/protobuf:protoc($host_toolchain)" |
| _protoc_path = get_label_info(_protoc_label, "root_out_dir") + "/protoc" + |
| _host_executable_suffix |
| |
| template("proto_library") { |
| assert(defined(invoker.sources), "Need sources for proto_library") |
| proto_sources = invoker.sources |
| |
| 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.generate_javascript)) { |
| generate_javascript = invoker.generate_javascript |
| } else { |
| generate_javascript = false |
| } |
| |
| if (defined(invoker.generate_descriptor)) { |
| generate_descriptor = invoker.generate_descriptor |
| } else { |
| generate_descriptor = "" |
| } |
| |
| if (defined(invoker.generate_py_runtime)) { |
| generate_py_runtime = invoker.generate_py_runtime |
| } else { |
| generate_py_runtime = false |
| } |
| if (generate_py_runtime) { |
| generate_python = true |
| } |
| |
| # exclude_imports is only used for generating the descriptor. Therefore, the |
| # check needs to be here to avoid complaints from GN about the unused |
| # variable. |
| if (generate_descriptor != "") { |
| if (defined(invoker.exclude_imports)) { |
| exclude_imports = invoker.exclude_imports |
| } else { |
| exclude_imports = false |
| } |
| } |
| |
| 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) |
| } |
| if (generate_javascript) { |
| js_out_dir = "$root_out_dir/jsproto/" + proto_out_dir |
| rel_js_out_dir = rebase_path(js_out_dir, root_build_dir) |
| } |
| if (generate_descriptor != "") { |
| descriptor_out = |
| "$root_gen_dir/" + proto_out_dir + "/" + generate_descriptor |
| rel_descriptor_out = rebase_path(descriptor_out, root_build_dir) |
| } |
| |
| protos = rebase_path(invoker.sources, proto_in_dir) |
| protogens = [] |
| protogens_py = [] |
| protogens_cc = [] |
| protogens_js = [] |
| |
| # Whether source code bindings should be generated. |
| generate_sources = generate_cc || generate_python || generate_with_plugin || |
| generate_javascript |
| |
| # Whether library should be generated. |
| # Library is not needed when proto_library is used to generate binary descriptor, in which case |
| # corresponding library target should be omitted entirely. |
| if (defined(invoker.generate_library)) { |
| generate_library = invoker.generate_library |
| } else { |
| generate_library = generate_sources |
| } |
| |
| # List output files. |
| if (generate_sources) { |
| 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 += [ |
| "$cc_out_dir/$proto_path.pb.h", |
| "$cc_out_dir/$proto_path.pb.cc", |
| ] |
| } |
| if (generate_python) { |
| protogens_py += [ "$py_out_dir/${proto_path}_pb2.py" ] |
| } |
| if (generate_with_plugin) { |
| foreach(suffix, generator_plugin_suffixes) { |
| protogens_cc += [ "$cc_out_dir/${proto_path}${suffix}" ] |
| } |
| } |
| if (generate_javascript) { |
| protogens_js += [ "$js_out_dir/${proto_path}.js" ] |
| } |
| } |
| } |
| |
| # If descriptor needs to be generated, it should be added to list of outputs once. |
| if (generate_descriptor != "") { |
| protogens += [ descriptor_out ] |
| } |
| |
| action_name = "${target_name}_gen" |
| source_set_name = target_name |
| javascript_name = "${target_name}_js" |
| py_runtime_name = "${target_name}_py_runtime" |
| |
| # Generate protobuf stubs. |
| action(action_name) { |
| visibility = [ |
| ":$javascript_name", |
| ":$py_runtime_name", |
| ":$source_set_name", |
| ] |
| script = "//tools/protoc_wrapper/protoc_wrapper.py" |
| args = protos |
| |
| sources = proto_sources |
| outputs = |
| get_path_info(protogens + protogens_cc + protogens_js + protogens_py, |
| "abspath") |
| |
| if (defined(invoker.testonly)) { |
| testonly = invoker.testonly |
| } |
| |
| 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), |
| "--proto-in-dir", |
| rebase_path(proto_in_dir, root_build_dir), |
| ] |
| |
| if (generate_cc) { |
| args += [ |
| "--cc-out-dir", |
| rel_cc_out_dir, |
| ] |
| if (enable_kythe_annotations) { |
| args += [ "--enable-kythe-annotation" ] |
| } |
| 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_javascript) { |
| args += [ |
| "--js-out-dir", |
| rel_js_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 (generate_descriptor != "") { |
| depfile = |
| "$root_gen_dir/" + proto_out_dir + "/" + generate_descriptor + ".d" |
| rel_depfile = rebase_path(depfile, root_build_dir) |
| |
| if (exclude_imports) { |
| args += [ "--exclude-imports" ] |
| } |
| |
| args += [ |
| "--descriptor-set-out", |
| rel_descriptor_out, |
| "--descriptor-set-dependency-file", |
| rel_depfile, |
| ] |
| } |
| |
| if (defined(invoker.import_dirs)) { |
| foreach(path, invoker.import_dirs) { |
| args += [ "--import-dir=" + rebase_path(path, root_build_dir) ] |
| } |
| } |
| |
| # 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 ] |
| } |
| } |
| |
| # The deps may have steps that have to run before running protoc. |
| if (defined(invoker.proto_deps)) { |
| deps += invoker.proto_deps |
| } |
| if (defined(invoker.deps)) { |
| deps += invoker.deps |
| } |
| } |
| |
| if (!generate_library) { |
| # If only descriptor is required, just generate a group wrapper for action output. |
| link_target_type = "group" |
| } else if ((defined(invoker.force_source_set) && invoker.force_source_set) || |
| (defined(invoker.component_build_force_source_set) && |
| invoker.component_build_force_source_set && is_component_build)) { |
| # Option to disable building a library in 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. |
| config_name = "${target_name}_config" |
| config(config_name) { |
| include_dirs = [] |
| if (has_nested_dirs && generate_cc) { |
| include_dirs += [ cc_out_dir ] |
| } |
| if (defined(invoker.import_dirs)) { |
| foreach(path, invoker.import_dirs) { |
| include_dirs += [ "$root_gen_dir/" + rebase_path(path, "//") ] |
| } |
| } |
| } |
| |
| # Build generated javascript stubs. |
| if (generate_javascript) { |
| js_library(javascript_name) { |
| forward_variables_from(invoker, |
| [ |
| "testonly", |
| "visibility", |
| ]) |
| |
| sources = protogens_js |
| |
| deps = [ "//third_party/protobuf:js_proto" ] |
| |
| extra_deps = [ ":$action_name" ] |
| } |
| } |
| |
| # Build generated protobuf stubs as libary or source set. |
| target(link_target_type, target_name) { |
| forward_variables_from(invoker, |
| [ |
| "defines", |
| "testonly", |
| "visibility", |
| ]) |
| |
| if (generate_library) { |
| sources = get_path_info(protogens_cc, "abspath") |
| |
| if (defined(invoker.remove_configs)) { |
| configs -= invoker.remove_configs |
| } |
| |
| if (defined(invoker.extra_configs)) { |
| configs += invoker.extra_configs |
| } |
| |
| # Remove Sanitizer and coverage instrumentation for a performance boost when |
| # fuzzing, since the only fuzzers that use protobuf are libprotobuf-mutator |
| # based fuzzers, and they don't actually target protobuf code. |
| configs -= not_fuzzed_remove_configs |
| configs += [ "//build/config/sanitizers:not_fuzzed" ] |
| } |
| |
| public_configs = [ |
| "//third_party/protobuf:using_proto", |
| "//third_party/protobuf:allow_deprecated_proto_fields", |
| ] |
| public_deps = [] |
| |
| if (generate_cc || generate_with_plugin) { |
| # Not necessary if all protos are located in the same directory. |
| if (has_nested_dirs || defined(invoker.import_dirs)) { |
| # By default, propagate the config for |include_dirs| to dependent |
| # targets, so that public imports can be resolved to corresponding |
| # header files. In some cases, the embedder target handles include |
| # directory propagation itself, e.g. via a common config. |
| propagate_imports_configs = |
| !defined(invoker.propagate_imports_configs) || |
| invoker.propagate_imports_configs |
| if (propagate_imports_configs) { |
| public_configs += [ ":$config_name" ] |
| } else { |
| # Embedder handles include directory propagation to dependents. |
| 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" ] |
| } |
| |
| if (is_win) { |
| cflags = [ |
| # disable: C4125 decimal digit terminates octal escape sequence |
| # Protoc generates such sequences frequently, there's no obvious |
| # superior replacement behavior. Since this code is autogenerated, |
| # the warning would never catch a legitimate bug. |
| "/wd4125", |
| ] |
| } |
| } |
| } |
| |
| public_deps += [ ":$action_name" ] |
| deps = [] |
| |
| # 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 |
| } |
| if (defined(invoker.link_deps)) { |
| deps += invoker.link_deps |
| } |
| } |
| |
| if (generate_py_runtime) { |
| group(py_runtime_name) { |
| data = protogens_py |
| deps = [ |
| ":$action_name", |
| "//third_party/protobuf:py_proto_runtime", |
| ] |
| } |
| } |
| } |
| |
| # Convert a protocol buffer between text and binary formats. |
| # This can be used to run protoc with the --encode or --decode options. |
| # Parameters: |
| # |
| # sources: list of string |
| # The sources to loop over and run protoc on |
| # |
| # inputs: list of string |
| # The file dependencies for the action. This should be the list of .proto |
| # files involved in the conversion operation. |
| # |
| # output_pattern: string |
| # A path pattern with source expansion variables (like source_name_part) |
| # for where the result of conversion should be placed. |
| # |
| # deps: (optional) list of label |
| # Additional dependencies for the target. |
| # |
| # args: list of string |
| # Arguments to pass to the protoc tool. This could include -I for include |
| # paths, as well as the name of the proto file. |
| # |
| # |
| # Example to convert a .textproto to a .binarybp: |
| # protoc_convert("convert_foo") { |
| # sources = [ |
| # "test/data/example1.textproto", |
| # "test/data/example2.textproto", |
| # ] |
| # inputs = [ |
| # "//component/core/foo.proto", |
| # ] |
| # output_pattern = "$target_gen_dir/foo_data/{{source_name_part}}.binarypb" |
| # args = [ |
| # "--encode=foo.FooMessage", |
| # "-I", |
| # rebase_path("//"), |
| # "component/core/foo.proto", |
| # ] |
| # } |
| template("protoc_convert") { |
| action_foreach(target_name) { |
| script = "//tools/protoc_wrapper/protoc_convert.py" |
| |
| sources = invoker.sources |
| |
| inputs = invoker.inputs |
| |
| deps = [ _protoc_label ] |
| if (defined(invoker.deps)) { |
| deps += invoker.deps |
| } |
| |
| if (defined(invoker.testonly)) { |
| testonly = invoker.testonly |
| } |
| |
| outputs = [ invoker.output_pattern ] |
| |
| args = [ |
| "--protoc", |
| "./" + rebase_path(_protoc_path, root_build_dir), |
| "--infile", |
| "{{source}}", |
| "--outfile", |
| rebase_path(invoker.output_pattern), |
| ] + invoker.args |
| } |
| } |