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
5# Compile a protocol buffer.
6#
7# Protobuf parameters:
8#
9#   proto_out_dir (optional)
10#       Specifies the path suffix that output files are generated under. This
11#       path will be appended to the root_gen_dir.
12#
13#       Targets that depend on the proto target will be able to include the
14#       resulting proto headers with an include like:
15#         #include "dir/for/my_proto_lib/foo.pb.h"
16#       If undefined, this defaults to matching the input directory for each
17#       .proto file (you should almost always use the default mode).
18#
19#   cc_generator_options (optional)
20#       List of extra flags passed to the protocol compiler.  If you need to
21#       add an EXPORT macro to a protobuf's C++ header, set the
22#       'cc_generator_options' variable with the value:
23#       'dllexport_decl=FOO_EXPORT:' (note trailing colon).
24#
25#       It is likely you also need to #include a file for the above EXPORT
26#       macro to work. See cc_include.
27#
28#   cc_include (optional)
29#       String listing an extra include that should be passed.
30#       Example: cc_include = "foo/bar.h"
31#
32#   deps (optional)
33#       Additional dependencies.
34#
35# Parameters for compiling the generated code:
36#
37#   defines (optional)
38#       Defines to supply to the source set that compiles the generated source
39#       code.
40#
41#   extra_configs (optional)
42#       A list of config labels that will be appended to the configs applying
43#       to the source set.
44#
45# Example:
46#  proto_library("mylib") {
47#    sources = [
48#      "foo.proto",
49#    ]
50#  }
51
52template("proto_library") {
53  assert(defined(invoker.sources), "Need sources for proto_library")
54
55  action_name = "${target_name}_gen"
56  source_set_name = target_name
57  action_foreach(action_name) {
58    visibility = [ ":$source_set_name" ]
59
60    script = "//tools/protoc_wrapper/protoc_wrapper.py"
61
62    sources = invoker.sources
63
64    # Compute the output directory, both relative to the source root (for
65    # declaring "outputs") and relative to the build dir (for passing to the
66    # script).
67    if (defined(invoker.proto_out_dir)) {
68      # Put the results in the specified dir in the gen tree.
69      out_dir = "$root_gen_dir/" + invoker.proto_out_dir
70      rel_out_dir = rebase_path(out_dir, root_build_dir)
71    } else {
72      # Use the gen directory corresponding to the source file. This expansion
73      # will be done differently in the outputs and the args, so we don't need
74      # to worry about rebasing as above.
75      out_dir = "{{source_gen_dir}}"
76      rel_out_dir = "{{source_gen_dir}}"
77    }
78
79    outputs = [
80      "$out_dir/{{source_name_part}}_pb2.py",
81      "$out_dir/{{source_name_part}}.pb.cc",
82      "$out_dir/{{source_name_part}}.pb.h",
83    ]
84
85    args = []
86    if (defined(invoker.cc_include)) {
87      args += [ "--include", invoker.cc_include ]
88    }
89
90    args += [
91      "--protobuf", "$rel_out_dir/{{source_name_part}}.pb.h",
92      "--proto-in-dir", "{{source_dir}}",
93      "--proto-in-file", "{{source_file_part}}",
94      # TODO(brettw) support system protobuf compiler.
95      "--use-system-protobuf=0",
96    ]
97
98    protoc_label = "//third_party/protobuf:protoc($host_toolchain)"
99    args += [
100      "--", 
101      # Prepend with "./" so this will never pick up the system one (normally
102      # when not cross-compiling, protoc's output directory will be the same
103      # as the build dir, so the relative location will be empty).
104      "./" + rebase_path(get_label_info(protoc_label, "root_out_dir") +
105             "/protoc", root_build_dir),
106    ]
107
108    # If passed cc_generator_options should end in a colon, which will separate
109    # it from the directory when we concatenate them. The proto compiler
110    # understands this syntax.
111    if (defined(invoker.cc_generator_options)) {
112      cc_generator_options = invoker.cc_generator_options
113    } else {
114      cc_generator_options = ""
115    }
116    args += [
117      # cc_generator_options is supposed to end in a colon if it's nonempty.
118      "--cpp_out", "$cc_generator_options$rel_out_dir",
119      "--python_out", rel_out_dir,
120    ]
121
122    deps = [ protoc_label ]
123
124    if (defined(invoker.deps)) {
125      deps += invoker.deps
126    }
127  }
128
129  source_set(target_name) {
130    if (defined(invoker.visibility)) {
131      visibility = invoker.visibility
132    }
133
134    sources = get_target_outputs(":$action_name")
135
136    if (defined(invoker.defines)) {
137      defines = invoker.defines
138    }
139    if (defined(invoker.extra_configs)) {
140      configs += invoker.extra_configs
141    }
142
143    public_configs = [ "//third_party/protobuf:using_proto" ]
144
145    public_deps = [
146      # The generated headers reference headers within protobuf_lite, so
147      # dependencies must be able to find those headers too.
148      "//third_party/protobuf:protobuf_lite",
149    ]
150    deps = [
151      ":$action_name",
152    ]
153  }
154}
155