# 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", # ] # } import("//build/config/sanitizers/sanitizers.gni") 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. 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" ] script = "//tools/protoc_wrapper/protoc_wrapper.py" sources = proto_sources outputs = get_path_info(protogens, "abspath") args = protos 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), "--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) ] } } # 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 (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" ] 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", ] } 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", ] } } } 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 } } }